diff options
Diffstat (limited to 'test/ruby')
101 files changed, 3305 insertions, 9870 deletions
diff --git a/test/ruby/enc/test_case_comprehensive.rb b/test/ruby/enc/test_case_comprehensive.rb index de18ac865c..bde47017a2 100644 --- a/test/ruby/enc/test_case_comprehensive.rb +++ b/test/ruby/enc/test_case_comprehensive.rb @@ -24,7 +24,7 @@ class TestComprehensiveCaseMapping < Test::Unit::TestCase def test_data_files_available unless TestComprehensiveCaseMapping.data_files_available? - omit "Unicode data files not available in #{UNICODE_DATA_PATH}." + skip "Unicode data files not available in #{UNICODE_DATA_PATH}." end end end @@ -37,7 +37,7 @@ TestComprehensiveCaseMapping.data_files_available? and class TestComprehensiveC end def self.read_data_file(filename) - File.foreach(expand_filename(filename), encoding: Encoding::ASCII_8BIT) do |line| + IO.foreach(expand_filename(filename), encoding: Encoding::ASCII_8BIT) do |line| if $. == 1 if filename == 'UnicodeData' elsif line.start_with?("# #{filename}-#{UNICODE_VERSION}.txt") diff --git a/test/ruby/enc/test_emoji_breaks.rb b/test/ruby/enc/test_emoji_breaks.rb index bb5114680e..cdde4da9bf 100644 --- a/test/ruby/enc/test_emoji_breaks.rb +++ b/test/ruby/enc/test_emoji_breaks.rb @@ -4,47 +4,50 @@ require "test/unit" class TestEmojiBreaks < Test::Unit::TestCase - class BreakTest - attr_reader :string, :comment, :filename, :line_number, :type, :shortname - - def initialize(filename, line_number, data, comment='') - @filename = filename - @line_number = line_number - @comment = comment.gsub(/\s+/, ' ').strip - if filename=='emoji-test' or filename=='emoji-variation-sequences' - codes, @type = data.split(/\s*;\s*/) - @shortname = '' - else - codes, @type, @shortname = data.split(/\s*;\s*/) - end - @type = @type.gsub(/\s+/, ' ').strip - @shortname = @shortname.gsub(/\s+/, ' ').strip - @string = codes.split(/\s+/) - .map do |ch| - c = ch.to_i(16) - # eliminate cases with surrogates - # raise ArgumentError if 0xD800 <= c and c <= 0xDFFF - c.chr('UTF-8') - end.join +end + +class TestEmojiBreaks::BreakTest + attr_reader :string, :comment, :filename, :line_number, :type, :shortname + + def initialize(filename, line_number, data, comment='') + @filename = filename + @line_number = line_number + @comment = comment.gsub(/\s+/, ' ').strip + if filename=='emoji-test' or filename=='emoji-variation-sequences' + codes, @type = data.split(/\s*;\s*/) + @shortname = '' + else + codes, @type, @shortname = data.split(/\s*;\s*/) end + @type = @type.gsub(/\s+/, ' ').strip + @shortname = @shortname.gsub(/\s+/, ' ').strip + @string = codes.split(/\s+/) + .map do |ch| + c = ch.to_i(16) + # eliminate cases with surrogates + # raise ArgumentError if 0xD800 <= c and c <= 0xDFFF + c.chr('UTF-8') + end.join end +end - class BreakFile - attr_reader :basename, :fullname, :version - FILES = [] +class TestEmojiBreaks::BreakFile + attr_reader :basename, :fullname, :version + FILES = [] - def initialize(basename, path, version) - @basename = basename - @fullname = "#{path}/#{basename}.txt" # File.expand_path(path + version, __dir__) - @version = version - FILES << self - end + def initialize(basename, path, version) + @basename = basename + @fullname = "#{path}/#{basename}.txt" # File.expand_path(path + version, __dir__) + @version = version + FILES << self + end - def self.files - FILES - end + def self.files + FILES end +end +class TestEmojiBreaks < Test::Unit::TestCase UNICODE_VERSION = RbConfig::CONFIG['UNICODE_VERSION'] UNICODE_DATA_PATH = File.expand_path("../../../enc/unicode/data/#{UNICODE_VERSION}/ucd/emoji", __dir__) EMOJI_VERSION = RbConfig::CONFIG['UNICODE_EMOJI_VERSION'] @@ -53,7 +56,7 @@ class TestEmojiBreaks < Test::Unit::TestCase EMOJI_DATA_FILES = %w[emoji-sequences emoji-test emoji-zwj-sequences].map do |basename| BreakFile.new(basename, EMOJI_DATA_PATH, EMOJI_VERSION) end - UNICODE_DATA_FILE = BreakFile.new('emoji-variation-sequences', UNICODE_DATA_PATH, UNICODE_VERSION) + UNICODE_DATA_FILE = BreakFile.new('emoji-variation-sequences', UNICODE_DATA_PATH, UNICODE_VERSION[0..-3]) # [0..-3] deals with a versioning mismatch problem in Unicode EMOJI_DATA_FILES << UNICODE_DATA_FILE def self.data_files_available? @@ -65,90 +68,83 @@ class TestEmojiBreaks < Test::Unit::TestCase def test_data_files_available assert_equal 4, EMOJI_DATA_FILES.size # debugging test unless TestEmojiBreaks.data_files_available? - omit "Emoji data files not available in #{EMOJI_DATA_PATH}." + skip "Emoji data files not available in #{EMOJI_DATA_PATH}." end end +end - if data_files_available? - def read_data - tests = [] - EMOJI_DATA_FILES.each do |file| - version_mismatch = true - file_tests = [] - File.foreach(file.fullname, encoding: Encoding::UTF_8) do |line| - line.chomp! - if $.==1 - if line=="# #{file.basename}-#{file.version}.txt" - version_mismatch = false - elsif line!="# #{file.basename}.txt" - raise "File Name Mismatch: line: #{line}, expected filename: #{file.basename}.txt" - end - end - version_mismatch = false if line =~ /^# Version: #{file.version}/ # 13.0 and older - version_mismatch = false if line =~ /^# Used with Emoji Version #{EMOJI_VERSION}/ # 14.0 and newer - next if line.match?(/\A(#|\z)/) - if line =~ /^(\h{4,6})\.\.(\h{4,6}) *(;.+)/ # deal with Unicode ranges in emoji-sequences.txt (Bug #18028) - range_start = $1.to_i(16) - range_end = $2.to_i(16) - rest = $3 - (range_start..range_end).each do |code_point| - file_tests << BreakTest.new(file.basename, $., *(code_point.to_s(16)+rest).split('#', 2)) - end - else - file_tests << BreakTest.new(file.basename, $., *line.split('#', 2)) +TestEmojiBreaks.data_files_available? and class TestEmojiBreaks + def read_data + tests = [] + EMOJI_DATA_FILES.each do |file| + version_mismatch = true + file_tests = [] + IO.foreach(file.fullname, encoding: Encoding::UTF_8) do |line| + line.chomp! + raise "File Name Mismatch: line: #{line}, expected filename: #{file.basename}.txt" if $.==1 and not line=="# #{file.basename}.txt" + version_mismatch = false if line =~ /^# Version: #{file.version}/ + next if line.match?(/\A(#|\z)/) + if line =~ /^(\h{4,6})\.\.(\h{4,6}) *(;.+)/ # deal with Unicode ranges in emoji-sequences.txt (Bug #18028) + range_start = $1.to_i(16) + range_end = $2.to_i(16) + rest = $3 + (range_start..range_end).each do |code_point| + file_tests << BreakTest.new(file.basename, $., *(code_point.to_s(16)+rest).split('#', 2)) end + else + file_tests << BreakTest.new(file.basename, $., *line.split('#', 2)) end - raise "File Version Mismatch: file: #{file.fullname}, version: #{file.version}" if version_mismatch - tests += file_tests end - tests + raise "File Version Mismatch: file: #{file.fullname}, version: #{file.version}" if version_mismatch + tests += file_tests end + tests + end - def all_tests - @@tests ||= read_data - rescue Errno::ENOENT - @@tests ||= [] - end + def all_tests + @@tests ||= read_data + rescue Errno::ENOENT + @@tests ||= [] + end - def test_single_emoji - all_tests.each do |test| - expected = [test.string] - actual = test.string.each_grapheme_cluster.to_a - assert_equal expected, actual, - "file: #{test.filename}, line #{test.line_number}, " + - "type: #{test.type}, shortname: #{test.shortname}, comment: #{test.comment}" - end + def test_single_emoji + all_tests.each do |test| + expected = [test.string] + actual = test.string.each_grapheme_cluster.to_a + assert_equal expected, actual, + "file: #{test.filename}, line #{test.line_number}, " + + "type: #{test.type}, shortname: #{test.shortname}, comment: #{test.comment}" end + end - def test_embedded_emoji - all_tests.each do |test| - expected = ["\t", test.string, "\t"] - actual = "\t#{test.string}\t".each_grapheme_cluster.to_a - assert_equal expected, actual, - "file: #{test.filename}, line #{test.line_number}, " + - "type: #{test.type}, shortname: #{test.shortname}, comment: #{test.comment}" - end + def test_embedded_emoji + all_tests.each do |test| + expected = ["\t", test.string, "\t"] + actual = "\t#{test.string}\t".each_grapheme_cluster.to_a + assert_equal expected, actual, + "file: #{test.filename}, line #{test.line_number}, " + + "type: #{test.type}, shortname: #{test.shortname}, comment: #{test.comment}" end + end - # test some pseodorandom combinations of emoji - def test_mixed_emoji - srand 0 - length = all_tests.length - step = 503 # use a prime number - all_tests.each do |test1| - start = rand step - start.step(by: step, to: length-1) do |t2| - test2 = all_tests[t2] - # exclude skin tones, because they glue to previous grapheme clusters - next if (0x1F3FB..0x1F3FF).include? test2.string.ord - expected = [test1.string, test2.string] - actual = (test1.string+test2.string).each_grapheme_cluster.to_a - assert_equal expected, actual, - "file1: #{test1.filename}, line1 #{test1.line_number}, " + - "file2: #{test2.filename}, line2 #{test2.line_number},\n" + - "type1: #{test1.type}, shortname1: #{test1.shortname}, comment1: #{test1.comment},\n" + - "type2: #{test2.type}, shortname2: #{test2.shortname}, comment2: #{test2.comment}" - end + # test some pseodorandom combinations of emoji + def test_mixed_emoji + srand 0 + length = all_tests.length + step = 503 # use a prime number + all_tests.each do |test1| + start = rand step + start.step(by: step, to: length-1) do |t2| + test2 = all_tests[t2] + # exclude skin tones, because they glue to previous grapheme clusters + next if (0x1F3FB..0x1F3FF).include? test2.string.ord + expected = [test1.string, test2.string] + actual = (test1.string+test2.string).each_grapheme_cluster.to_a + assert_equal expected, actual, + "file1: #{test1.filename}, line1 #{test1.line_number}, " + + "file2: #{test2.filename}, line2 #{test2.line_number},\n" + + "type1: #{test1.type}, shortname1: #{test1.shortname}, comment1: #{test1.comment},\n" + + "type2: #{test2.type}, shortname2: #{test2.shortname}, comment2: #{test2.comment}" end end end diff --git a/test/ruby/enc/test_grapheme_breaks.rb b/test/ruby/enc/test_grapheme_breaks.rb index 7e6d722d40..e8f3aa04a7 100644 --- a/test/ruby/enc/test_grapheme_breaks.rb +++ b/test/ruby/enc/test_grapheme_breaks.rb @@ -37,14 +37,14 @@ class TestGraphemeBreaksFromFile < Test::Unit::TestCase def test_data_files_available unless TestGraphemeBreaksFromFile.file_available? - omit "Unicode data file GraphemeBreakTest not available in #{UNICODE_DATA_PATH}." + skip "Unicode data file GraphemeBreakTest not available in #{UNICODE_DATA_PATH}." end end if file_available? def read_data tests = [] - File.foreach(GRAPHEME_BREAK_TEST_FILE, encoding: Encoding::UTF_8) do |line| + IO.foreach(GRAPHEME_BREAK_TEST_FILE, encoding: Encoding::UTF_8) do |line| if $. == 1 and not line.start_with?("# GraphemeBreakTest-#{UNICODE_VERSION}.txt") raise "File Version Mismatch" end diff --git a/test/ruby/enc/test_regex_casefold.rb b/test/ruby/enc/test_regex_casefold.rb index b5d5c6e337..ec5dc7f220 100644 --- a/test/ruby/enc/test_regex_casefold.rb +++ b/test/ruby/enc/test_regex_casefold.rb @@ -19,7 +19,7 @@ class TestCaseFold < Test::Unit::TestCase end def read_tests - File.readlines("#{UNICODE_DATA_PATH}/CaseFolding.txt", encoding: Encoding::ASCII_8BIT) + IO.readlines("#{UNICODE_DATA_PATH}/CaseFolding.txt", encoding: Encoding::ASCII_8BIT) .collect.with_index { |linedata, linenumber| [linenumber.to_i+1, linedata.chomp] } .reject { |number, data| data =~ /^(#|$)/ } .collect do |linenumber, linedata| @@ -39,7 +39,7 @@ class TestCaseFold < Test::Unit::TestCase @@tests ||= read_tests rescue Errno::ENOENT => e @@tests ||= [] - omit e.message + skip e.message end def self.generate_test_casefold(encoding) diff --git a/test/ruby/rjit/test_assembler.rb b/test/ruby/rjit/test_assembler.rb deleted file mode 100644 index a9ed6ce39e..0000000000 --- a/test/ruby/rjit/test_assembler.rb +++ /dev/null @@ -1,366 +0,0 @@ -require 'test/unit' -require_relative '../../lib/jit_support' - -return unless JITSupport.rjit_supported? -return unless RubyVM::RJIT.enabled? -return unless RubyVM::RJIT::C.HAVE_LIBCAPSTONE - -require 'stringio' -require 'ruby_vm/rjit/assembler' - -module RubyVM::RJIT - class TestAssembler < Test::Unit::TestCase - MEM_SIZE = 16 * 1024 - - def setup - @mem_block ||= C.mmap(MEM_SIZE) - @cb = CodeBlock.new(mem_block: @mem_block, mem_size: MEM_SIZE) - end - - def test_add - asm = Assembler.new - asm.add([:rcx], 1) # ADD r/m64, imm8 (Mod 00: [reg]) - asm.add(:rax, 0x7f) # ADD r/m64, imm8 (Mod 11: reg) - asm.add(:rbx, 0x7fffffff) # ADD r/m64 imm32 (Mod 11: reg) - asm.add(:rsi, :rdi) # ADD r/m64, r64 (Mod 11: reg) - assert_compile(asm, <<~EOS) - 0x0: add qword ptr [rcx], 1 - 0x4: add rax, 0x7f - 0x8: add rbx, 0x7fffffff - 0xf: add rsi, rdi - EOS - end - - def test_and - asm = Assembler.new - asm.and(:rax, 0) # AND r/m64, imm8 (Mod 11: reg) - asm.and(:rbx, 0x7fffffff) # AND r/m64, imm32 (Mod 11: reg) - asm.and(:rcx, [:rdi, 8]) # AND r64, r/m64 (Mod 01: [reg]+disp8) - assert_compile(asm, <<~EOS) - 0x0: and rax, 0 - 0x4: and rbx, 0x7fffffff - 0xb: and rcx, qword ptr [rdi + 8] - EOS - end - - def test_call - asm = Assembler.new - asm.call(rel32(0xff)) # CALL rel32 - asm.call(:rax) # CALL r/m64 (Mod 11: reg) - assert_compile(asm, <<~EOS) - 0x0: call 0xff - 0x5: call rax - EOS - end - - def test_cmove - asm = Assembler.new - asm.cmove(:rax, :rcx) # CMOVE r64, r/m64 (Mod 11: reg) - assert_compile(asm, <<~EOS) - 0x0: cmove rax, rcx - EOS - end - - def test_cmovg - asm = Assembler.new - asm.cmovg(:rbx, :rdi) # CMOVG r64, r/m64 (Mod 11: reg) - assert_compile(asm, <<~EOS) - 0x0: cmovg rbx, rdi - EOS - end - - def test_cmovge - asm = Assembler.new - asm.cmovge(:rsp, :rbp) # CMOVGE r64, r/m64 (Mod 11: reg) - assert_compile(asm, <<~EOS) - 0x0: cmovge rsp, rbp - EOS - end - - def test_cmovl - asm = Assembler.new - asm.cmovl(:rdx, :rsp) # CMOVL r64, r/m64 (Mod 11: reg) - assert_compile(asm, <<~EOS) - 0x0: cmovl rdx, rsp - EOS - end - - def test_cmovle - asm = Assembler.new - asm.cmovle(:rax, :rax) # CMOVLE r64, r/m64 (Mod 11: reg) - assert_compile(asm, <<~EOS) - 0x0: cmovle rax, rax - EOS - end - - def test_cmovne - asm = Assembler.new - asm.cmovne(:rax, :rbx) # CMOVNE r64, r/m64 (Mod 11: reg) - assert_compile(asm, <<~EOS) # cmovne == cmovnz - 0x0: cmovne rax, rbx - EOS - end - - def test_cmovnz - asm = Assembler.new - asm.cmovnz(:rax, :rbx) # CMOVNZ r64, r/m64 (Mod 11: reg) - assert_compile(asm, <<~EOS) # cmovne == cmovnz - 0x0: cmovne rax, rbx - EOS - end - - def test_cmovz - asm = Assembler.new - asm.cmovz(:rax, :rbx) # CMOVZ r64, r/m64 (Mod 11: reg) - assert_compile(asm, <<~EOS) # cmove == cmovz - 0x0: cmove rax, rbx - EOS - end - - def test_cmp - asm = Assembler.new - asm.cmp(BytePtr[:rax, 8], 8) # CMP r/m8, imm8 (Mod 01: [reg]+disp8) - asm.cmp(DwordPtr[:rax, 8], 0x100) # CMP r/m32, imm32 (Mod 01: [reg]+disp8) - asm.cmp([:rax, 8], 8) # CMP r/m64, imm8 (Mod 01: [reg]+disp8) - asm.cmp([:rax, 0x100], 8) # CMP r/m64, imm8 (Mod 10: [reg]+disp32) - asm.cmp(:rax, 8) # CMP r/m64, imm8 (Mod 11: reg) - asm.cmp(:rax, 0x100) # CMP r/m64, imm32 (Mod 11: reg) - asm.cmp([:rax, 8], :rbx) # CMP r/m64, r64 (Mod 01: [reg]+disp8) - asm.cmp([:rax, -0x100], :rbx) # CMP r/m64, r64 (Mod 10: [reg]+disp32) - asm.cmp(:rax, :rbx) # CMP r/m64, r64 (Mod 11: reg) - assert_compile(asm, <<~EOS) - 0x0: cmp byte ptr [rax + 8], 8 - 0x4: cmp dword ptr [rax + 8], 0x100 - 0xb: cmp qword ptr [rax + 8], 8 - 0x10: cmp qword ptr [rax + 0x100], 8 - 0x18: cmp rax, 8 - 0x1c: cmp rax, 0x100 - 0x23: cmp qword ptr [rax + 8], rbx - 0x27: cmp qword ptr [rax - 0x100], rbx - 0x2e: cmp rax, rbx - EOS - end - - def test_jbe - asm = Assembler.new - asm.jbe(rel32(0xff)) # JBE rel32 - assert_compile(asm, <<~EOS) - 0x0: jbe 0xff - EOS - end - - def test_je - asm = Assembler.new - asm.je(rel32(0xff)) # JE rel32 - assert_compile(asm, <<~EOS) - 0x0: je 0xff - EOS - end - - def test_jl - asm = Assembler.new - asm.jl(rel32(0xff)) # JL rel32 - assert_compile(asm, <<~EOS) - 0x0: jl 0xff - EOS - end - - def test_jmp - asm = Assembler.new - label = asm.new_label('label') - asm.jmp(label) # JZ rel8 - asm.write_label(label) - asm.jmp(rel32(0xff)) # JMP rel32 - asm.jmp([:rax, 8]) # JMP r/m64 (Mod 01: [reg]+disp8) - asm.jmp(:rax) # JMP r/m64 (Mod 11: reg) - assert_compile(asm, <<~EOS) - 0x0: jmp 2 - 0x2: jmp 0xff - 0x7: jmp qword ptr [rax + 8] - 0xa: jmp rax - EOS - end - - def test_jne - asm = Assembler.new - asm.jne(rel32(0xff)) # JNE rel32 - assert_compile(asm, <<~EOS) - 0x0: jne 0xff - EOS - end - - def test_jnz - asm = Assembler.new - asm.jnz(rel32(0xff)) # JNZ rel32 - assert_compile(asm, <<~EOS) - 0x0: jne 0xff - EOS - end - - def test_jo - asm = Assembler.new - asm.jo(rel32(0xff)) # JO rel32 - assert_compile(asm, <<~EOS) - 0x0: jo 0xff - EOS - end - - def test_jz - asm = Assembler.new - asm.jz(rel32(0xff)) # JZ rel32 - assert_compile(asm, <<~EOS) - 0x0: je 0xff - EOS - end - - def test_lea - asm = Assembler.new - asm.lea(:rax, [:rax, 8]) # LEA r64,m (Mod 01: [reg]+disp8) - asm.lea(:rax, [:rax, 0xffff]) # LEA r64,m (Mod 10: [reg]+disp32) - assert_compile(asm, <<~EOS) - 0x0: lea rax, [rax + 8] - 0x4: lea rax, [rax + 0xffff] - EOS - end - - def test_mov - asm = Assembler.new - asm.mov(:eax, DwordPtr[:rbx, 8]) # MOV r32 r/m32 (Mod 01: [reg]+disp8) - asm.mov(:eax, 0x100) # MOV r32, imm32 (Mod 11: reg) - asm.mov(:rax, [:rbx]) # MOV r64, r/m64 (Mod 00: [reg]) - asm.mov(:rax, [:rbx, 8]) # MOV r64, r/m64 (Mod 01: [reg]+disp8) - asm.mov(:rax, [:rbx, 0x100]) # MOV r64, r/m64 (Mod 10: [reg]+disp32) - asm.mov(:rax, :rbx) # MOV r64, r/m64 (Mod 11: reg) - asm.mov(:rax, 0x100) # MOV r/m64, imm32 (Mod 11: reg) - asm.mov(:rax, 0x100000000) # MOV r64, imm64 - asm.mov(DwordPtr[:rax, 8], 0x100) # MOV r/m32, imm32 (Mod 01: [reg]+disp8) - asm.mov([:rax], 0x100) # MOV r/m64, imm32 (Mod 00: [reg]) - asm.mov([:rax], :rbx) # MOV r/m64, r64 (Mod 00: [reg]) - asm.mov([:rax, 8], 0x100) # MOV r/m64, imm32 (Mod 01: [reg]+disp8) - asm.mov([:rax, 8], :rbx) # MOV r/m64, r64 (Mod 01: [reg]+disp8) - asm.mov([:rax, 0x100], 0x100) # MOV r/m64, imm32 (Mod 10: [reg]+disp32) - asm.mov([:rax, 0x100], :rbx) # MOV r/m64, r64 (Mod 10: [reg]+disp32) - assert_compile(asm, <<~EOS) - 0x0: mov eax, dword ptr [rbx + 8] - 0x3: mov eax, 0x100 - 0x8: mov rax, qword ptr [rbx] - 0xb: mov rax, qword ptr [rbx + 8] - 0xf: mov rax, qword ptr [rbx + 0x100] - 0x16: mov rax, rbx - 0x19: mov rax, 0x100 - 0x20: movabs rax, 0x100000000 - 0x2a: mov dword ptr [rax + 8], 0x100 - 0x31: mov qword ptr [rax], 0x100 - 0x38: mov qword ptr [rax], rbx - 0x3b: mov qword ptr [rax + 8], 0x100 - 0x43: mov qword ptr [rax + 8], rbx - 0x47: mov qword ptr [rax + 0x100], 0x100 - 0x52: mov qword ptr [rax + 0x100], rbx - EOS - end - - def test_or - asm = Assembler.new - asm.or(:rax, 0) # OR r/m64, imm8 (Mod 11: reg) - asm.or(:rax, 0xffff) # OR r/m64, imm32 (Mod 11: reg) - asm.or(:rax, [:rbx, 8]) # OR r64, r/m64 (Mod 01: [reg]+disp8) - assert_compile(asm, <<~EOS) - 0x0: or rax, 0 - 0x4: or rax, 0xffff - 0xb: or rax, qword ptr [rbx + 8] - EOS - end - - def test_push - asm = Assembler.new - asm.push(:rax) # PUSH r64 - assert_compile(asm, <<~EOS) - 0x0: push rax - EOS - end - - def test_pop - asm = Assembler.new - asm.pop(:rax) # POP r64 - assert_compile(asm, <<~EOS) - 0x0: pop rax - EOS - end - - def test_ret - asm = Assembler.new - asm.ret # RET - assert_compile(asm, "0x0: ret \n") - end - - def test_sar - asm = Assembler.new - asm.sar(:rax, 0) # SAR r/m64, imm8 (Mod 11: reg) - assert_compile(asm, <<~EOS) - 0x0: sar rax, 0 - EOS - end - - def test_sub - asm = Assembler.new - asm.sub(:rax, 8) # SUB r/m64, imm8 (Mod 11: reg) - asm.sub(:rax, :rbx) # SUB r/m64, r64 (Mod 11: reg) - assert_compile(asm, <<~EOS) - 0x0: sub rax, 8 - 0x4: sub rax, rbx - EOS - end - - def test_test - asm = Assembler.new - asm.test(BytePtr[:rax, 8], 16) # TEST r/m8*, imm8 (Mod 01: [reg]+disp8) - asm.test([:rax, 8], 8) # TEST r/m64, imm32 (Mod 01: [reg]+disp8) - asm.test([:rax, 0xffff], 0xffff) # TEST r/m64, imm32 (Mod 10: [reg]+disp32) - asm.test(:rax, 0xffff) # TEST r/m64, imm32 (Mod 11: reg) - asm.test(:eax, :ebx) # TEST r/m32, r32 (Mod 11: reg) - asm.test(:rax, :rbx) # TEST r/m64, r64 (Mod 11: reg) - assert_compile(asm, <<~EOS) - 0x0: test byte ptr [rax + 8], 0x10 - 0x4: test qword ptr [rax + 8], 8 - 0xc: test qword ptr [rax + 0xffff], 0xffff - 0x17: test rax, 0xffff - 0x1e: test eax, ebx - 0x20: test rax, rbx - EOS - end - - def test_xor - asm = Assembler.new - asm.xor(:rax, :rbx) - assert_compile(asm, <<~EOS) - 0x0: xor rax, rbx - EOS - end - - private - - def rel32(offset) - @cb.write_addr + 0xff - end - - def assert_compile(asm, expected) - actual = compile(asm) - assert_equal expected, actual, "---\n#{actual}---" - end - - def compile(asm) - start_addr = @cb.write_addr - @cb.write(asm) - end_addr = @cb.write_addr - - io = StringIO.new - @cb.dump_disasm(start_addr, end_addr, io:, color: false, test: true) - io.seek(0) - disasm = io.read - - disasm.gsub!(/^ /, '') - disasm.sub!(/\n\z/, '') - disasm - end - end -end diff --git a/test/ruby/test_argf.rb b/test/ruby/test_argf.rb index 12f7d6485a..e3bd1cd075 100644 --- a/test/ruby/test_argf.rb +++ b/test/ruby/test_argf.rb @@ -143,17 +143,6 @@ class TestArgf < Test::Unit::TestCase }; end - def test_lineno_after_shebang - expected = %w"1 1 1 2 2 2 3 3 1 4 4 2" - assert_in_out_err(["--enable=gems", "-", @t1.path, @t2.path], "#{<<~"{#"}\n#{<<~'};'}", expected) - #!/usr/bin/env ruby - {# - ARGF.each do |line| - puts [$., ARGF.lineno, ARGF.file.lineno] - end - }; - end - def test_new_lineno_each f = ARGF.class.new(@t1.path, @t2.path, @t3.path) result = [] @@ -268,13 +257,13 @@ class TestArgf < Test::Unit::TestCase def test_inplace_nonascii ext = Encoding.default_external or - omit "no default external encoding" + skip "no default external encoding" t = nil ["\u{3042}", "\u{e9}"].any? do |n| t = make_tempfile(n.encode(ext)) rescue Encoding::UndefinedConversionError end - t or omit "no name to test" + t or skip "no name to test" assert_in_out_err(["-i.bak", "-", t.path], "#{<<~"{#"}\n#{<<~'};'}") {# diff --git a/test/ruby/test_arity.rb b/test/ruby/test_arity.rb index bd26d5f0f5..b98248f603 100644 --- a/test/ruby/test_arity.rb +++ b/test/ruby/test_arity.rb @@ -2,7 +2,7 @@ require 'test/unit' class TestArity < Test::Unit::TestCase - def assert_arity(expected, method_proc = nil, argc = 0) + def err_mess(method_proc = nil, argc = 0) args = (1..argc).to_a assert_raise_with_message(ArgumentError, /wrong number of arguments \(.*\b(\d+)\b.* (\d\S*?)\)/) do case method_proc @@ -14,7 +14,7 @@ class TestArity < Test::Unit::TestCase method_proc.call(*args) end end - assert_equal expected, [$1, $2] + [$1, $2] end def a @@ -36,22 +36,22 @@ class TestArity < Test::Unit::TestCase end def test_method_err_mess - assert_arity(%w[1 0], :a, 1) - assert_arity(%w[10 7..9], :b, 10) - assert_arity(%w[2 3+], :c, 2) - assert_arity(%w[2 1], :d, 2) - assert_arity(%w[0 1], :d, 0) - assert_arity(%w[2 1], :e, 2) - assert_arity(%w[0 1], :e, 0) - assert_arity(%w[1 2+], :f, 1) + assert_equal %w[1 0], err_mess(:a, 1) + assert_equal %w[10 7..9], err_mess(:b, 10) + assert_equal %w[2 3+], err_mess(:c, 2) + assert_equal %w[2 1], err_mess(:d, 2) + assert_equal %w[0 1], err_mess(:d, 0) + assert_equal %w[2 1], err_mess(:e, 2) + assert_equal %w[0 1], err_mess(:e, 0) + assert_equal %w[1 2+], err_mess(:f, 1) end def test_proc_err_mess - assert_arity(%w[0 1..2], ->(b, c=42){}, 0) - assert_arity(%w[1 2+], ->(a, b, c=42, *d){}, 1) - assert_arity(%w[3 4+], ->(a, b, *c, d, e){}, 3) - assert_arity(%w[3 1..2], ->(b, c=42){}, 3) - assert_arity(%w[1 0], ->(&block){}, 1) + assert_equal %w[0 1..2], err_mess(->(b, c=42){}, 0) + assert_equal %w[1 2+], err_mess(->(a, b, c=42, *d){}, 1) + assert_equal %w[3 4+], err_mess(->(a, b, *c, d, e){}, 3) + assert_equal %w[3 1..2], err_mess(->(b, c=42){}, 3) + assert_equal %w[1 0], err_mess(->(&block){}, 1) # Double checking: p = Proc.new{|b, c=42| :ok} assert_equal :ok, p.call(1, 2, 3) @@ -59,11 +59,12 @@ class TestArity < Test::Unit::TestCase end def test_message_change_issue_6085 - assert_arity(%w[3 1..2]) { SignalException.new(1, "", nil) } - assert_arity(%w[1 0]) { Hash.new(1){} } - assert_arity(%w[3 1..2]) { Module.send :define_method, 1, 2, 3 } - assert_arity(%w[1 2]) { "".sub!(//) } - assert_arity(%w[0 1..2]) { "".sub!{} } - assert_arity(%w[0 1+]) { exec } + assert_equal %w[3 1..2], err_mess{ SignalException.new(1, "", nil) } + assert_equal %w[1 0], err_mess{ Hash.new(1){} } + assert_equal %w[3 1..2], err_mess{ Module.send :define_method, 1, 2, 3 } + assert_equal %w[1 2], err_mess{ "".sub!(//) } + assert_equal %w[0 1..2], err_mess{ "".sub!{} } + assert_equal %w[0 1+], err_mess{ exec } + assert_equal %w[0 1+], err_mess{ Struct.new } end end diff --git a/test/ruby/test_array.rb b/test/ruby/test_array.rb index 6c0db0832b..0ed8ada95c 100644 --- a/test/ruby/test_array.rb +++ b/test/ruby/test_array.rb @@ -1445,14 +1445,6 @@ class TestArray < Test::Unit::TestCase assert_raise(FrozenError) { fa.replace(42) } end - def test_replace_wb_variable_width_alloc - small_embed = [] - 4.times { GC.start } # age small_embed - large_embed = [1, 2, 3, 4, 5, Array.new] # new young object - small_embed.replace(large_embed) # adds old to young reference - GC.verify_internal_consistency - end - def test_reverse a = @cls[*%w( dog cat bee ant )] assert_equal(@cls[*%w(ant bee cat dog)], a.reverse) @@ -1586,96 +1578,6 @@ class TestArray < Test::Unit::TestCase assert_equal_instance(a.values_at(*idx), a.slice((3..90)%2)) idx = 90.step(3, -2).to_a assert_equal_instance(a.values_at(*idx), a.slice((90 .. 3)% -2)) - - a = [0, 1, 2, 3, 4, 5] - assert_equal([2, 1, 0], a.slice((2..).step(-1))) - assert_equal([2, 0], a.slice((2..).step(-2))) - assert_equal([2], a.slice((2..).step(-3))) - assert_equal([2], a.slice((2..).step(-4))) - - assert_equal([3, 2, 1, 0], a.slice((-3..).step(-1))) - assert_equal([3, 1], a.slice((-3..).step(-2))) - assert_equal([3, 0], a.slice((-3..).step(-3))) - assert_equal([3], a.slice((-3..).step(-4))) - assert_equal([3], a.slice((-3..).step(-5))) - - assert_equal([5, 4, 3, 2, 1, 0], a.slice((..0).step(-1))) - assert_equal([5, 3, 1], a.slice((..0).step(-2))) - assert_equal([5, 2], a.slice((..0).step(-3))) - assert_equal([5, 1], a.slice((..0).step(-4))) - assert_equal([5, 0], a.slice((..0).step(-5))) - assert_equal([5], a.slice((..0).step(-6))) - assert_equal([5], a.slice((..0).step(-7))) - - assert_equal([5, 4, 3, 2, 1], a.slice((...0).step(-1))) - assert_equal([5, 3, 1], a.slice((...0).step(-2))) - assert_equal([5, 2], a.slice((...0).step(-3))) - assert_equal([5, 1], a.slice((...0).step(-4))) - assert_equal([5], a.slice((...0).step(-5))) - assert_equal([5], a.slice((...0).step(-6))) - - assert_equal([5, 4, 3, 2], a.slice((...1).step(-1))) - assert_equal([5, 3], a.slice((...1).step(-2))) - assert_equal([5, 2], a.slice((...1).step(-3))) - assert_equal([5], a.slice((...1).step(-4))) - assert_equal([5], a.slice((...1).step(-5))) - - assert_equal([5, 4, 3, 2, 1], a.slice((..-5).step(-1))) - assert_equal([5, 3, 1], a.slice((..-5).step(-2))) - assert_equal([5, 2], a.slice((..-5).step(-3))) - assert_equal([5, 1], a.slice((..-5).step(-4))) - assert_equal([5], a.slice((..-5).step(-5))) - assert_equal([5], a.slice((..-5).step(-6))) - - assert_equal([5, 4, 3, 2], a.slice((...-5).step(-1))) - assert_equal([5, 3], a.slice((...-5).step(-2))) - assert_equal([5, 2], a.slice((...-5).step(-3))) - assert_equal([5], a.slice((...-5).step(-4))) - assert_equal([5], a.slice((...-5).step(-5))) - - assert_equal([4, 3, 2, 1], a.slice((4..1).step(-1))) - assert_equal([4, 2], a.slice((4..1).step(-2))) - assert_equal([4, 1], a.slice((4..1).step(-3))) - assert_equal([4], a.slice((4..1).step(-4))) - assert_equal([4], a.slice((4..1).step(-5))) - - assert_equal([4, 3, 2], a.slice((4...1).step(-1))) - assert_equal([4, 2], a.slice((4...1).step(-2))) - assert_equal([4], a.slice((4...1).step(-3))) - assert_equal([4], a.slice((4...1).step(-4))) - - assert_equal([4, 3, 2, 1], a.slice((-2..1).step(-1))) - assert_equal([4, 2], a.slice((-2..1).step(-2))) - assert_equal([4, 1], a.slice((-2..1).step(-3))) - assert_equal([4], a.slice((-2..1).step(-4))) - assert_equal([4], a.slice((-2..1).step(-5))) - - assert_equal([4, 3, 2], a.slice((-2...1).step(-1))) - assert_equal([4, 2], a.slice((-2...1).step(-2))) - assert_equal([4], a.slice((-2...1).step(-3))) - assert_equal([4], a.slice((-2...1).step(-4))) - - assert_equal([4, 3, 2, 1], a.slice((4..-5).step(-1))) - assert_equal([4, 2], a.slice((4..-5).step(-2))) - assert_equal([4, 1], a.slice((4..-5).step(-3))) - assert_equal([4], a.slice((4..-5).step(-4))) - assert_equal([4], a.slice((4..-5).step(-5))) - - assert_equal([4, 3, 2], a.slice((4...-5).step(-1))) - assert_equal([4, 2], a.slice((4...-5).step(-2))) - assert_equal([4], a.slice((4...-5).step(-3))) - assert_equal([4], a.slice((4...-5).step(-4))) - - assert_equal([4, 3, 2, 1], a.slice((-2..-5).step(-1))) - assert_equal([4, 2], a.slice((-2..-5).step(-2))) - assert_equal([4, 1], a.slice((-2..-5).step(-3))) - assert_equal([4], a.slice((-2..-5).step(-4))) - assert_equal([4], a.slice((-2..-5).step(-5))) - - assert_equal([4, 3, 2], a.slice((-2...-5).step(-1))) - assert_equal([4, 2], a.slice((-2...-5).step(-2))) - assert_equal([4], a.slice((-2...-5).step(-3))) - assert_equal([4], a.slice((-2...-5).step(-4))) end def test_slice_out_of_range @@ -2986,9 +2888,7 @@ class TestArray < Test::Unit::TestCase assert_raise(RangeError) { [*0..2].shuffle(random: gen) } - end - def test_shuffle_random_clobbering ary = (0...10000).to_a gen = proc do ary.replace([]) @@ -2998,9 +2898,7 @@ class TestArray < Test::Unit::TestCase alias rand call end assert_raise(RuntimeError) {ary.shuffle!(random: gen)} - end - def test_shuffle_random_zero zero = Object.new def zero.to_int 0 @@ -3013,10 +2911,7 @@ class TestArray < Test::Unit::TestCase end ary = (0...10000).to_a assert_equal(ary.rotate, ary.shuffle(random: gen_to_int)) - end - def test_shuffle_random_invalid_generator - ary = (0...10).to_a assert_raise(NoMethodError) { ary.shuffle(random: Object.new) } @@ -3033,9 +2928,7 @@ class TestArray < Test::Unit::TestCase assert_include([0, 1, 2], sample) } end - end - def test_sample_statistics srand(0) a = (1..18).to_a (0..20).each do |n| @@ -3052,13 +2945,9 @@ class TestArray < Test::Unit::TestCase end assert_operator(h.values.min * 2, :>=, h.values.max) if n != 0 end - end - def test_sample_invalid_argument assert_raise(ArgumentError, '[ruby-core:23374]') {[1, 2].sample(-1)} - end - def test_sample_random_srand0 gen = Random.new(0) srand(0) a = (1..18).to_a @@ -3067,15 +2956,13 @@ class TestArray < Test::Unit::TestCase assert_equal(a.sample(n), a.sample(n, random: gen), "#{i}/#{n}") end end - end - def test_sample_unknown_keyword assert_raise_with_message(ArgumentError, /unknown keyword/) do [0, 1, 2].sample(xawqij: "a") end end - def test_sample_random_generator + def test_sample_random ary = (0...10000).to_a assert_raise(ArgumentError) {ary.sample(1, 2, random: nil)} gen0 = proc do |max| @@ -3118,9 +3005,7 @@ class TestArray < Test::Unit::TestCase assert_equal([5000, 0, 5001, 2, 5002, 4, 5003, 6, 5004, 8, 5005], ary.sample(11, random: gen0)) ary.sample(11, random: gen1) # implementation detail, may change in the future assert_equal([], ary) - end - def test_sample_random_generator_half half = Object.new def half.to_int 5000 @@ -3133,10 +3018,7 @@ class TestArray < Test::Unit::TestCase end ary = (0...10000).to_a assert_equal(5000, ary.sample(random: gen_to_int)) - end - def test_sample_random_invalid_generator - ary = (0..10).to_a assert_raise(NoMethodError) { ary.sample(random: Object.new) } @@ -3398,7 +3280,7 @@ class TestArray < Test::Unit::TestCase end EOS rescue Timeout::Error => e - omit e.message + skip e.message end end diff --git a/test/ruby/test_assignment.rb b/test/ruby/test_assignment.rb index 3a8dafb7f0..41e8bffe82 100644 --- a/test/ruby/test_assignment.rb +++ b/test/ruby/test_assignment.rb @@ -139,104 +139,6 @@ class TestAssignment < Test::Unit::TestCase order.clear end - def test_massign_const_order - order = [] - - test_mod_class = Class.new(Module) do - define_method(:x1){order << :x1; self} - define_method(:y1){order << :y1; self} - define_method(:x2){order << :x2; self} - define_method(:x3){order << :x3; self} - define_method(:x4){order << :x4; self} - define_method(:[]){|*args| order << [:[], *args]; self} - define_method(:r1){order << :r1; :r1} - define_method(:r2){order << :r2; :r2} - - define_method(:constant_values) do - h = {} - constants.each do |sym| - h[sym] = const_get(sym) - end - h - end - - define_singleton_method(:run) do |code| - m = new - m.instance_eval(code) - ret = [order.dup, m.constant_values] - order.clear - ret - end - end - - ord, constants = test_mod_class.run( - "x1.y1::A, x2[1, 2, 3]::B, self[4]::C = r1, 6, r2" - ) - assert_equal([:x1, :y1, :x2, [:[], 1, 2, 3], [:[], 4], :r1, :r2], ord) - assert_equal({:A=>:r1, :B=>6, :C=>:r2}, constants) - - ord, constants = test_mod_class.run( - "x1.y1::A, *x2[1, 2, 3]::B, self[4]::C = r1, 6, 7, r2" - ) - assert_equal([:x1, :y1, :x2, [:[], 1, 2, 3], [:[], 4], :r1, :r2], ord) - assert_equal({:A=>:r1, :B=>[6, 7], :C=>:r2}, constants) - - ord, constants = test_mod_class.run( - "x1.y1::A, *x2[1, 2, 3]::B, x3[4]::C = r1, 6, 7, r2" - ) - assert_equal([:x1, :y1, :x2, [:[], 1, 2, 3], :x3, [:[], 4], :r1, :r2], ord) - assert_equal({:A=>:r1, :B=>[6, 7], :C=>:r2}, constants) - - - ord, constants = test_mod_class.run( - "x1.y1::A, *x2[1, 2, 3]::B, x3[4]::C, x4::D = r1, 6, 7, r2, 8" - ) - assert_equal([:x1, :y1, :x2, [:[], 1, 2, 3], :x3, [:[], 4], :x4, :r1, :r2], ord) - assert_equal({:A=>:r1, :B=>[6, 7], :C=>:r2, :D=>8}, constants) - - ord, constants = test_mod_class.run( - "(x1.y1::A, x2::B), _a = [r1, r2], 7" - ) - assert_equal([:x1, :y1, :x2, :r1, :r2], ord) - assert_equal({:A=>:r1, :B=>:r2}, constants) - - ord, constants = test_mod_class.run( - "(x1.y1::A, x1::B), *x2[1, 2, 3]::C = [r1, 5], 6, 7, r2, 8" - ) - assert_equal([:x1, :y1, :x1, :x2, [:[], 1, 2, 3], :r1, :r2], ord) - assert_equal({:A=>:r1, :B=>5, :C=>[6, 7, :r2, 8]}, constants) - - ord, constants = test_mod_class.run( - "*x2[1, 2, 3]::A, (x3[4]::B, x4::C) = 6, 7, [r2, 8]" - ) - assert_equal([:x2, [:[], 1, 2, 3], :x3, [:[], 4], :x4, :r2], ord) - assert_equal({:A=>[6, 7], :B=>:r2, :C=>8}, constants) - - ord, constants = test_mod_class.run( - "(x1.y1::A, x1::B), *x2[1, 2, 3]::C, x3[4]::D, x4::E = [r1, 5], 6, 7, r2, 8" - ) - assert_equal([:x1, :y1, :x1, :x2, [:[], 1, 2, 3], :x3, [:[], 4], :x4, :r1, :r2], ord) - assert_equal({:A=>:r1, :B=>5, :C=>[6, 7], :D=>:r2, :E=>8}, constants) - - ord, constants = test_mod_class.run( - "(x1.y1::A, x1::B), *x2[1, 2, 3]::C, (x3[4]::D, x4::E) = [r1, 5], 6, 7, [r2, 8]" - ) - assert_equal([:x1, :y1, :x1, :x2, [:[], 1, 2, 3], :x3, [:[], 4], :x4, :r1, :r2], ord) - assert_equal({:A=>:r1, :B=>5, :C=>[6, 7], :D=>:r2, :E=>8}, constants) - - ord, constants = test_mod_class.run( - "((x1.y1::A, x1::B), _a), *x2[1, 2, 3]::C, ((x3[4]::D, x4::E), _b) = [[r1, 5], 10], 6, 7, [[r2, 8], 11]" - ) - assert_equal([:x1, :y1, :x1, :x2, [:[], 1, 2, 3], :x3, [:[], 4], :x4, :r1, :r2], ord) - assert_equal({:A=>:r1, :B=>5, :C=>[6, 7], :D=>:r2, :E=>8}, constants) - - ord, constants = test_mod_class.run( - "((x1.y1::A, x1::B), _a), *x2[1, 2, 3]::C, ((*x3[4]::D, x4::E), _b) = [[r1, 5], 10], 6, 7, [[r2, 8], 11]" - ) - assert_equal([:x1, :y1, :x1, :x2, [:[], 1, 2, 3], :x3, [:[], 4], :x4, :r1, :r2], ord) - assert_equal({:A=>:r1, :B=>5, :C=>[6, 7], :D=>[:r2], :E=>8}, constants) - end - def test_massign_splat a,b,*c = *[]; assert_equal([nil,nil,[]], [a,b,c]) a,b,*c = *[1]; assert_equal([1,nil,[]], [a,b,c]) @@ -717,16 +619,6 @@ class TestAssignment < Test::Unit::TestCase result = eval("if (a, b = MyObj.new); [a, b]; end", nil, __FILE__, __LINE__) assert_equal [[1,2],[3,4]], result end - - def test_const_assign_order - assert_raise(RuntimeError) do - eval('raise("recv")::C = raise(ArgumentError, "bar")') - end - - assert_raise(RuntimeError) do - eval('m = 1; m::C = raise("bar")') - end - end end require_relative 'sentence' diff --git a/test/ruby/test_ast.rb b/test/ruby/test_ast.rb index b4bcc03cfe..cd7299f200 100644 --- a/test/ruby/test_ast.rb +++ b/test/ruby/test_ast.rb @@ -1,7 +1,6 @@ # frozen_string_literal: false require 'test/unit' require 'tempfile' -require 'pp' class RubyVM module AbstractSyntaxTree @@ -132,34 +131,6 @@ class TestAst < Test::Unit::TestCase end end - Dir.glob("test/**/*.rb", base: SRCDIR).each do |path| - define_method("test_all_tokens:#{path}") do - node = RubyVM::AbstractSyntaxTree.parse_file("#{SRCDIR}/#{path}", keep_tokens: true) - tokens = node.all_tokens.sort_by { [_1.last[0], _1.last[1]] } - tokens_bytes = tokens.map { _1[2]}.join.bytes - source_bytes = File.read("#{SRCDIR}/#{path}").bytes - - assert_equal(source_bytes, tokens_bytes) - - (tokens.count - 1).times do |i| - token_0 = tokens[i] - token_1 = tokens[i + 1] - end_pos = token_0.last[2..3] - beg_pos = token_1.last[0..1] - - if end_pos[0] == beg_pos[0] - # When both tokens are same line, column should be consecutives - assert_equal(beg_pos[1], end_pos[1], "#{token_0}. #{token_1}") - else - # Line should be next - assert_equal(beg_pos[0], end_pos[0] + 1, "#{token_0}. #{token_1}") - # It should be on the beginning of the line - assert_equal(0, beg_pos[1], "#{token_0}. #{token_1}") - end - end - end - end - private def parse(src) EnvUtil.suppress_warning { RubyVM::AbstractSyntaxTree.parse(src) @@ -214,25 +185,6 @@ class TestAst < Test::Unit::TestCase end end - def test_node_id_for_location - exception = begin - raise - rescue => e - e - end - loc = exception.backtrace_locations.first - node_id = RubyVM::AbstractSyntaxTree.node_id_for_backtrace_location(loc) - node = RubyVM::AbstractSyntaxTree.of(loc, keep_script_lines: true) - - assert_equal node.node_id, node_id - end - - def test_node_id_for_backtrace_location_raises_argument_error - bug19262 = '[ruby-core:111435]' - - assert_raise(TypeError, bug19262) { RubyVM::AbstractSyntaxTree.node_id_for_backtrace_location(1) } - end - def test_of_proc_and_method proc = Proc.new { 1 + 2 } method = self.method(__method__) @@ -303,8 +255,6 @@ class TestAst < Test::Unit::TestCase end def test_of_proc_and_method_under_eval_with_keep_script_lines - pend if ENV['RUBY_ISEQ_DUMP_DEBUG'] # TODO - keep_script_lines_back = RubyVM.keep_script_lines RubyVM.keep_script_lines = true @@ -352,8 +302,6 @@ class TestAst < Test::Unit::TestCase end def test_of_backtrace_location_under_eval_with_keep_script_lines - pend if ENV['RUBY_ISEQ_DUMP_DEBUG'] # TODO - keep_script_lines_back = RubyVM.keep_script_lines RubyVM.keep_script_lines = true @@ -495,30 +443,6 @@ class TestAst < Test::Unit::TestCase assert_not_equal(type1, type2) end - def test_rest_arg - rest_arg = lambda do |arg_str| - node = RubyVM::AbstractSyntaxTree.parse("def a(#{arg_str}) end") - node = node.children.last.children.last.children[1].children[-4] - end - - assert_equal(nil, rest_arg.call('')) - assert_equal(:r, rest_arg.call('*r')) - assert_equal(:r, rest_arg.call('a, *r')) - assert_equal(:*, rest_arg.call('*')) - assert_equal(:*, rest_arg.call('a, *')) - end - - def test_block_arg - block_arg = lambda do |arg_str| - node = RubyVM::AbstractSyntaxTree.parse("def a(#{arg_str}) end") - node = node.children.last.children.last.children[1].children[-1] - end - - assert_equal(nil, block_arg.call('')) - assert_equal(:block, block_arg.call('&block')) - assert_equal(:&, block_arg.call('&')) - end - def test_keyword_rest kwrest = lambda do |arg_str| node = RubyVM::AbstractSyntaxTree.parse("def a(#{arg_str}) end") @@ -527,21 +451,11 @@ class TestAst < Test::Unit::TestCase end assert_equal(nil, kwrest.call('')) - assert_equal([:**], kwrest.call('**')) + assert_equal([nil], kwrest.call('**')) assert_equal(false, kwrest.call('**nil')) assert_equal([:a], kwrest.call('**a')) end - def test_argument_forwarding - forwarding = lambda do |arg_str| - node = RubyVM::AbstractSyntaxTree.parse("def a(#{arg_str}) end") - node = node.children.last.children.last.children[1] - node ? [node.children[-4], node.children[-2]&.children, node.children[-1]] : [] - end - - assert_equal([:*, nil, :&], forwarding.call('...')) - end - def test_ranges_numbered_parameter helper = Helper.new(__FILE__, src: "1.times {_1}") helper.validate_range @@ -624,37 +538,7 @@ dummy assert_equal("def test_keep_script_lines_for_of\n", node_method.source.lines.first) end - def test_keep_tokens_for_parse - node = RubyVM::AbstractSyntaxTree.parse(<<~END, keep_tokens: true) - 1.times do - end - __END__ - dummy - END - - expected = [ - [:tINTEGER, "1"], - [:".", "."], - [:tIDENTIFIER, "times"], - [:tSP, " "], - [:keyword_do, "do"], - [:tIGNORED_NL, "\n"], - [:keyword_end, "end"], - [:nl, "\n"], - ] - assert_equal(expected, node.all_tokens.map { [_2, _3]}) - end - - def test_keep_tokens_unexpected_backslash - assert_raise_with_message(SyntaxError, /unexpected backslash/) do - RubyVM::AbstractSyntaxTree.parse("\\", keep_tokens: true) - end - end - def test_encoding_with_keep_script_lines - # Stop a warning "possibly useless use of a literal in void context" - verbose_bak, $VERBOSE = $VERBOSE, nil - enc = Encoding::EUC_JP code = "__ENCODING__".encode(enc) @@ -665,440 +549,10 @@ dummy node = RubyVM::AbstractSyntaxTree.parse(code, keep_script_lines: true) assert_equal(enc, node.children[2].children[0]) - - ensure - $VERBOSE = verbose_bak end def test_e_option assert_in_out_err(["-e", "def foo; end; pp RubyVM::AbstractSyntaxTree.of(method(:foo)).type"], "", [":SCOPE"], []) end - - def test_error_tolerant - verbose_bak, $VERBOSE = $VERBOSE, false - node = RubyVM::AbstractSyntaxTree.parse(<<~STR, error_tolerant: true) - class A - def m - if; - a = 10 - end - end - STR - assert_nil($!) - - assert_equal(:SCOPE, node.type) - ensure - $VERBOSE = verbose_bak - end - - def test_error_tolerant_end_is_short_for_method_define - assert_error_tolerant(<<~STR, <<~EXP) - def m - m2 - STR - (SCOPE@1:0-2:4 - tbl: [] - args: nil - body: - (DEFN@1:0-2:4 - mid: :m - body: - (SCOPE@1:0-2:4 - tbl: [] - args: - (ARGS@1:5-1:5 - pre_num: 0 - pre_init: nil - opt: nil - first_post: nil - post_num: 0 - post_init: nil - rest: nil - kw: nil - kwrest: nil - block: nil) - body: (VCALL@2:2-2:4 :m2)))) - EXP - end - - def test_error_tolerant_end_is_short_for_singleton_method_define - assert_error_tolerant(<<~STR, <<~EXP) - def obj.m - m2 - STR - (SCOPE@1:0-2:4 - tbl: [] - args: nil - body: - (DEFS@1:0-2:4 (VCALL@1:4-1:7 :obj) :m - (SCOPE@1:0-2:4 - tbl: [] - args: - (ARGS@1:9-1:9 - pre_num: 0 - pre_init: nil - opt: nil - first_post: nil - post_num: 0 - post_init: nil - rest: nil - kw: nil - kwrest: nil - block: nil) - body: (VCALL@2:2-2:4 :m2)))) - EXP - end - - def test_error_tolerant_end_is_short_for_begin - assert_error_tolerant(<<~STR, <<~EXP) - begin - a = 1 - STR - (SCOPE@1:0-2:7 tbl: [:a] args: nil body: (LASGN@2:2-2:7 :a (LIT@2:6-2:7 1))) - EXP - end - - def test_error_tolerant_end_is_short_for_if - assert_error_tolerant(<<~STR, <<~EXP) - if cond - a = 1 - STR - (SCOPE@1:0-2:7 - tbl: [:a] - args: nil - body: - (IF@1:0-2:7 (VCALL@1:3-1:7 :cond) (LASGN@2:2-2:7 :a (LIT@2:6-2:7 1)) nil)) - EXP - - assert_error_tolerant(<<~STR, <<~EXP) - if cond - a = 1 - else - STR - (SCOPE@1:0-3:4 - tbl: [:a] - args: nil - body: - (IF@1:0-3:4 (VCALL@1:3-1:7 :cond) (LASGN@2:2-2:7 :a (LIT@2:6-2:7 1)) - (BEGIN@3:4-3:4 nil))) - EXP - end - - def test_error_tolerant_end_is_short_for_unless - assert_error_tolerant(<<~STR, <<~EXP) - unless cond - a = 1 - STR - (SCOPE@1:0-2:7 - tbl: [:a] - args: nil - body: - (UNLESS@1:0-2:7 (VCALL@1:7-1:11 :cond) (LASGN@2:2-2:7 :a (LIT@2:6-2:7 1)) - nil)) - EXP - - assert_error_tolerant(<<~STR, <<~EXP) - unless cond - a = 1 - else - STR - (SCOPE@1:0-3:4 - tbl: [:a] - args: nil - body: - (UNLESS@1:0-3:4 (VCALL@1:7-1:11 :cond) (LASGN@2:2-2:7 :a (LIT@2:6-2:7 1)) - (BEGIN@3:4-3:4 nil))) - EXP - end - - def test_error_tolerant_end_is_short_for_while - assert_error_tolerant(<<~STR, <<~EXP) - while true - m - STR - (SCOPE@1:0-2:3 - tbl: [] - args: nil - body: (WHILE@1:0-2:3 (TRUE@1:6-1:10) (VCALL@2:2-2:3 :m) true)) - EXP - end - - def test_error_tolerant_end_is_short_for_until - assert_error_tolerant(<<~STR, <<~EXP) - until true - m - STR - (SCOPE@1:0-2:3 - tbl: [] - args: nil - body: (UNTIL@1:0-2:3 (TRUE@1:6-1:10) (VCALL@2:2-2:3 :m) true)) - EXP - end - - def test_error_tolerant_end_is_short_for_case - assert_error_tolerant(<<~STR, <<~EXP) - case a - when 1 - STR - (SCOPE@1:0-2:6 - tbl: [] - args: nil - body: - (CASE@1:0-2:6 (VCALL@1:5-1:6 :a) - (WHEN@2:0-2:6 (LIST@2:5-2:6 (LIT@2:5-2:6 1) nil) (BEGIN@2:6-2:6 nil) - nil))) - EXP - - - assert_error_tolerant(<<~STR, <<~EXP) - case - when a == 1 - STR - (SCOPE@1:0-2:11 - tbl: [] - args: nil - body: - (CASE2@1:0-2:11 nil - (WHEN@2:0-2:11 - (LIST@2:5-2:11 - (OPCALL@2:5-2:11 (VCALL@2:5-2:6 :a) :== - (LIST@2:10-2:11 (LIT@2:10-2:11 1) nil)) nil) - (BEGIN@2:11-2:11 nil) nil))) - EXP - - - assert_error_tolerant(<<~STR, <<~EXP) - case a - in {a: String} - STR - (SCOPE@1:0-2:14 - tbl: [] - args: nil - body: - (CASE3@1:0-2:14 (VCALL@1:5-1:6 :a) - (IN@2:0-2:14 - (HSHPTN@2:4-2:13 - const: nil - kw: - (HASH@2:4-2:13 - (LIST@2:4-2:13 (LIT@2:4-2:6 :a) (CONST@2:7-2:13 :String) nil)) - kwrest: nil) (BEGIN@2:14-2:14 nil) nil))) - EXP - end - - def test_error_tolerant_end_is_short_for_for - assert_error_tolerant(<<~STR, <<~EXP) - for i in ary - m - STR - (SCOPE@1:0-2:3 - tbl: [:i] - args: nil - body: - (FOR@1:0-2:3 (VCALL@1:9-1:12 :ary) - (SCOPE@1:0-2:3 - tbl: [nil] - args: - (ARGS@1:4-1:5 - pre_num: 1 - pre_init: (LASGN@1:4-1:5 :i (DVAR@1:4-1:5 nil)) - opt: nil - first_post: nil - post_num: 0 - post_init: nil - rest: nil - kw: nil - kwrest: nil - block: nil) - body: (VCALL@2:2-2:3 :m)))) - EXP - end - - def test_error_tolerant_end_is_short_for_class - assert_error_tolerant(<<~STR, <<~EXP) - class C - STR - (SCOPE@1:0-1:7 - tbl: [] - args: nil - body: - (CLASS@1:0-1:7 (COLON2@1:6-1:7 nil :C) nil - (SCOPE@1:0-1:7 tbl: [] args: nil body: (BEGIN@1:7-1:7 nil)))) - EXP - end - - def test_error_tolerant_end_is_short_for_module - assert_error_tolerant(<<~STR, <<~EXP) - module M - STR - (SCOPE@1:0-1:8 - tbl: [] - args: nil - body: - (MODULE@1:0-1:8 (COLON2@1:7-1:8 nil :M) - (SCOPE@1:0-1:8 tbl: [] args: nil body: (BEGIN@1:8-1:8 nil)))) - EXP - end - - def test_error_tolerant_end_is_short_for_do - assert_error_tolerant(<<~STR, <<~EXP) - m do - a - STR - (SCOPE@1:0-2:3 - tbl: [] - args: nil - body: - (ITER@1:0-2:3 (FCALL@1:0-1:1 :m nil) - (SCOPE@1:2-2:3 tbl: [] args: nil body: (VCALL@2:2-2:3 :a)))) - EXP - end - - def test_error_tolerant_end_is_short_for_do_block - assert_error_tolerant(<<~STR, <<~EXP) - m 1 do - a - STR - (SCOPE@1:0-2:3 - tbl: [] - args: nil - body: - (ITER@1:0-2:3 (FCALL@1:0-1:3 :m (LIST@1:2-1:3 (LIT@1:2-1:3 1) nil)) - (SCOPE@1:4-2:3 tbl: [] args: nil body: (VCALL@2:2-2:3 :a)))) - EXP - end - - def test_error_tolerant_end_is_short_for_do_LAMBDA - assert_error_tolerant(<<~STR, <<~EXP) - -> do - a - STR - (SCOPE@1:0-2:3 - tbl: [] - args: nil - body: - (LAMBDA@1:0-2:3 - (SCOPE@1:2-2:3 - tbl: [] - args: - (ARGS@1:2-1:2 - pre_num: 0 - pre_init: nil - opt: nil - first_post: nil - post_num: 0 - post_init: nil - rest: nil - kw: nil - kwrest: nil - block: nil) - body: (VCALL@2:2-2:3 :a)))) - EXP - end - - def test_error_tolerant_treat_end_as_keyword_based_on_indent - assert_error_tolerant(<<~STR, <<~EXP) - module Z - class Foo - foo. - end - - def bar - end - end - STR - (SCOPE@1:0-8:3 - tbl: [] - args: nil - body: - (MODULE@1:0-8:3 (COLON2@1:7-1:8 nil :Z) - (SCOPE@1:0-8:3 - tbl: [] - args: nil - body: - (BLOCK@1:8-7:5 (BEGIN@1:8-1:8 nil) - (CLASS@2:2-4:5 (COLON2@2:8-2:11 nil :Foo) nil - (SCOPE@2:2-4:5 - tbl: [] - args: nil - body: (BLOCK@2:11-4:5 (BEGIN@2:11-2:11 nil) (ERROR@3:4-4:5)))) - (DEFN@6:2-7:5 - mid: :bar - body: - (SCOPE@6:2-7:5 - tbl: [] - args: - (ARGS@6:9-6:9 - pre_num: 0 - pre_init: nil - opt: nil - first_post: nil - post_num: 0 - post_init: nil - rest: nil - kw: nil - kwrest: nil - block: nil) - body: nil)))))) - EXP - end - - def test_error_tolerant_expr_value_can_be_error - assert_error_tolerant(<<~STR, <<~EXP) - def m - if - end - STR - (SCOPE@1:0-3:3 - tbl: [] - args: nil - body: - (DEFN@1:0-3:3 - mid: :m - body: - (SCOPE@1:0-3:3 - tbl: [] - args: - (ARGS@1:5-1:5 - pre_num: 0 - pre_init: nil - opt: nil - first_post: nil - post_num: 0 - post_init: nil - rest: nil - kw: nil - kwrest: nil - block: nil) - body: (IF@2:2-3:3 (ERROR@3:0-3:3) nil nil)))) - EXP - end - - def test_error_tolerant_unexpected_backslash - node = assert_error_tolerant("\\", <<~EXP, keep_tokens: true) - (SCOPE@1:0-1:1 tbl: [] args: nil body: (ERROR@1:0-1:1)) - EXP - assert_equal([[0, :backslash, "\\", [1, 0, 1, 1]]], node.children.last.tokens) - end - - def test_with_bom - assert_error_tolerant("\u{feff}nil", <<~EXP) - (SCOPE@1:0-1:3 tbl: [] args: nil body: (NIL@1:0-1:3)) - EXP - end - - def assert_error_tolerant(src, expected, keep_tokens: false) - begin - verbose_bak, $VERBOSE = $VERBOSE, false - node = RubyVM::AbstractSyntaxTree.parse(src, error_tolerant: true, keep_tokens: keep_tokens) - ensure - $VERBOSE = verbose_bak - end - assert_nil($!) - str = "" - PP.pp(node, str, 80) - assert_equal(expected, str) - node - end end diff --git a/test/ruby/test_autoload.rb b/test/ruby/test_autoload.rb index e475520321..7010645317 100644 --- a/test/ruby/test_autoload.rb +++ b/test/ruby/test_autoload.rb @@ -168,7 +168,6 @@ p Foo::Bar end def test_nameerror_when_autoload_did_not_define_the_constant - verbose_bak, $VERBOSE = $VERBOSE, nil Tempfile.create(['autoload', '.rb']) {|file| file.puts '' file.close @@ -181,8 +180,6 @@ p Foo::Bar remove_autoload_constant end } - ensure - $VERBOSE = verbose_bak end def test_override_autoload @@ -464,23 +461,6 @@ p Foo::Bar end end - def test_source_location_after_require - bug = "Bug18624" - Dir.mktmpdir('autoload') do |tmpdir| - path = "#{tmpdir}/test-#{bug}.rb" - File.write(path, "C::#{bug} = __FILE__\n") - assert_separately(%W[-I #{tmpdir}], "#{<<-"begin;"}\n#{<<-"end;"}") - begin; - class C; end - C.autoload(:Bug18624, #{path.dump}) - require #{path.dump} - assert_equal [#{path.dump}, 1], C.const_source_location(#{bug.dump}) - assert_equal #{path.dump}, C.const_get(#{bug.dump}) - assert_equal [#{path.dump}, 1], C.const_source_location(#{bug.dump}) - end; - end - end - def test_no_memory_leak assert_no_memory_leak([], '', "#{<<~"begin;"}\n#{<<~'end;'}", 'many autoloads', timeout: 60) begin; @@ -500,7 +480,6 @@ p Foo::Bar File.write(autoload_path, '') assert_separately(%W[-I #{tmpdir}], <<-RUBY) - $VERBOSE = nil path = #{File.realpath(autoload_path).inspect} autoload :X, path assert_equal(path, Object.autoload?(:X)) @@ -530,69 +509,4 @@ p Foo::Bar ::Object.class_eval {remove_const(:AutoloadTest)} if defined? Object::AutoloadTest TestAutoload.class_eval {remove_const(:AutoloadTest)} if defined? TestAutoload::AutoloadTest end - - def test_autoload_module_gc - Dir.mktmpdir('autoload') do |tmpdir| - autoload_path = File.join(tmpdir, "autoload_module_gc.rb") - File.write(autoload_path, "X = 1; Y = 2;") - - x = Module.new - x.autoload :X, "./feature.rb" - - 1000.times do - y = Module.new - y.autoload :Y, "./feature.rb" - end - - x = y = nil - - # Ensure the internal data structures are cleaned up correctly / don't crash: - GC.start - end - end - - def test_autoload_parallel_race - Dir.mktmpdir('autoload') do |tmpdir| - autoload_path = File.join(tmpdir, "autoload_parallel_race.rb") - File.write(autoload_path, 'module Foo; end; module Bar; end') - - assert_separately([], <<-RUBY, timeout: 100) - autoload_path = #{File.realpath(autoload_path).inspect} - - # This should work with no errors or failures. - 1000.times do - autoload :Foo, autoload_path - autoload :Bar, autoload_path - - t1 = Thread.new {Foo} - t2 = Thread.new {Bar} - - t1.join - GC.start # force GC. - t2.join - - Object.send(:remove_const, :Foo) - Object.send(:remove_const, :Bar) - - $LOADED_FEATURES.delete(autoload_path) - end - RUBY - end - end - - def test_autoload_parent_namespace - Dir.mktmpdir('autoload') do |tmpdir| - autoload_path = File.join(tmpdir, "some_const.rb") - File.write(autoload_path, 'class SomeConst; end') - - assert_separately(%W[-I #{tmpdir}], <<-RUBY) - module SomeNamespace - autoload :SomeConst, #{File.realpath(autoload_path).inspect} - assert_warning(%r{/some_const\.rb to define SomeNamespace::SomeConst but it didn't}) do - assert_not_nil SomeConst - end - end - RUBY - end - end end diff --git a/test/ruby/test_backtrace.rb b/test/ruby/test_backtrace.rb index d35dead95b..aa79db24cb 100644 --- a/test/ruby/test_backtrace.rb +++ b/test/ruby/test_backtrace.rb @@ -154,35 +154,6 @@ class TestBacktrace < Test::Unit::TestCase assert_equal caller(0), caller(0, nil) end - def test_each_backtrace_location - i = 0 - cl = caller_locations(1, 1)[0]; ecl = Thread.each_caller_location{|x| i+=1; break x if i == 1} - assert_equal(cl.to_s, ecl.to_s) - assert_kind_of(Thread::Backtrace::Location, ecl) - - i = 0 - ary = [] - cllr = caller_locations(1, 2); last = Thread.each_caller_location{|x| ary << x; i+=1; break x if i == 2} - assert_equal(cllr.map(&:to_s), ary.map(&:to_s)) - assert_kind_of(Thread::Backtrace::Location, last) - - i = 0 - ary = [] - ->{->{ - cllr = caller_locations(1, 2); last = Thread.each_caller_location{|x| ary << x; i+=1; break x if i == 2} - }.()}.() - assert_equal(cllr.map(&:to_s), ary.map(&:to_s)) - assert_kind_of(Thread::Backtrace::Location, last) - - cllr = caller_locations(1, 2); ary = Thread.to_enum(:each_caller_location).to_a[2..3] - assert_equal(cllr.map(&:to_s), ary.map(&:to_s)) - - ecl = Thread.to_enum(:each_caller_location) - assert_raise(StopIteration) { - ecl.next - } - end - def test_caller_locations_first_label def self.label caller_locations.first.label @@ -215,15 +186,15 @@ class TestBacktrace < Test::Unit::TestCase @res = caller_locations(2, 1).inspect end @line = __LINE__ + 1 - [1].map.map { [1].map.map { foo } } - assert_equal("[\"#{__FILE__}:#{@line}:in `map'\"]", @res) + 1.times.map { 1.times.map { foo } } + assert_equal("[\"#{__FILE__}:#{@line}:in `times'\"]", @res) end def test_caller_location_path_cfunc_iseq_no_pc def self.foo @res = caller_locations(2, 1)[0].path end - [1].map.map { [1].map.map { foo } } + 1.times.map { 1.times.map { foo } } assert_equal(__FILE__, @res) end diff --git a/test/ruby/test_beginendblock.rb b/test/ruby/test_beginendblock.rb index 301a746f4a..eb8394864f 100644 --- a/test/ruby/test_beginendblock.rb +++ b/test/ruby/test_beginendblock.rb @@ -14,11 +14,6 @@ class TestBeginEndBlock < Test::Unit::TestCase assert_in_out_err(["-p", "-eBEGIN{p :begin}", "-eEND{p :end}"], "foo\nbar\n", %w(:begin foo bar :end)) end - def test_endblock_variable - assert_in_out_err(["-n", "-ea = :ok", "-eEND{p a}"], "foo\n", %w(:ok)) - assert_in_out_err(["-p", "-ea = :ok", "-eEND{p a}"], "foo\n", %w(foo :ok)) - end - def test_begininmethod assert_raise_with_message(SyntaxError, /BEGIN is permitted only at toplevel/) do eval("def foo; BEGIN {}; end") @@ -45,9 +40,9 @@ class TestBeginEndBlock < Test::Unit::TestCase end def test_endblockwarn_in_eval - assert_in_out_err([], "#{<<~"begin;"}\n#{<<~'end;'}", [], ['test.rb:1: warning: END in method; use at_exit']) + assert_in_out_err([], "#{<<~"begin;"}\n#{<<~'end;'}", [], ['(eval):2: warning: END in method; use at_exit']) begin; - eval <<-EOE, nil, "test.rb", 0 + eval <<-EOE def end2 END {} end diff --git a/test/ruby/test_bignum.rb b/test/ruby/test_bignum.rb index 065a944853..3ffe7114b5 100644 --- a/test/ruby/test_bignum.rb +++ b/test/ruby/test_bignum.rb @@ -203,15 +203,6 @@ class TestBignum < Test::Unit::TestCase assert_equal(00_02, '00_02'.to_i) end - def test_very_big_str_to_inum - assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") - begin; - digits = [["3", 700], ["0", 2700], ["1", 1], ["0", 26599]] - num = digits.inject("") {|s,(c,n)|s << c*n}.to_i - assert_equal digits.sum {|c,n|n}, num.to_s.size - end; - end - def test_to_s2 assert_raise(ArgumentError) { T31P.to_s(37) } assert_equal("9" * 32768, (10**32768-1).to_s) @@ -653,7 +644,7 @@ class TestBignum < Test::Unit::TestCase thread.raise thread.join time = Time.now - time - omit "too fast cpu" if end_flag + skip "too fast cpu" if end_flag assert_operator(time, :<, 10) end @@ -684,7 +675,7 @@ class TestBignum < Test::Unit::TestCase return end end - omit "cannot create suitable test case" + skip "cannot create suitable test case" ensure Signal.trap(:INT, oldtrap) if oldtrap end diff --git a/test/ruby/test_call.rb b/test/ruby/test_call.rb index 88a0df4388..67b3a936d4 100644 --- a/test/ruby/test_call.rb +++ b/test/ruby/test_call.rb @@ -1,6 +1,5 @@ # frozen_string_literal: false require 'test/unit' -require '-test-/iter' class TestCall < Test::Unit::TestCase def aaa(a, b=100, *rest) @@ -48,19 +47,12 @@ class TestCall < Test::Unit::TestCase assert_equal(5, o.y) o&.z ||= 6 assert_equal(6, o.z) - o&.z &&= 7 - assert_equal(7, o.z) o = nil assert_nil(o&.x) assert_nothing_raised(NoMethodError) {o&.x = raise} - assert_nothing_raised(NoMethodError) {o&.x = raise; nil} assert_nothing_raised(NoMethodError) {o&.x *= raise} assert_nothing_raised(NoMethodError) {o&.x *= raise; nil} - assert_nothing_raised(NoMethodError) {o&.x ||= raise} - assert_nothing_raised(NoMethodError) {o&.x ||= raise; nil} - assert_nothing_raised(NoMethodError) {o&.x &&= raise} - assert_nothing_raised(NoMethodError) {o&.x &&= raise; nil} end def test_safe_call_evaluate_arguments_only_method_call_is_made @@ -100,21 +92,6 @@ class TestCall < Test::Unit::TestCase } end - def test_call_bmethod_proc - pr = proc{|sym| sym} - define_singleton_method(:a, &pr) - ary = [10] - assert_equal(10, a(*ary)) - end - - def test_call_bmethod_proc_restarg - pr = proc{|*sym| sym} - define_singleton_method(:a, &pr) - ary = [10] - assert_equal([10], a(*ary)) - assert_equal([10], a(10)) - end - def test_call_splat_order bug12860 = '[ruby-core:77701] [Bug# 12860]' ary = [1, 2] @@ -131,968 +108,4 @@ class TestCall < Test::Unit::TestCase ary = [1, 2, b] assert_equal([0, 1, 2, b], aaa(0, *ary, &ary.pop), bug16504) end - - OVER_STACK_LEN = (ENV['RUBY_OVER_STACK_LEN'] || 150).to_i # Greater than VM_ARGC_STACK_MAX - OVER_STACK_ARGV = OVER_STACK_LEN.times.to_a.freeze - - def test_call_cfunc_splat_large_array_bug_4040 - a = OVER_STACK_ARGV - - assert_equal(a, [].push(*a)) - assert_equal(a, [].push(a[0], *a[1..])) - assert_equal(a, [].push(a[0], a[1], *a[2..])) - assert_equal(a, [].push(*a[0..1], *a[2..])) - assert_equal(a, [].push(*a[...-1], a[-1])) - assert_equal(a, [].push(a[0], *a[1...-1], a[-1])) - assert_equal(a, [].push(a[0], a[1], *a[2...-1], a[-1])) - assert_equal(a, [].push(*a[0..1], *a[2...-1], a[-1])) - assert_equal(a, [].push(*a[...-2], a[-2], a[-1])) - assert_equal(a, [].push(a[0], *a[1...-2], a[-2], a[-1])) - assert_equal(a, [].push(a[0], a[1], *a[2...-2], a[-2], a[-1])) - assert_equal(a, [].push(*a[0..1], *a[2...-2], a[-2], a[-1])) - - kw = {x: 1} - a_kw = a + [kw] - - assert_equal(a_kw, [].push(*a, **kw)) - assert_equal(a_kw, [].push(a[0], *a[1..], **kw)) - assert_equal(a_kw, [].push(a[0], a[1], *a[2..], **kw)) - assert_equal(a_kw, [].push(*a[0..1], *a[2..], **kw)) - assert_equal(a_kw, [].push(*a[...-1], a[-1], **kw)) - assert_equal(a_kw, [].push(a[0], *a[1...-1], a[-1], **kw)) - assert_equal(a_kw, [].push(a[0], a[1], *a[2...-1], a[-1], **kw)) - assert_equal(a_kw, [].push(*a[0..1], *a[2...-1], a[-1], **kw)) - assert_equal(a_kw, [].push(*a[...-2], a[-2], a[-1], **kw)) - assert_equal(a_kw, [].push(a[0], *a[1...-2], a[-2], a[-1], **kw)) - assert_equal(a_kw, [].push(a[0], a[1], *a[2...-2], a[-2], a[-1], **kw)) - assert_equal(a_kw, [].push(*a[0..1], *a[2...-2], a[-2], a[-1], **kw)) - - assert_equal(a_kw, [].push(*a, x: 1)) - assert_equal(a_kw, [].push(a[0], *a[1..], x: 1)) - assert_equal(a_kw, [].push(a[0], a[1], *a[2..], x: 1)) - assert_equal(a_kw, [].push(*a[0..1], *a[2..], x: 1)) - assert_equal(a_kw, [].push(*a[...-1], a[-1], x: 1)) - assert_equal(a_kw, [].push(a[0], *a[1...-1], a[-1], x: 1)) - assert_equal(a_kw, [].push(a[0], a[1], *a[2...-1], a[-1], x: 1)) - assert_equal(a_kw, [].push(*a[0..1], *a[2...-1], a[-1], x: 1)) - assert_equal(a_kw, [].push(*a[...-2], a[-2], a[-1], x: 1)) - assert_equal(a_kw, [].push(a[0], *a[1...-2], a[-2], a[-1], x: 1)) - assert_equal(a_kw, [].push(a[0], a[1], *a[2...-2], a[-2], a[-1], x: 1)) - assert_equal(a_kw, [].push(*a[0..1], *a[2...-2], a[-2], a[-1], x: 1)) - - a_kw[-1][:y] = 2 - kw = {y: 2} - - assert_equal(a_kw, [].push(*a, x: 1, **kw)) - assert_equal(a_kw, [].push(a[0], *a[1..], x: 1, **kw)) - assert_equal(a_kw, [].push(a[0], a[1], *a[2..], x: 1, **kw)) - assert_equal(a_kw, [].push(*a[0..1], *a[2..], x: 1, **kw)) - assert_equal(a_kw, [].push(*a[...-1], a[-1], x: 1, **kw)) - assert_equal(a_kw, [].push(a[0], *a[1...-1], a[-1], x: 1, **kw)) - assert_equal(a_kw, [].push(a[0], a[1], *a[2...-1], a[-1], x: 1, **kw)) - assert_equal(a_kw, [].push(*a[0..1], *a[2...-1], a[-1], x: 1, **kw)) - assert_equal(a_kw, [].push(*a[...-2], a[-2], a[-1], x: 1, **kw)) - assert_equal(a_kw, [].push(a[0], *a[1...-2], a[-2], a[-1], x: 1, **kw)) - assert_equal(a_kw, [].push(a[0], a[1], *a[2...-2], a[-2], a[-1], x: 1, **kw)) - assert_equal(a_kw, [].push(*a[0..1], *a[2...-2], a[-2], a[-1], x: 1, **kw)) - - kw = {} - - assert_equal(a, [].push(*a, **kw)) - assert_equal(a, [].push(a[0], *a[1..], **kw)) - assert_equal(a, [].push(a[0], a[1], *a[2..], **kw)) - assert_equal(a, [].push(*a[0..1], *a[2..], **kw)) - assert_equal(a, [].push(*a[...-1], a[-1], **kw)) - assert_equal(a, [].push(a[0], *a[1...-1], a[-1], **kw)) - assert_equal(a, [].push(a[0], a[1], *a[2...-1], a[-1], **kw)) - assert_equal(a, [].push(*a[0..1], *a[2...-1], a[-1], **kw)) - assert_equal(a, [].push(*a[...-2], a[-2], a[-1], **kw)) - assert_equal(a, [].push(a[0], *a[1...-2], a[-2], a[-1], **kw)) - assert_equal(a, [].push(a[0], a[1], *a[2...-2], a[-2], a[-1], **kw)) - assert_equal(a, [].push(*a[0..1], *a[2...-2], a[-2], a[-1], **kw)) - - a_kw = a + [Hash.ruby2_keywords_hash({})] - assert_equal(a, [].push(*a_kw)) - - # Single test with value that would cause SystemStackError. - # Not all tests use such a large array to reduce testing time. - assert_equal(1380888, [].push(*1380888.times.to_a).size) - end - - def test_call_iseq_large_array_splat_fail - def self.a; end - def self.b(a=1); end - def self.c(k: 1); end - def self.d(**kw); end - def self.e(k: 1, **kw); end - def self.f(a=1, k: 1); end - def self.g(a=1, **kw); end - def self.h(a=1, k: 1, **kw); end - - (:a..:h).each do |meth| - assert_raise_with_message(ArgumentError, /wrong number of arguments \(given #{OVER_STACK_LEN}, expected 0(\.\.[12])?\)/) do - instance_eval("#{meth}(*OVER_STACK_ARGV)", __FILE__, __LINE__) - end - end - end - - def test_call_iseq_large_array_splat_pass - def self.a(*a); a.length end - assert_equal OVER_STACK_LEN, a(*OVER_STACK_ARGV) - - def self.b(_, *a); a.length end - assert_equal (OVER_STACK_LEN - 1), b(*OVER_STACK_ARGV) - - def self.c(_, *a, _); a.length end - assert_equal (OVER_STACK_LEN - 2), c(*OVER_STACK_ARGV) - - def self.d(b=1, *a); a.length end - assert_equal (OVER_STACK_LEN - 1), d(*OVER_STACK_ARGV) - - def self.e(b=1, *a, _); a.length end - assert_equal (OVER_STACK_LEN - 2), e(*OVER_STACK_ARGV) - - def self.f(b, *a); a.length end - assert_equal (OVER_STACK_LEN - 1), f(*OVER_STACK_ARGV) - - def self.g(*a, k: 1); a.length end - assert_equal OVER_STACK_LEN, g(*OVER_STACK_ARGV) - - def self.h(*a, **kw); a.length end - assert_equal OVER_STACK_LEN, h(*OVER_STACK_ARGV) - - def self.i(*a, k: 1, **kw); a.length end - assert_equal OVER_STACK_LEN, i(*OVER_STACK_ARGV) - - def self.j(b=1, *a, k: 1); a.length end - assert_equal (OVER_STACK_LEN - 1), j(*OVER_STACK_ARGV) - - def self.k(b=1, *a, **kw); a.length end - assert_equal (OVER_STACK_LEN - 1), k(*OVER_STACK_ARGV) - - def self.l(b=1, *a, k: 1, **kw); a.length end - assert_equal (OVER_STACK_LEN - 1), l(*OVER_STACK_ARGV) - - def self.m(b=1, *a, _, k: 1); a.length end - assert_equal (OVER_STACK_LEN - 2), m(*OVER_STACK_ARGV) - - def self.n(b=1, *a, _, **kw); a.length end - assert_equal (OVER_STACK_LEN - 2), n(*OVER_STACK_ARGV) - - def self.o(b=1, *a, _, k: 1, **kw); a.length end - assert_equal (OVER_STACK_LEN - 2), o(*OVER_STACK_ARGV) - end - - def test_call_iseq_large_array_splat_with_large_number_of_parameters - args = OVER_STACK_ARGV.map{|i| "a#{i}"}.join(',') - args1 = (OVER_STACK_LEN-1).times.map{|i| "a#{i}"}.join(',') - - singleton_class.class_eval("def a(#{args}); [#{args}] end") - assert_equal OVER_STACK_ARGV, a(*OVER_STACK_ARGV) - - singleton_class.class_eval("def b(#{args}, b=0); [#{args}, b] end") - assert_equal(OVER_STACK_ARGV + [0], b(*OVER_STACK_ARGV)) - - singleton_class.class_eval("def c(#{args}, *b); [#{args}, b] end") - assert_equal(OVER_STACK_ARGV + [[]], c(*OVER_STACK_ARGV)) - - singleton_class.class_eval("def d(#{args1}, *b); [#{args1}, b] end") - assert_equal(OVER_STACK_ARGV[0...-1] + [[OVER_STACK_ARGV.last]], d(*OVER_STACK_ARGV)) - end if OVER_STACK_LEN < 200 - - def test_call_proc_large_array_splat_pass - [ - proc{0} , - proc{|a=1|a}, - proc{|k: 1|0}, - proc{|**kw| 0}, - proc{|k: 1, **kw| 0}, - proc{|a=1, k: 1| a}, - proc{|a=1, **kw| a}, - proc{|a=1, k: 1, **kw| a}, - ].each do |l| - assert_equal 0, l.call(*OVER_STACK_ARGV) - end - - assert_equal OVER_STACK_LEN, proc{|*a| a.length}.(*OVER_STACK_ARGV) - assert_equal (OVER_STACK_LEN - 1), proc{|_, *a| a.length}.(*OVER_STACK_ARGV) - assert_equal (OVER_STACK_LEN - 2), proc{|_, *a, _| a.length}.(*OVER_STACK_ARGV) - assert_equal (OVER_STACK_LEN - 1), proc{|b=1, *a| a.length}.(*OVER_STACK_ARGV) - assert_equal (OVER_STACK_LEN - 2), proc{|b=1, *a, _| a.length}.(*OVER_STACK_ARGV) - assert_equal (OVER_STACK_LEN - 1), proc{|b=1, *a| a.length}.(*OVER_STACK_ARGV) - assert_equal OVER_STACK_LEN, proc{|*a, k: 1| a.length}.(*OVER_STACK_ARGV) - assert_equal OVER_STACK_LEN, proc{|*a, **kw| a.length}.(*OVER_STACK_ARGV) - assert_equal OVER_STACK_LEN, proc{|*a, k: 1, **kw| a.length}.(*OVER_STACK_ARGV) - assert_equal (OVER_STACK_LEN - 1), proc{|b=1, *a, k: 1| a.length}.(*OVER_STACK_ARGV) - assert_equal (OVER_STACK_LEN - 1), proc{|b=1, *a, **kw| a.length}.(*OVER_STACK_ARGV) - assert_equal (OVER_STACK_LEN - 1), proc{|b=1, *a, k: 1, **kw| a.length}.(*OVER_STACK_ARGV) - assert_equal (OVER_STACK_LEN - 2), proc{|b=1, *a, _, k: 1| a.length}.(*OVER_STACK_ARGV) - assert_equal (OVER_STACK_LEN - 2), proc{|b=1, *a, _, **kw| a.length}.(*OVER_STACK_ARGV) - assert_equal (OVER_STACK_LEN - 2), proc{|b=1, *a, _, k: 1, **kw| a.length}.(*OVER_STACK_ARGV) - end - - def test_call_proc_large_array_splat_with_large_number_of_parameters - args = OVER_STACK_ARGV.map{|i| "a#{i}"}.join(',') - args1 = (OVER_STACK_LEN-1).times.map{|i| "a#{i}"}.join(',') - - l = instance_eval("proc{|#{args}| [#{args}]}") - assert_equal OVER_STACK_ARGV, l.(*OVER_STACK_ARGV) - - l = instance_eval("proc{|#{args}, b| [#{args}, b]}") - assert_equal(OVER_STACK_ARGV + [nil], l.(*OVER_STACK_ARGV)) - - l = instance_eval("proc{|#{args1}| [#{args1}]}") - assert_equal(OVER_STACK_ARGV[0...-1], l.(*OVER_STACK_ARGV)) - - l = instance_eval("proc{|#{args}, *b| [#{args}, b]}") - assert_equal(OVER_STACK_ARGV + [[]], l.(*OVER_STACK_ARGV)) - - l = instance_eval("proc{|#{args1}, *b| [#{args1}, b]}") - assert_equal(OVER_STACK_ARGV[0...-1] + [[OVER_STACK_ARGV.last]], l.(*OVER_STACK_ARGV)) - - l = instance_eval("proc{|#{args}, b, *c| [#{args}, b, c]}") - assert_equal(OVER_STACK_ARGV + [nil, []], l.(*OVER_STACK_ARGV)) - - l = instance_eval("proc{|#{args}, b, *c, d| [#{args}, b, c, d]}") - assert_equal(OVER_STACK_ARGV + [nil, [], nil], l.(*OVER_STACK_ARGV)) - end if OVER_STACK_LEN < 200 - - def test_call_lambda_large_array_splat_fail - [ - ->{} , - ->(a=1){}, - ->(k: 1){}, - ->(**kw){}, - ->(k: 1, **kw){}, - ->(a=1, k: 1){}, - ->(a=1, **kw){}, - ->(a=1, k: 1, **kw){}, - ].each do |l| - assert_raise_with_message(ArgumentError, /wrong number of arguments \(given #{OVER_STACK_LEN}, expected 0(\.\.[12])?\)/) do - l.call(*OVER_STACK_ARGV) - end - end - end - - def test_call_lambda_large_array_splat_pass - assert_equal OVER_STACK_LEN, ->(*a){a.length}.(*OVER_STACK_ARGV) - assert_equal (OVER_STACK_LEN - 1), ->(_, *a){a.length}.(*OVER_STACK_ARGV) - assert_equal (OVER_STACK_LEN - 2), ->(_, *a, _){a.length}.(*OVER_STACK_ARGV) - assert_equal (OVER_STACK_LEN - 1), ->(b=1, *a){a.length}.(*OVER_STACK_ARGV) - assert_equal (OVER_STACK_LEN - 2), ->(b=1, *a, _){a.length}.(*OVER_STACK_ARGV) - assert_equal (OVER_STACK_LEN - 1), ->(b, *a){a.length}.(*OVER_STACK_ARGV) - assert_equal OVER_STACK_LEN, ->(*a, k: 1){a.length}.(*OVER_STACK_ARGV) - assert_equal OVER_STACK_LEN, ->(*a, **kw){a.length}.(*OVER_STACK_ARGV) - assert_equal OVER_STACK_LEN, ->(*a, k: 1, **kw){a.length}.(*OVER_STACK_ARGV) - assert_equal (OVER_STACK_LEN - 1), ->(b=1, *a, k: 1){a.length}.(*OVER_STACK_ARGV) - assert_equal (OVER_STACK_LEN - 1), ->(b=1, *a, **kw){a.length}.(*OVER_STACK_ARGV) - assert_equal (OVER_STACK_LEN - 1), ->(b=1, *a, k: 1, **kw){a.length}.(*OVER_STACK_ARGV) - assert_equal (OVER_STACK_LEN - 2), ->(b=1, *a, _, k: 1){a.length}.(*OVER_STACK_ARGV) - assert_equal (OVER_STACK_LEN - 2), ->(b=1, *a, _, **kw){a.length}.(*OVER_STACK_ARGV) - assert_equal (OVER_STACK_LEN - 2), ->(b=1, *a, _, k: 1, **kw){a.length}.(*OVER_STACK_ARGV) - end - - def test_call_yield_block_large_array_splat_pass - def self.a - yield(*OVER_STACK_ARGV) - end - - [ - proc{0} , - proc{|a=1|a}, - proc{|k: 1|0}, - proc{|**kw| 0}, - proc{|k: 1, **kw| 0}, - proc{|a=1, k: 1| a}, - proc{|a=1, **kw| a}, - proc{|a=1, k: 1, **kw| a}, - ].each do |l| - assert_equal 0, a(&l) - end - - assert_equal OVER_STACK_LEN, a{|*a| a.length} - assert_equal (OVER_STACK_LEN - 1), a{|_, *a| a.length} - assert_equal (OVER_STACK_LEN - 2), a{|_, *a, _| a.length} - assert_equal (OVER_STACK_LEN - 1), a{|b=1, *a| a.length} - assert_equal (OVER_STACK_LEN - 2), a{|b=1, *a, _| a.length} - assert_equal (OVER_STACK_LEN - 1), a{|b, *a| a.length} - assert_equal OVER_STACK_LEN, a{|*a, k: 1| a.length} - assert_equal OVER_STACK_LEN, a{|*a, **kw| a.length} - assert_equal OVER_STACK_LEN, a{|*a, k: 1, **kw| a.length} - assert_equal (OVER_STACK_LEN - 1), a{|b=1, *a, k: 1| a.length} - assert_equal (OVER_STACK_LEN - 1), a{|b=1, *a, **kw| a.length} - assert_equal (OVER_STACK_LEN - 1), a{|b=1, *a, k: 1, **kw| a.length} - assert_equal (OVER_STACK_LEN - 2), a{|b=1, *a, _, k: 1| a.length} - assert_equal (OVER_STACK_LEN - 2), a{|b=1, *a, _, **kw| a.length} - assert_equal (OVER_STACK_LEN - 2), a{|b=1, *a, _, k: 1, **kw| a.length} - end - - def test_call_yield_large_array_splat_with_large_number_of_parameters - def self.a - yield(*OVER_STACK_ARGV) - end - - args = OVER_STACK_ARGV.map{|i| "a#{i}"}.join(',') - args1 = (OVER_STACK_LEN-1).times.map{|i| "a#{i}"}.join(',') - - assert_equal OVER_STACK_ARGV, instance_eval("a{|#{args}| [#{args}]}", __FILE__, __LINE__) - assert_equal(OVER_STACK_ARGV + [nil], instance_eval("a{|#{args}, b| [#{args}, b]}", __FILE__, __LINE__)) - assert_equal(OVER_STACK_ARGV[0...-1], instance_eval("a{|#{args1}| [#{args1}]}", __FILE__, __LINE__)) - assert_equal(OVER_STACK_ARGV + [[]], instance_eval("a{|#{args}, *b| [#{args}, b]}", __FILE__, __LINE__)) - assert_equal(OVER_STACK_ARGV[0...-1] + [[OVER_STACK_ARGV.last]], instance_eval("a{|#{args1}, *b| [#{args1}, b]}", __FILE__, __LINE__)) - assert_equal(OVER_STACK_ARGV + [nil, []], instance_eval("a{|#{args}, b, *c| [#{args}, b, c]}", __FILE__, __LINE__)) - assert_equal(OVER_STACK_ARGV + [nil, [], nil], instance_eval("a{|#{args}, b, *c, d| [#{args}, b, c, d]}", __FILE__, __LINE__)) - end if OVER_STACK_LEN < 200 - - def test_call_yield_lambda_large_array_splat_fail - def self.a - yield(*OVER_STACK_ARGV) - end - [ - ->{} , - ->(a=1){}, - ->(k: 1){}, - ->(**kw){}, - ->(k: 1, **kw){}, - ->(a=1, k: 1){}, - ->(a=1, **kw){}, - ->(a=1, k: 1, **kw){}, - ].each do |l| - assert_raise_with_message(ArgumentError, /wrong number of arguments \(given #{OVER_STACK_LEN}, expected 0(\.\.[12])?\)/) do - a(&l) - end - end - end - - def test_call_yield_lambda_large_array_splat_pass - def self.a - yield(*OVER_STACK_ARGV) - end - - assert_equal OVER_STACK_LEN, a(&->(*a){a.length}) - assert_equal (OVER_STACK_LEN - 1), a(&->(_, *a){a.length}) - assert_equal (OVER_STACK_LEN - 2), a(&->(_, *a, _){a.length}) - assert_equal (OVER_STACK_LEN - 1), a(&->(b=1, *a){a.length}) - assert_equal (OVER_STACK_LEN - 2), a(&->(b=1, *a, _){a.length}) - assert_equal (OVER_STACK_LEN - 1), a(&->(b, *a){a.length}) - assert_equal OVER_STACK_LEN, a(&->(*a, k: 1){a.length}) - assert_equal OVER_STACK_LEN, a(&->(*a, **kw){a.length}) - assert_equal OVER_STACK_LEN, a(&->(*a, k: 1, **kw){a.length}) - assert_equal (OVER_STACK_LEN - 1), a(&->(b=1, *a, k: 1){a.length}) - assert_equal (OVER_STACK_LEN - 1), a(&->(b=1, *a, **kw){a.length}) - assert_equal (OVER_STACK_LEN - 1), a(&->(b=1, *a, k: 1, **kw){a.length}) - assert_equal (OVER_STACK_LEN - 2), a(&->(b=1, *a, _, k: 1){a.length}) - assert_equal (OVER_STACK_LEN - 2), a(&->(b=1, *a, _, **kw){a.length}) - assert_equal (OVER_STACK_LEN - 2), a(&->(b=1, *a, _, k: 1, **kw){a.length}) - end - - def test_call_send_iseq_large_array_splat_fail - def self.a; end - def self.b(a=1); end - def self.c(k: 1); end - def self.d(**kw); end - def self.e(k: 1, **kw); end - def self.f(a=1, k: 1); end - def self.g(a=1, **kw); end - def self.h(a=1, k: 1, **kw); end - - (:a..:h).each do |meth| - assert_raise_with_message(ArgumentError, /wrong number of arguments \(given #{OVER_STACK_LEN}, expected 0(\.\.[12])?\)/) do - send(meth, *OVER_STACK_ARGV) - end - end - end - - def test_call_send_iseq_large_array_splat_pass - def self.a(*a); a.length end - assert_equal OVER_STACK_LEN, send(:a, *OVER_STACK_ARGV) - - def self.b(_, *a); a.length end - assert_equal (OVER_STACK_LEN - 1), send(:b, *OVER_STACK_ARGV) - - def self.c(_, *a, _); a.length end - assert_equal (OVER_STACK_LEN - 2), send(:c, *OVER_STACK_ARGV) - - def self.d(b=1, *a); a.length end - assert_equal (OVER_STACK_LEN - 1), send(:d, *OVER_STACK_ARGV) - - def self.e(b=1, *a, _); a.length end - assert_equal (OVER_STACK_LEN - 2), send(:e, *OVER_STACK_ARGV) - - def self.f(b, *a); a.length end - assert_equal (OVER_STACK_LEN - 1), send(:f, *OVER_STACK_ARGV) - - def self.g(*a, k: 1); a.length end - assert_equal OVER_STACK_LEN, send(:g, *OVER_STACK_ARGV) - - def self.h(*a, **kw); a.length end - assert_equal OVER_STACK_LEN, send(:h, *OVER_STACK_ARGV) - - def self.i(*a, k: 1, **kw); a.length end - assert_equal OVER_STACK_LEN, send(:i, *OVER_STACK_ARGV) - - def self.j(b=1, *a, k: 1); a.length end - assert_equal (OVER_STACK_LEN - 1), send(:j, *OVER_STACK_ARGV) - - def self.k(b=1, *a, **kw); a.length end - assert_equal (OVER_STACK_LEN - 1), send(:k, *OVER_STACK_ARGV) - - def self.l(b=1, *a, k: 1, **kw); a.length end - assert_equal (OVER_STACK_LEN - 1), send(:l, *OVER_STACK_ARGV) - - def self.m(b=1, *a, _, k: 1); a.length end - assert_equal (OVER_STACK_LEN - 2), send(:m, *OVER_STACK_ARGV) - - def self.n(b=1, *a, _, **kw); a.length end - assert_equal (OVER_STACK_LEN - 2), send(:n, *OVER_STACK_ARGV) - - def self.o(b=1, *a, _, k: 1, **kw); a.length end - assert_equal (OVER_STACK_LEN - 2), send(:o, *OVER_STACK_ARGV) - end - - def test_call_send_iseq_large_array_splat_with_large_number_of_parameters - args = OVER_STACK_ARGV.map{|i| "a#{i}"}.join(',') - args1 = (OVER_STACK_LEN-1).times.map{|i| "a#{i}"}.join(',') - - singleton_class.class_eval("def a(#{args}); [#{args}] end") - assert_equal OVER_STACK_ARGV, send(:a, *OVER_STACK_ARGV) - - singleton_class.class_eval("def b(#{args}, b=0); [#{args}, b] end") - assert_equal(OVER_STACK_ARGV + [0], send(:b, *OVER_STACK_ARGV)) - - singleton_class.class_eval("def c(#{args}, *b); [#{args}, b] end") - assert_equal(OVER_STACK_ARGV + [[]], send(:c, *OVER_STACK_ARGV)) - - singleton_class.class_eval("def d(#{args1}, *b); [#{args1}, b] end") - assert_equal(OVER_STACK_ARGV[0...-1] + [[OVER_STACK_ARGV.last]], send(:d, *OVER_STACK_ARGV)) - end if OVER_STACK_LEN < 200 - - def test_call_send_cfunc_large_array_splat_fail - assert_raise_with_message(ArgumentError, "wrong number of arguments (given #{OVER_STACK_LEN}, expected 0)") do - send(:object_id, *OVER_STACK_ARGV) - end - end - - def test_call_send_cfunc_large_array_splat_pass - assert_equal OVER_STACK_LEN, [].send(:push, *OVER_STACK_ARGV).length - end - - def test_call_attr_reader_large_array_splat_fail - singleton_class.send(:attr_reader, :a) - assert_raise_with_message(ArgumentError, "wrong number of arguments (given #{OVER_STACK_LEN}, expected 0)") do - a(*OVER_STACK_ARGV) - end - assert_raise_with_message(ArgumentError, "wrong number of arguments (given #{OVER_STACK_LEN}, expected 0)") do - send(:a, *OVER_STACK_ARGV) - end - end - - def test_call_attr_writer_large_array_splat_fail - singleton_class.send(:attr_writer, :a) - singleton_class.send(:alias_method, :a, :a=) - - assert_raise_with_message(ArgumentError, "wrong number of arguments (given #{OVER_STACK_LEN}, expected 1)") do - a(*OVER_STACK_ARGV) - end - assert_raise_with_message(ArgumentError, "wrong number of arguments (given #{OVER_STACK_LEN}, expected 1)") do - send(:a, *OVER_STACK_ARGV) - end - end - - def test_call_struct_aref_large_array_splat_fail - s = Struct.new(:a).new - assert_raise_with_message(ArgumentError, "wrong number of arguments (given #{OVER_STACK_LEN}, expected 0)") do - s.a(*OVER_STACK_ARGV) - end - assert_raise_with_message(ArgumentError, "wrong number of arguments (given #{OVER_STACK_LEN}, expected 0)") do - s.send(:a, *OVER_STACK_ARGV) - end - end - - def test_call_struct_aset_large_array_splat_fail - s = Struct.new(:a) do - alias b a= - end.new - assert_raise_with_message(ArgumentError, "wrong number of arguments (given #{OVER_STACK_LEN}, expected 1)") do - s.b(*OVER_STACK_ARGV) - end - assert_raise_with_message(ArgumentError, "wrong number of arguments (given #{OVER_STACK_LEN}, expected 1)") do - s.send(:b, *OVER_STACK_ARGV) - end - end - - def test_call_alias_large_array_splat - c = Class.new do - def a; end - def c(*a); a.length end - attr_accessor :e - end - sc = Class.new(c) do - alias b a - alias d c - alias f e - alias g e= - end - - obj = sc.new - assert_raise_with_message(ArgumentError, "wrong number of arguments (given #{OVER_STACK_LEN}, expected 0)") do - obj.b(*OVER_STACK_ARGV) - end - assert_raise_with_message(ArgumentError, "wrong number of arguments (given #{OVER_STACK_LEN}, expected 0)") do - obj.f(*OVER_STACK_ARGV) - end - assert_raise_with_message(ArgumentError, "wrong number of arguments (given #{OVER_STACK_LEN}, expected 1)") do - obj.g(*OVER_STACK_ARGV) - end - - assert_equal OVER_STACK_LEN, obj.d(*OVER_STACK_ARGV) - end - - def test_call_zsuper_large_array_splat - c = Class.new do - private - def a; end - def c(*a); a.length end - attr_reader :e - end - sc = Class.new(c) do - public :a - public :c - public :e - end - - obj = sc.new - assert_raise_with_message(ArgumentError, "wrong number of arguments (given #{OVER_STACK_LEN}, expected 0)") do - obj.a(*OVER_STACK_ARGV) - end - assert_raise_with_message(ArgumentError, "wrong number of arguments (given #{OVER_STACK_LEN}, expected 0)") do - obj.e(*OVER_STACK_ARGV) - end - - assert_equal OVER_STACK_LEN, obj.c(*OVER_STACK_ARGV) - end - - class RefinedModuleLargeArrayTest - c = self - using(Module.new do - refine c do - def a; end - def c(*a) a.length end - attr_reader :e - end - end) - - def b - a(*OVER_STACK_ARGV) - end - - def d - c(*OVER_STACK_ARGV) - end - - def f - e(*OVER_STACK_ARGV) - end - end - - def test_call_refined_large_array_splat_fail - assert_raise_with_message(ArgumentError, "wrong number of arguments (given #{OVER_STACK_LEN}, expected 0)") do - RefinedModuleLargeArrayTest.new.b - end - - assert_raise_with_message(ArgumentError, "wrong number of arguments (given #{OVER_STACK_LEN}, expected 0)") do - RefinedModuleLargeArrayTest.new.f - end - end - - def test_call_refined_large_array_splat_pass - assert_equal OVER_STACK_LEN, RefinedModuleLargeArrayTest.new.d - end - - def test_call_method_missing_iseq_large_array_splat_fail - def self.method_missing(_) end - assert_raise_with_message(ArgumentError, "wrong number of arguments (given #{OVER_STACK_LEN+1}, expected 1)") do - nonexistent_method(*OVER_STACK_ARGV) - end - - assert_raise_with_message(ArgumentError, "wrong number of arguments (given #{OVER_STACK_LEN+1}, expected 1)") do - send(:nonexistent_method, *OVER_STACK_ARGV) - end - - assert_raise_with_message(ArgumentError, "wrong number of arguments (given #{OVER_STACK_LEN+1}, expected 1)") do - send("nonexistent_method123", *OVER_STACK_ARGV) - end - end - - def test_call_method_missing_iseq_large_array_splat_pass - def self.method_missing(m, *a) - a.length - end - assert_equal OVER_STACK_LEN, nonexistent_method(*OVER_STACK_ARGV) - assert_equal OVER_STACK_LEN, send(:nonexistent_method, *OVER_STACK_ARGV) - assert_equal OVER_STACK_LEN, send("nonexistent_method123", *OVER_STACK_ARGV) - end - - def test_call_bmethod_large_array_splat_fail - define_singleton_method(:a){} - define_singleton_method(:b){|a=1|} - define_singleton_method(:c){|k: 1|} - define_singleton_method(:d){|**kw|} - define_singleton_method(:e){|k: 1, **kw|} - define_singleton_method(:f){|a=1, k: 1|} - define_singleton_method(:g){|a=1, **kw|} - define_singleton_method(:h){|a=1, k: 1, **kw|} - - (:a..:h).each do |meth| - assert_raise_with_message(ArgumentError, /wrong number of arguments \(given #{OVER_STACK_LEN}, expected 0(\.\.[12])?\)/) do - instance_eval("#{meth}(*OVER_STACK_ARGV)", __FILE__, __LINE__) - end - end - end - - def test_call_bmethod_large_array_splat_pass - define_singleton_method(:a){|*a| a.length} - assert_equal OVER_STACK_LEN, a(*OVER_STACK_ARGV) - - define_singleton_method(:b){|_, *a| a.length} - assert_equal (OVER_STACK_LEN - 1), b(*OVER_STACK_ARGV) - - define_singleton_method(:c){|_, *a, _| a.length} - assert_equal (OVER_STACK_LEN - 2), c(*OVER_STACK_ARGV) - - define_singleton_method(:d){|b=1, *a| a.length} - assert_equal (OVER_STACK_LEN - 1), d(*OVER_STACK_ARGV) - - define_singleton_method(:e){|b=1, *a, _| a.length} - assert_equal (OVER_STACK_LEN - 2), e(*OVER_STACK_ARGV) - - define_singleton_method(:f){|b, *a| a.length} - assert_equal (OVER_STACK_LEN - 1), f(*OVER_STACK_ARGV) - - define_singleton_method(:g){|*a, k: 1| a.length} - assert_equal OVER_STACK_LEN, g(*OVER_STACK_ARGV) - - define_singleton_method(:h){|*a, **kw| a.length} - assert_equal OVER_STACK_LEN, h(*OVER_STACK_ARGV) - - define_singleton_method(:i){|*a, k: 1, **kw| a.length} - assert_equal OVER_STACK_LEN, i(*OVER_STACK_ARGV) - - define_singleton_method(:j){|b=1, *a, k: 1| a.length} - assert_equal (OVER_STACK_LEN - 1), j(*OVER_STACK_ARGV) - - define_singleton_method(:k){|b=1, *a, **kw| a.length} - assert_equal (OVER_STACK_LEN - 1), k(*OVER_STACK_ARGV) - - define_singleton_method(:l){|b=1, *a, k: 1, **kw| a.length} - assert_equal (OVER_STACK_LEN - 1), l(*OVER_STACK_ARGV) - - define_singleton_method(:m){|b=1, *a, _, k: 1| a.length} - assert_equal (OVER_STACK_LEN - 2), m(*OVER_STACK_ARGV) - - define_singleton_method(:n){|b=1, *a, _, **kw| a.length} - assert_equal (OVER_STACK_LEN - 2), n(*OVER_STACK_ARGV) - - define_singleton_method(:o){|b=1, *a, _, k: 1, **kw| a.length} - assert_equal (OVER_STACK_LEN - 2), o(*OVER_STACK_ARGV) - end - - def test_call_method_missing_bmethod_large_array_splat_fail - define_singleton_method(:method_missing){|_|} - assert_raise_with_message(ArgumentError, "wrong number of arguments (given #{OVER_STACK_LEN+1}, expected 1)") do - nonexistent_method(*OVER_STACK_ARGV) - end - - assert_raise_with_message(ArgumentError, "wrong number of arguments (given #{OVER_STACK_LEN+1}, expected 1)") do - send(:nonexistent_method, *OVER_STACK_ARGV) - end - - assert_raise_with_message(ArgumentError, "wrong number of arguments (given #{OVER_STACK_LEN+1}, expected 1)") do - send("nonexistent_method123", *OVER_STACK_ARGV) - end - end - - def test_call_method_missing_bmethod_large_array_splat_pass - define_singleton_method(:method_missing){|_, *a| a.length} - assert_equal OVER_STACK_LEN, nonexistent_method(*OVER_STACK_ARGV) - assert_equal OVER_STACK_LEN, send(:nonexistent_method, *OVER_STACK_ARGV) - assert_equal OVER_STACK_LEN, send("nonexistent_method123", *OVER_STACK_ARGV) - end - - def test_call_symproc_large_array_splat_fail - define_singleton_method(:a){} - define_singleton_method(:b){|a=1|} - define_singleton_method(:c){|k: 1|} - define_singleton_method(:d){|**kw|} - define_singleton_method(:e){|k: 1, **kw|} - define_singleton_method(:f){|a=1, k: 1|} - define_singleton_method(:g){|a=1, **kw|} - define_singleton_method(:h){|a=1, k: 1, **kw|} - - (:a..:h).each do |meth| - assert_raise_with_message(ArgumentError, /wrong number of arguments \(given #{OVER_STACK_LEN}, expected 0(\.\.[12])?\)/) do - instance_eval(":#{meth}.to_proc.(self, *OVER_STACK_ARGV)", __FILE__, __LINE__) - end - end - end - - def test_call_symproc_large_array_splat_pass - define_singleton_method(:a){|*a| a.length} - assert_equal OVER_STACK_LEN, :a.to_proc.(self, *OVER_STACK_ARGV) - - define_singleton_method(:b){|_, *a| a.length} - assert_equal (OVER_STACK_LEN - 1), :b.to_proc.(self, *OVER_STACK_ARGV) - - define_singleton_method(:c){|_, *a, _| a.length} - assert_equal (OVER_STACK_LEN - 2), :c.to_proc.(self, *OVER_STACK_ARGV) - - define_singleton_method(:d){|b=1, *a| a.length} - assert_equal (OVER_STACK_LEN - 1), :d.to_proc.(self, *OVER_STACK_ARGV) - - define_singleton_method(:e){|b=1, *a, _| a.length} - assert_equal (OVER_STACK_LEN - 2), :e.to_proc.(self, *OVER_STACK_ARGV) - - define_singleton_method(:f){|b, *a| a.length} - assert_equal (OVER_STACK_LEN - 1), :f.to_proc.(self, *OVER_STACK_ARGV) - - define_singleton_method(:g){|*a, k: 1| a.length} - assert_equal OVER_STACK_LEN, :g.to_proc.(self, *OVER_STACK_ARGV) - - define_singleton_method(:h){|*a, **kw| a.length} - assert_equal OVER_STACK_LEN, :h.to_proc.(self, *OVER_STACK_ARGV) - - define_singleton_method(:i){|*a, k: 1, **kw| a.length} - assert_equal OVER_STACK_LEN, :i.to_proc.(self, *OVER_STACK_ARGV) - - define_singleton_method(:j){|b=1, *a, k: 1| a.length} - assert_equal (OVER_STACK_LEN - 1), :j.to_proc.(self, *OVER_STACK_ARGV) - - define_singleton_method(:k){|b=1, *a, **kw| a.length} - assert_equal (OVER_STACK_LEN - 1), :k.to_proc.(self, *OVER_STACK_ARGV) - - define_singleton_method(:l){|b=1, *a, k: 1, **kw| a.length} - assert_equal (OVER_STACK_LEN - 1), :l.to_proc.(self, *OVER_STACK_ARGV) - - define_singleton_method(:m){|b=1, *a, _, k: 1| a.length} - assert_equal (OVER_STACK_LEN - 2), :m.to_proc.(self, *OVER_STACK_ARGV) - - define_singleton_method(:n){|b=1, *a, _, **kw| a.length} - assert_equal (OVER_STACK_LEN - 2), :n.to_proc.(self, *OVER_STACK_ARGV) - - define_singleton_method(:o){|b=1, *a, _, k: 1, **kw| a.length} - assert_equal (OVER_STACK_LEN - 2), :o.to_proc.(self, *OVER_STACK_ARGV) - end - - def test_call_rb_call_iseq_large_array_splat_fail - extend Bug::Iter::Yield - l = ->(*a){} - - def self.a; end - def self.b(a=1) end - def self.c(k: 1) end - def self.d(**kw) end - def self.e(k: 1, **kw) end - def self.f(a=1, k: 1) end - def self.g(a=1, **kw) end - def self.h(a=1, k: 1, **kw) end - - (:a..:h).each do |meth| - assert_raise_with_message(ArgumentError, /wrong number of arguments \(given #{OVER_STACK_LEN}, expected 0(\.\.[12])?\)/) do - yield_block(meth, *OVER_STACK_ARGV, &l) - end - end - end - - def test_call_rb_call_iseq_large_array_splat_pass - extend Bug::Iter::Yield - l = ->(*a){a.length} - - def self.a(*a) a.length end - assert_equal OVER_STACK_LEN, yield_block(:a, *OVER_STACK_ARGV, &l) - - def self.b(_, *a) a.length end - assert_equal (OVER_STACK_LEN - 1), yield_block(:b, *OVER_STACK_ARGV, &l) - - def self.c(_, *a, _) a.length end - assert_equal (OVER_STACK_LEN - 2), yield_block(:c, *OVER_STACK_ARGV, &l) - - def self.d(b=1, *a) a.length end - assert_equal (OVER_STACK_LEN - 1), yield_block(:d, *OVER_STACK_ARGV, &l) - - def self.e(b=1, *a, _) a.length end - assert_equal (OVER_STACK_LEN - 2), yield_block(:e, *OVER_STACK_ARGV, &l) - - def self.f(b, *a) a.length end - assert_equal (OVER_STACK_LEN - 1), yield_block(:f, *OVER_STACK_ARGV, &l) - - def self.g(*a, k: 1) a.length end - assert_equal OVER_STACK_LEN, yield_block(:g, *OVER_STACK_ARGV, &l) - - def self.h(*a, **kw) a.length end - assert_equal OVER_STACK_LEN, yield_block(:h, *OVER_STACK_ARGV, &l) - - def self.i(*a, k: 1, **kw) a.length end - assert_equal OVER_STACK_LEN, yield_block(:h, *OVER_STACK_ARGV, &l) - - def self.j(b=1, *a, k: 1) a.length end - assert_equal (OVER_STACK_LEN - 1), yield_block(:j, *OVER_STACK_ARGV, &l) - - def self.k(b=1, *a, **kw) a.length end - assert_equal (OVER_STACK_LEN - 1), yield_block(:k, *OVER_STACK_ARGV, &l) - - def self.l(b=1, *a, k: 1, **kw) a.length end - assert_equal (OVER_STACK_LEN - 1), yield_block(:l, *OVER_STACK_ARGV, &l) - - def self.m(b=1, *a, _, k: 1) a.length end - assert_equal (OVER_STACK_LEN - 2), yield_block(:m, *OVER_STACK_ARGV, &l) - - def self.n(b=1, *a, _, **kw) a.length end - assert_equal (OVER_STACK_LEN - 2), yield_block(:n, *OVER_STACK_ARGV, &l) - - def self.o(b=1, *a, _, k: 1, **kw) a.length end - assert_equal (OVER_STACK_LEN - 2), yield_block(:o, *OVER_STACK_ARGV, &l) - end - - def test_call_rb_call_bmethod_large_array_splat_fail - extend Bug::Iter::Yield - l = ->(*a){} - - define_singleton_method(:a){||} - define_singleton_method(:b){|a=1|} - define_singleton_method(:c){|k: 1|} - define_singleton_method(:d){|**kw|} - define_singleton_method(:e){|k: 1, **kw|} - define_singleton_method(:f){|a=1, k: 1|} - define_singleton_method(:g){|a=1, **kw|} - define_singleton_method(:h){|a=1, k: 1, **kw|} - - (:a..:h).each do |meth| - assert_raise_with_message(ArgumentError, /wrong number of arguments \(given #{OVER_STACK_LEN}, expected 0(\.\.[12])?\)/) do - yield_block(meth, *OVER_STACK_ARGV, &l) - end - end - end - - def test_call_rb_call_bmethod_large_array_splat_pass - extend Bug::Iter::Yield - l = ->(*a){a.length} - - define_singleton_method(:a){|*a| a.length} - assert_equal OVER_STACK_LEN, yield_block(:a, *OVER_STACK_ARGV, &l) - - define_singleton_method(:b){|_, *a| a.length} - assert_equal (OVER_STACK_LEN - 1), yield_block(:b, *OVER_STACK_ARGV, &l) - - define_singleton_method(:c){|_, *a, _| a.length} - assert_equal (OVER_STACK_LEN - 2), yield_block(:c, *OVER_STACK_ARGV, &l) - - define_singleton_method(:d){|b=1, *a| a.length} - assert_equal (OVER_STACK_LEN - 1), yield_block(:d, *OVER_STACK_ARGV, &l) - - define_singleton_method(:e){|b=1, *a, _| a.length} - assert_equal (OVER_STACK_LEN - 2), yield_block(:e, *OVER_STACK_ARGV, &l) - - define_singleton_method(:f){|b, *a| a.length} - assert_equal (OVER_STACK_LEN - 1), yield_block(:f, *OVER_STACK_ARGV, &l) - - define_singleton_method(:g){|*a, k: 1| a.length} - assert_equal OVER_STACK_LEN, yield_block(:g, *OVER_STACK_ARGV, &l) - - define_singleton_method(:h){|*a, **kw| a.length} - assert_equal OVER_STACK_LEN, yield_block(:h, *OVER_STACK_ARGV, &l) - - define_singleton_method(:i){|*a, k: 1, **kw| a.length} - assert_equal OVER_STACK_LEN, yield_block(:h, *OVER_STACK_ARGV, &l) - - define_singleton_method(:j){|b=1, *a, k: 1| a.length} - assert_equal (OVER_STACK_LEN - 1), yield_block(:j, *OVER_STACK_ARGV, &l) - - define_singleton_method(:k){|b=1, *a, **kw| a.length} - assert_equal (OVER_STACK_LEN - 1), yield_block(:k, *OVER_STACK_ARGV, &l) - - define_singleton_method(:l){|b=1, *a, k: 1, **kw| a.length} - assert_equal (OVER_STACK_LEN - 1), yield_block(:l, *OVER_STACK_ARGV, &l) - - define_singleton_method(:m){|b=1, *a, _, k: 1| a.length} - assert_equal (OVER_STACK_LEN - 2), yield_block(:m, *OVER_STACK_ARGV, &l) - - define_singleton_method(:n){|b=1, *a, _, **kw| a.length} - assert_equal (OVER_STACK_LEN - 2), yield_block(:n, *OVER_STACK_ARGV, &l) - - define_singleton_method(:o){|b=1, *a, _, k: 1, **kw| a.length} - assert_equal (OVER_STACK_LEN - 2), yield_block(:o, *OVER_STACK_ARGV, &l) - end - - def test_call_ifunc_iseq_large_array_splat_fail - extend Bug::Iter::Yield - def self.a(*a) - yield(*a) - end - [ - ->(){}, - ->(a=1){}, - ->(k: 1){}, - ->(**kw){}, - ->(k: 1, **kw){}, - ->(a=1, k: 1){}, - ->(a=1, **kw){}, - ->(a=1, k: 1, **kw){}, - ].each do |l| - assert_raise_with_message(ArgumentError, /wrong number of arguments \(given #{OVER_STACK_LEN}, expected 0(\.\.[12])?\)/) do - yield_block(:a, *OVER_STACK_ARGV, &l) - end - end - end - - def test_call_ifunc_iseq_large_array_splat_pass - extend Bug::Iter::Yield - def self.a(*a) - yield(*a) - end - - l = ->(*a) do a.length end - assert_equal OVER_STACK_LEN, yield_block(:a, *OVER_STACK_ARGV, &l) - - l = ->(_, *a) do a.length end - assert_equal (OVER_STACK_LEN - 1), yield_block(:a, *OVER_STACK_ARGV, &l) - - l = ->(_, *a, _) do a.length end - assert_equal (OVER_STACK_LEN - 2), yield_block(:a, *OVER_STACK_ARGV, &l) - - l = ->(b=1, *a) do a.length end - assert_equal (OVER_STACK_LEN - 1), yield_block(:a, *OVER_STACK_ARGV, &l) - - l = ->(b=1, *a, _) do a.length end - assert_equal (OVER_STACK_LEN - 2), yield_block(:a, *OVER_STACK_ARGV, &l) - - l = ->(b, *a) do a.length end - assert_equal (OVER_STACK_LEN - 1), yield_block(:a, *OVER_STACK_ARGV, &l) - - l = ->(*a, k: 1) do a.length end - assert_equal OVER_STACK_LEN, yield_block(:a, *OVER_STACK_ARGV, &l) - - l = ->(*a, **kw) do a.length end - assert_equal OVER_STACK_LEN, yield_block(:a, *OVER_STACK_ARGV, &l) - - l = ->(*a, k: 1, **kw) do a.length end - assert_equal OVER_STACK_LEN, yield_block(:a, *OVER_STACK_ARGV, &l) - - l = ->(b=1, *a, k: 1) do a.length end - assert_equal (OVER_STACK_LEN - 1), yield_block(:a, *OVER_STACK_ARGV, &l) - - l = ->(b=1, *a, **kw) do a.length end - assert_equal (OVER_STACK_LEN - 1), yield_block(:a, *OVER_STACK_ARGV, &l) - - l = ->(b=1, *a, k: 1, **kw) do a.length end - assert_equal (OVER_STACK_LEN - 1), yield_block(:a, *OVER_STACK_ARGV, &l) - - l = ->(b=1, *a, _, k: 1) do a.length end - assert_equal (OVER_STACK_LEN - 2), yield_block(:a, *OVER_STACK_ARGV, &l) - - l = ->(b=1, *a, _, **kw) do a.length end - assert_equal (OVER_STACK_LEN - 2), yield_block(:a, *OVER_STACK_ARGV, &l) - - l = ->(b=1, *a, _, k: 1, **kw) do a.length end - assert_equal (OVER_STACK_LEN - 2), yield_block(:a, *OVER_STACK_ARGV, &l) - end end diff --git a/test/ruby/test_class.rb b/test/ruby/test_class.rb index a8a019cee2..07c34ce9d5 100644 --- a/test/ruby/test_class.rb +++ b/test/ruby/test_class.rb @@ -96,13 +96,6 @@ class TestClass < Test::Unit::TestCase def test_superclass_of_basicobject assert_equal(nil, BasicObject.superclass) - - assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") - begin; - module Mod end - BasicObject.include(Mod) - assert_equal(nil, BasicObject.superclass) - end; end def test_module_function @@ -362,17 +355,6 @@ class TestClass < Test::Unit::TestCase assert_equal(42, PrivateClass.new.foo) end - def test_private_const_access - assert_raise_with_message NameError, /uninitialized/ do - begin - eval('class ::TestClass::PrivateClass; end') - rescue NameError - end - - Object.const_get "NOT_AVAILABLE_CONST_NAME_#{__LINE__}" - end - end - StrClone = String.clone Class.new(StrClone) @@ -777,31 +759,6 @@ class TestClass < Test::Unit::TestCase end end - def test_attached_object - c = Class.new - sc = c.singleton_class - obj = c.new - - assert_equal(obj, obj.singleton_class.attached_object) - assert_equal(c, sc.attached_object) - - assert_raise_with_message(TypeError, /is not a singleton class/) do - c.attached_object - end - - assert_raise_with_message(TypeError, /`NilClass' is not a singleton class/) do - nil.singleton_class.attached_object - end - - assert_raise_with_message(TypeError, /`FalseClass' is not a singleton class/) do - false.singleton_class.attached_object - end - - assert_raise_with_message(TypeError, /`TrueClass' is not a singleton class/) do - true.singleton_class.attached_object - end - end - def test_subclass_gc c = Class.new 10_000.times do @@ -827,13 +784,4 @@ PREP 3_000_000.times(&code) CODE end - - def test_instance_freeze_dont_freeze_the_class_bug_19164 - klass = Class.new - klass.prepend(Module.new) - - klass.new.freeze - klass.define_method(:bar) {} - assert_equal klass, klass.remove_method(:bar), '[Bug #19164]' - end end diff --git a/test/ruby/test_clone.rb b/test/ruby/test_clone.rb index 216eaa39d2..321feb07c7 100644 --- a/test/ruby/test_clone.rb +++ b/test/ruby/test_clone.rb @@ -27,52 +27,6 @@ class TestClone < Test::Unit::TestCase assert_equal([M003, M002, M001], M003.ancestors) end - def test_frozen_properties_retained_on_clone - obj = Object.new.freeze - cloned_obj = obj.clone - - assert_predicate(obj, :frozen?) - assert_predicate(cloned_obj, :frozen?) - end - - def test_ivar_retained_on_clone - obj = Object.new - obj.instance_variable_set(:@a, 1) - cloned_obj = obj.clone - - assert_equal(obj.instance_variable_get(:@a), 1) - assert_equal(cloned_obj.instance_variable_get(:@a), 1) - end - - def test_ivars_retained_on_extended_obj_clone - ivars = { :@a => 1, :@b => 2, :@c => 3, :@d => 4 } - obj = Object.new - ivars.each do |ivar_name, val| - obj.instance_variable_set(ivar_name, val) - end - - cloned_obj = obj.clone - - ivars.each do |ivar_name, val| - assert_equal(obj.instance_variable_get(ivar_name), val) - assert_equal(cloned_obj.instance_variable_get(ivar_name), val) - end - end - - def test_frozen_properties_and_ivars_retained_on_clone_with_ivar - obj = Object.new - obj.instance_variable_set(:@a, 1) - obj.freeze - - cloned_obj = obj.clone - - assert_predicate(obj, :frozen?) - assert_equal(obj.instance_variable_get(:@a), 1) - - assert_predicate(cloned_obj, :frozen?) - assert_equal(cloned_obj.instance_variable_get(:@a), 1) - end - def test_user_flags assert_separately([], <<-EOS) # diff --git a/test/ruby/test_comparable.rb b/test/ruby/test_comparable.rb index 4a90d443bf..b849217b7d 100644 --- a/test/ruby/test_comparable.rb +++ b/test/ruby/test_comparable.rb @@ -85,7 +85,7 @@ class TestComparable < Test::Unit::TestCase assert_equal(1, @o.clamp(1, 1)) assert_equal(@o, @o.clamp(0, 0)) - assert_raise_with_message(ArgumentError, 'min argument must be less than or equal to max argument') { + assert_raise_with_message(ArgumentError, 'min argument must be smaller than max argument') { @o.clamp(2, 1) } end @@ -115,7 +115,7 @@ class TestComparable < Test::Unit::TestCase assert_raise_with_message(*exc) {@o.clamp(-1...0)} assert_raise_with_message(*exc) {@o.clamp(...2)} - assert_raise_with_message(ArgumentError, 'min argument must be less than or equal to max argument') { + assert_raise_with_message(ArgumentError, 'min argument must be smaller than max argument') { @o.clamp(2..1) } end diff --git a/test/ruby/test_complex.rb b/test/ruby/test_complex.rb index edbdffd069..a3a7546575 100644 --- a/test/ruby/test_complex.rb +++ b/test/ruby/test_complex.rb @@ -221,16 +221,10 @@ class Complex_Test < Test::Unit::TestCase assert_equal([1,2], Complex.polar(1,2).polar) assert_equal(Complex.polar(1.0, Math::PI * 2 / 3), Complex.polar(1, Math::PI * 2 / 3)) - one = 1+0i - c = Complex.polar(0, one) - assert_equal(0, c) - assert_predicate(c.real, :real?) - c = Complex.polar(one, 0) - assert_equal(1, c) - assert_predicate(c.real, :real?) - c = Complex.polar(one) - assert_equal(1, c) - assert_predicate(c.real, :real?) + assert_in_out_err([], <<-'end;', ['OK'], []) + Complex.polar(1, Complex(1, 0)) + puts :OK + end; end def test_uplus @@ -573,24 +567,20 @@ class Complex_Test < Test::Unit::TestCase assert_raise_with_message(TypeError, /C\u{1f5ff}/) { Complex(1).coerce(obj) } end - class ObjectX < Numeric - def initialize(real = true, n = 1) @n = n; @real = real; end - def +(x) Rational(@n) end + class ObjectX + def +(x) Rational(1) end alias - + alias * + alias / + alias quo + alias ** + - def coerce(x) [x, Complex(@n)] end - def real?; @real; end + def coerce(x) [x, Complex(1)] end end def test_coerce2 x = ObjectX.new - y = ObjectX.new(false) - %w(+ - * / quo ** <=>).each do |op| - assert_kind_of(Numeric, Complex(1).__send__(op, x), op) - assert_kind_of(Numeric, Complex(1).__send__(op, y), op) + %w(+ - * / quo **).each do |op| + assert_kind_of(Numeric, Complex(1).__send__(op, x)) end end @@ -853,42 +843,20 @@ class Complex_Test < Test::Unit::TestCase assert_equal(Complex(0), '_5'.to_c) assert_equal(Complex(5), '5_'.to_c) assert_equal(Complex(5), '5x'.to_c) - assert_equal(Complex(51), '5_1'.to_c) - assert_equal(Complex(5), '5__1'.to_c) assert_equal(Complex(5), '5+_3i'.to_c) assert_equal(Complex(5), '5+3_i'.to_c) assert_equal(Complex(5,3), '5+3i_'.to_c) assert_equal(Complex(5,3), '5+3ix'.to_c) - assert_equal(Complex(5,31), '5+3_1i'.to_c) - assert_equal(Complex(5), '5+3__1i'.to_c) - assert_equal(Complex(51), Complex('5_1')) - assert_equal(Complex(5,31), Complex('5+3_1i')) - assert_equal(Complex(5,31), Complex('5+3_1I')) - assert_equal(Complex(5,31), Complex('5+3_1j')) - assert_equal(Complex(5,31), Complex('5+3_1J')) - assert_equal(Complex(0,31), Complex('3_1i')) - assert_equal(Complex(0,31), Complex('3_1I')) - assert_equal(Complex(0,31), Complex('3_1j')) - assert_equal(Complex(0,31), Complex('3_1J')) assert_raise(ArgumentError){ Complex('')} assert_raise(ArgumentError){ Complex('_')} assert_raise(ArgumentError){ Complex("\f\n\r\t\v5\0")} assert_raise(ArgumentError){ Complex('_5')} assert_raise(ArgumentError){ Complex('5_')} - assert_raise(ArgumentError){ Complex('5__1')} assert_raise(ArgumentError){ Complex('5x')} assert_raise(ArgumentError){ Complex('5+_3i')} assert_raise(ArgumentError){ Complex('5+3_i')} assert_raise(ArgumentError){ Complex('5+3i_')} assert_raise(ArgumentError){ Complex('5+3ix')} - assert_raise(ArgumentError){ Complex('5+3__1i')} - assert_raise(ArgumentError){ Complex('5+3__1I')} - assert_raise(ArgumentError){ Complex('5+3__1j')} - assert_raise(ArgumentError){ Complex('5+3__1J')} - assert_raise(ArgumentError){ Complex('3__1i')} - assert_raise(ArgumentError){ Complex('3__1I')} - assert_raise(ArgumentError){ Complex('3__1j')} - assert_raise(ArgumentError){ Complex('3__1J')} assert_equal(Complex(Rational(1,5)), '1/5'.to_c) assert_equal(Complex(Rational(-1,5)), '-1/5'.to_c) @@ -1167,34 +1135,15 @@ class Complex_Test < Test::Unit::TestCase end def test_canonicalize_polar - error = "not a real" - assert_raise_with_message(TypeError, error) do - Complex.polar(1i) - end - assert_raise_with_message(TypeError, error) do - Complex.polar(1i, 0) - end - assert_raise_with_message(TypeError, error) do - Complex.polar(0, 1i) - end - n = Class.new(Numeric) do - def initialize(x = 1) - @x = x + obj = Class.new(Numeric) do + def initialize + @x = 2 end def real? (@x -= 1) > 0 end - end - obj = n.new - assert_raise_with_message(TypeError, error) do - Complex.polar(obj) - end - obj = n.new - assert_raise_with_message(TypeError, error) do - Complex.polar(obj, 0) - end - obj = n.new - assert_raise_with_message(TypeError, error) do + end.new + assert_raise(TypeError) do Complex.polar(1, obj) end end diff --git a/test/ruby/test_complex2.rb b/test/ruby/test_complex2.rb index b89e83efb2..594fc3f45a 100644 --- a/test/ruby/test_complex2.rb +++ b/test/ruby/test_complex2.rb @@ -4,7 +4,7 @@ require 'test/unit' class Complex_Test2 < Test::Unit::TestCase def test_kumi - omit unless defined?(Rational) + skip unless defined?(Rational) assert_equal(Complex(1, 0), +Complex(1, 0)) assert_equal(Complex(-1, 0), -Complex(1, 0)) diff --git a/test/ruby/test_complexrational.rb b/test/ruby/test_complexrational.rb index 31d11fe317..bf4e2b1809 100644 --- a/test/ruby/test_complexrational.rb +++ b/test/ruby/test_complexrational.rb @@ -4,7 +4,7 @@ require 'test/unit' class ComplexRational_Test < Test::Unit::TestCase def test_rat_srat - omit unless defined?(Rational) + skip unless defined?(Rational) c = SimpleRat(1,3) cc = Rational(3,2) @@ -89,7 +89,7 @@ class ComplexRational_Test < Test::Unit::TestCase end def test_comp_srat - omit unless defined?(Rational) + skip unless defined?(Rational) c = Complex(SimpleRat(2,3),SimpleRat(1,2)) cc = Complex(Rational(3,2),Rational(2,1)) diff --git a/test/ruby/test_data.rb b/test/ruby/test_data.rb deleted file mode 100644 index b911776bde..0000000000 --- a/test/ruby/test_data.rb +++ /dev/null @@ -1,266 +0,0 @@ -# -*- coding: us-ascii -*- -# frozen_string_literal: false -require 'test/unit' -require 'timeout' - -class TestData < Test::Unit::TestCase - def test_define - klass = Data.define(:foo, :bar) - assert_kind_of(Class, klass) - assert_equal(%i[foo bar], klass.members) - - assert_raise(NoMethodError) { Data.new(:foo) } - assert_raise(TypeError) { Data.define(0) } - - # Because some code is shared with Struct, check we don't share unnecessary functionality - assert_raise(TypeError) { Data.define(:foo, keyword_init: true) } - - assert_not_respond_to(Data.define, :define, "Cannot define from defined Data class") - end - - def test_define_edge_cases - # non-ascii - klass = Data.define(:"r\u{e9}sum\u{e9}") - o = klass.new(1) - assert_equal(1, o.send(:"r\u{e9}sum\u{e9}")) - - # junk string - klass = Data.define(:"a\000") - o = klass.new(1) - assert_equal(1, o.send(:"a\000")) - - # special characters in attribute names - klass = Data.define(:a, :b?) - x = Object.new - o = klass.new("test", x) - assert_same(x, o.b?) - - klass = Data.define(:a, :b!) - x = Object.new - o = klass.new("test", x) - assert_same(x, o.b!) - - assert_raise(ArgumentError) { Data.define(:x=) } - assert_raise(ArgumentError, /duplicate member/) { Data.define(:x, :x) } - end - - def test_define_with_block - klass = Data.define(:a, :b) do - def c - a + b - end - end - - assert_equal(3, klass.new(1, 2).c) - end - - def test_initialize - klass = Data.define(:foo, :bar) - - # Regular - test = klass.new(1, 2) - assert_equal(1, test.foo) - assert_equal(2, test.bar) - assert_equal(test, klass.new(1, 2)) - assert_predicate(test, :frozen?) - - # Keywords - test_kw = klass.new(foo: 1, bar: 2) - assert_equal(1, test_kw.foo) - assert_equal(2, test_kw.bar) - assert_equal(test_kw, klass.new(foo: 1, bar: 2)) - assert_equal(test_kw, test) - - # Wrong protocol - assert_raise(ArgumentError) { klass.new(1) } - assert_raise(ArgumentError) { klass.new(1, 2, 3) } - assert_raise(ArgumentError) { klass.new(foo: 1) } - assert_raise(ArgumentError) { klass.new(foo: 1, bar: 2, baz: 3) } - # Could be converted to foo: 1, bar: 2, but too smart is confusing - assert_raise(ArgumentError) { klass.new(1, bar: 2) } - end - - def test_initialize_redefine - klass = Data.define(:foo, :bar) do - attr_reader :passed - - def initialize(*args, **kwargs) - @passed = [args, kwargs] - super(foo: 1, bar: 2) # so we can experiment with passing wrong numbers of args - end - end - - assert_equal([[], {foo: 1, bar: 2}], klass.new(foo: 1, bar: 2).passed) - - # Positional arguments are converted to keyword ones - assert_equal([[], {foo: 1, bar: 2}], klass.new(1, 2).passed) - - # Missing arguments can be fixed in initialize - assert_equal([[], {foo: 1}], klass.new(foo: 1).passed) - assert_equal([[], {foo: 42}], klass.new(42).passed) - - # Extra keyword arguments can be dropped in initialize - assert_equal([[], {foo: 1, bar: 2, baz: 3}], klass.new(foo: 1, bar: 2, baz: 3).passed) - end - - def test_instance_behavior - klass = Data.define(:foo, :bar) - - test = klass.new(1, 2) - assert_equal(1, test.foo) - assert_equal(2, test.bar) - assert_equal(%i[foo bar], test.members) - assert_equal(1, test.public_send(:foo)) - assert_equal(0, test.method(:foo).arity) - assert_equal([], test.method(:foo).parameters) - - assert_equal({foo: 1, bar: 2}, test.to_h) - assert_equal({"foo"=>"1", "bar"=>"2"}, test.to_h { [_1.to_s, _2.to_s] }) - - assert_equal({foo: 1, bar: 2}, test.deconstruct_keys(nil)) - assert_equal({foo: 1}, test.deconstruct_keys(%i[foo])) - assert_equal({foo: 1}, test.deconstruct_keys(%i[foo baz])) - assert_raise(TypeError) { test.deconstruct_keys(0) } - - assert_kind_of(Integer, test.hash) - end - - def test_inspect - klass = Data.define(:a) - o = klass.new(1) - assert_equal("#<data a=1>", o.inspect) - - Object.const_set(:Foo, klass) - assert_equal("#<data Foo a=1>", o.inspect) - Object.instance_eval { remove_const(:Foo) } - - klass = Data.define(:@a) - o = klass.new(1) - assert_equal("#<data :@a=1>", o.inspect) - end - - def test_equal - klass1 = Data.define(:a) - klass2 = Data.define(:a) - o1 = klass1.new(1) - o2 = klass1.new(1) - o3 = klass2.new(1) - assert_equal(o1, o2) - assert_not_equal(o1, o3) - end - - def test_eql - klass1 = Data.define(:a) - klass2 = Data.define(:a) - o1 = klass1.new(1) - o2 = klass1.new(1) - o3 = klass2.new(1) - assert_operator(o1, :eql?, o2) - assert_not_operator(o1, :eql?, o3) - end - - def test_with - klass = Data.define(:foo, :bar) - source = klass.new(foo: 1, bar: 2) - - # Simple - test = source.with - assert_equal(source.object_id, test.object_id) - - # Changes - test = source.with(foo: 10) - - assert_equal(1, source.foo) - assert_equal(2, source.bar) - assert_equal(source, klass.new(foo: 1, bar: 2)) - - assert_equal(10, test.foo) - assert_equal(2, test.bar) - assert_equal(test, klass.new(foo: 10, bar: 2)) - - test = source.with(foo: 10, bar: 20) - - assert_equal(1, source.foo) - assert_equal(2, source.bar) - assert_equal(source, klass.new(foo: 1, bar: 2)) - - assert_equal(10, test.foo) - assert_equal(20, test.bar) - assert_equal(test, klass.new(foo: 10, bar: 20)) - - # Keyword splat - changes = { foo: 10, bar: 20 } - test = source.with(**changes) - - assert_equal(1, source.foo) - assert_equal(2, source.bar) - assert_equal(source, klass.new(foo: 1, bar: 2)) - - assert_equal(10, test.foo) - assert_equal(20, test.bar) - assert_equal(test, klass.new(foo: 10, bar: 20)) - - # Wrong protocol - assert_raise_with_message(ArgumentError, "wrong number of arguments (given 1, expected 0)") do - source.with(10) - end - assert_raise_with_message(ArgumentError, "unknown keywords: :baz, :quux") do - source.with(foo: 1, bar: 2, baz: 3, quux: 4) - end - assert_raise_with_message(ArgumentError, "wrong number of arguments (given 1, expected 0)") do - source.with(1, bar: 2) - end - assert_raise_with_message(ArgumentError, "wrong number of arguments (given 2, expected 0)") do - source.with(1, 2) - end - assert_raise_with_message(ArgumentError, "wrong number of arguments (given 1, expected 0)") do - source.with({ bar: 2 }) - end - end - - def test_with_initialize - oddclass = Data.define(:odd) do - def initialize(odd:) - raise ArgumentError, "Not odd" unless odd.odd? - super(odd: odd) - end - end - assert_raise_with_message(ArgumentError, "Not odd") { - oddclass.new(odd: 0) - } - odd = oddclass.new(odd: 1) - assert_raise_with_message(ArgumentError, "Not odd") { - odd.with(odd: 2) - } - end - - def test_memberless - klass = Data.define - - test = klass.new - - assert_equal(klass.new, test) - assert_not_equal(Data.define.new, test) - - assert_equal('#<data >', test.inspect) - assert_equal([], test.members) - assert_equal({}, test.to_h) - end - - def test_dup - klass = Data.define(:foo, :bar) - test = klass.new(foo: 1, bar: 2) - assert_equal(klass.new(foo: 1, bar: 2), test.dup) - assert_predicate(test.dup, :frozen?) - end - - Klass = Data.define(:foo, :bar) - - def test_marshal - test = Klass.new(foo: 1, bar: 2) - loaded = Marshal.load(Marshal.dump(test)) - assert_equal(test, loaded) - assert_not_same(test, loaded) - assert_predicate(loaded, :frozen?) - end -end diff --git a/test/ruby/test_default_gems.rb b/test/ruby/test_default_gems.rb index d8e8226253..3c4aea1561 100644 --- a/test/ruby/test_default_gems.rb +++ b/test/ruby/test_default_gems.rb @@ -2,26 +2,15 @@ require 'rubygems' class TestDefaultGems < Test::Unit::TestCase - def self.load(file) - code = File.read(file, mode: "r:UTF-8:-", &:read) - - # - `git ls-files` is useless under ruby's repository - # - `2>/dev/null` works only on Unix-like platforms - code.gsub!(/`git.*?`/, '""') - - eval(code, binding, file) - end def test_validate_gemspec + skip "git not found" unless system("git", "rev-parse", %i[out err]=>IO::NULL) srcdir = File.expand_path('../../..', __FILE__) - specs = 0 - Dir.chdir(srcdir) do - all_assertions_foreach(nil, *Dir["{lib,ext}/**/*.gemspec"]) do |src| - specs += 1 - assert_kind_of(Gem::Specification, self.class.load(src), "invalid spec in #{src}") + Dir.glob("#{srcdir}/{lib,ext}/**/*.gemspec").map do |src| + assert_nothing_raised do + raise("invalid spec in #{src}") unless Gem::Specification.load(src) end end - assert_operator specs, :>, 0, "gemspecs not found" end end diff --git a/test/ruby/test_defined.rb b/test/ruby/test_defined.rb index b9bf939394..3324a09afe 100644 --- a/test/ruby/test_defined.rb +++ b/test/ruby/test_defined.rb @@ -303,20 +303,6 @@ class TestDefined < Test::Unit::TestCase assert_equal("super", o.x, bug8367) end - def test_super_in_basic_object - BasicObject.class_eval do - def a - defined?(super) - end - end - - assert_nil(a) - ensure - BasicObject.class_eval do - undef_method :a if defined?(a) - end - end - def test_super_toplevel assert_separately([], "assert_nil(defined?(super))") end diff --git a/test/ruby/test_dir.rb b/test/ruby/test_dir.rb index 65803d0bc5..39a1dae889 100644 --- a/test/ruby/test_dir.rb +++ b/test/ruby/test_dir.rb @@ -19,21 +19,11 @@ class TestDir < Test::Unit::TestCase @dirs << File.join(i, "") end end - @envs = nil end def teardown $VERBOSE = @verbose FileUtils.remove_entry_secure @root if File.directory?(@root) - ENV.update(@envs) if @envs - end - - def setup_envs(envs = %w"HOME LOGDIR") - @envs ||= {} - envs.each do |e, v| - @envs[e] = ENV.delete(e) - ENV[e] = v if v - end end def test_seek @@ -96,9 +86,12 @@ class TestDir < Test::Unit::TestCase d.close end - def test_class_chdir + def test_chdir pwd = Dir.pwd - setup_envs + env_home = ENV["HOME"] + env_logdir = ENV["LOGDIR"] + ENV.delete("HOME") + ENV.delete("LOGDIR") assert_raise(Errno::ENOENT) { Dir.chdir(@nodir) } assert_raise(ArgumentError) { Dir.chdir } @@ -132,45 +125,8 @@ class TestDir < Test::Unit::TestCase rescue abort("cannot return the original directory: #{ pwd }") end - end - - def test_instance_chdir - pwd = Dir.pwd - dir = Dir.new(pwd) - root_dir = Dir.new(@root) - setup_envs - - ENV["HOME"] = pwd - root_dir.chdir do - assert_warning(/conflicting chdir during another chdir block/) { dir.chdir } - assert_warning(/conflicting chdir during another chdir block/) { root_dir.chdir } - - assert_equal(@root, Dir.pwd) - - assert_raise(RuntimeError) { Thread.new { Thread.current.report_on_exception = false; dir.chdir }.join } - assert_raise(RuntimeError) { Thread.new { Thread.current.report_on_exception = false; dir.chdir{} }.join } - - assert_warning(/conflicting chdir during another chdir block/) { dir.chdir } - assert_equal(pwd, Dir.pwd) - - assert_warning(/conflicting chdir during another chdir block/) { root_dir.chdir } - assert_equal(@root, Dir.pwd) - - assert_warning(/conflicting chdir during another chdir block/) { dir.chdir } - - root_dir.chdir do - assert_equal(@root, Dir.pwd) - end - assert_equal(pwd, Dir.pwd) - end - ensure - begin - dir.chdir - rescue - abort("cannot return the original directory: #{ pwd }") - end - dir.close - root_dir.close + ENV["HOME"] = env_home + ENV["LOGDIR"] = env_logdir end def test_chdir_conflict @@ -196,7 +152,7 @@ class TestDir < Test::Unit::TestCase end def test_chroot_nodir - omit if RUBY_PLATFORM =~ /android/ + skip if RUBY_PLATFORM =~ /android/ assert_raise(NotImplementedError, Errno::ENOENT, Errno::EPERM ) { Dir.chroot(File.join(@nodir, "")) } end @@ -548,9 +504,9 @@ class TestDir < Test::Unit::TestCase def test_glob_legacy_short_name bug10819 = '[ruby-core:67954] [Bug #10819]' bug11206 = '[ruby-core:69435] [Bug #11206]' - omit unless /\A\w:/ =~ ENV["ProgramFiles"] + skip unless /\A\w:/ =~ ENV["ProgramFiles"] short = "#$&/PROGRA~1" - omit unless File.directory?(short) + skip unless File.directory?(short) entries = Dir.glob("#{short}/Common*") assert_not_empty(entries, bug10819) long = File.expand_path(short) @@ -560,28 +516,13 @@ class TestDir < Test::Unit::TestCase assert_include(Dir.glob(wild, File::FNM_SHORTNAME), long, bug10819) assert_empty(entries - Dir.glob("#{wild}/Common*", File::FNM_SHORTNAME), bug10819) end - - def test_home_windows - setup_envs(%w[HOME USERPROFILE HOMEDRIVE HOMEPATH]) - - ENV['HOME'] = "C:\\ruby\\home" - assert_equal("C:/ruby/home", Dir.home) - - ENV['USERPROFILE'] = "C:\\ruby\\userprofile" - assert_equal("C:/ruby/home", Dir.home) - ENV.delete('HOME') - assert_equal("C:/ruby/userprofile", Dir.home) - - ENV['HOMEDRIVE'] = "C:" - ENV['HOMEPATH'] = "\\ruby\\homepath" - assert_equal("C:/ruby/userprofile", Dir.home) - ENV.delete('USERPROFILE') - assert_equal("C:/ruby/homepath", Dir.home) - end end def test_home - setup_envs + env_home = ENV["HOME"] + env_logdir = ENV["LOGDIR"] + ENV.delete("HOME") + ENV.delete("LOGDIR") ENV["HOME"] = @nodir assert_nothing_raised(ArgumentError) do @@ -599,16 +540,9 @@ class TestDir < Test::Unit::TestCase %W[no:such:user \u{7559 5b88}:\u{756a}].each do |user| assert_raise_with_message(ArgumentError, /#{user}/) {Dir.home(user)} end - end - - if Encoding.find("filesystem") == Encoding::UTF_8 - # On Windows and macOS, file system encoding is always UTF-8. - def test_home_utf8 - setup_envs - - ENV["HOME"] = "/\u{e4}~\u{1f3e0}" - assert_equal("/\u{e4}~\u{1f3e0}", Dir.home) - end + ensure + ENV["HOME"] = env_home + ENV["LOGDIR"] = env_logdir end def test_symlinks_not_resolved @@ -639,21 +573,6 @@ class TestDir < Test::Unit::TestCase } end - def test_for_fd - if Dir.respond_to? :for_fd - begin - new_dir = Dir.new('..') - for_fd_dir = Dir.for_fd(new_dir.fileno) - assert_equal(new_dir.chdir{Dir.pwd}, for_fd_dir.chdir{Dir.pwd}) - ensure - new_dir&.close - for_fd_dir&.close - end - else - assert_raise(NotImplementedError) { Dir.for_fd(0) } - end - end - def test_empty? assert_not_send([Dir, :empty?, @root]) a = File.join(@root, "a") diff --git a/test/ruby/test_dup.rb b/test/ruby/test_dup.rb deleted file mode 100644 index 75c4fc0339..0000000000 --- a/test/ruby/test_dup.rb +++ /dev/null @@ -1,110 +0,0 @@ -# frozen_string_literal: false -require 'test/unit' - -class TestDup < Test::Unit::TestCase - module M001; end - module M002; end - module M003; include M002; end - module M002; include M001; end - module M003; include M002; end - - def test_dup - foo = Object.new - def foo.test - "test" - end - bar = foo.dup - def bar.test2 - "test2" - end - - assert_equal("test2", bar.test2) - assert_raise(NoMethodError) { bar.test } - assert_equal("test", foo.test) - - assert_raise(NoMethodError) {foo.test2} - - assert_equal([M003, M002, M001], M003.ancestors) - end - - def test_frozen_properties_not_retained_on_dup - obj = Object.new.freeze - duped_obj = obj.dup - - assert_predicate(obj, :frozen?) - refute_predicate(duped_obj, :frozen?) - end - - def test_ivar_retained_on_dup - obj = Object.new - obj.instance_variable_set(:@a, 1) - duped_obj = obj.dup - - assert_equal(obj.instance_variable_get(:@a), 1) - assert_equal(duped_obj.instance_variable_get(:@a), 1) - end - - def test_ivars_retained_on_extended_obj_dup - ivars = { :@a => 1, :@b => 2, :@c => 3, :@d => 4 } - obj = Object.new - ivars.each do |ivar_name, val| - obj.instance_variable_set(ivar_name, val) - end - - duped_obj = obj.dup - - ivars.each do |ivar_name, val| - assert_equal(obj.instance_variable_get(ivar_name), val) - assert_equal(duped_obj.instance_variable_get(ivar_name), val) - end - end - - def test_frozen_properties_not_retained_on_dup_with_ivar - obj = Object.new - obj.instance_variable_set(:@a, 1) - obj.freeze - - duped_obj = obj.dup - - assert_predicate(obj, :frozen?) - assert_equal(obj.instance_variable_get(:@a), 1) - - refute_predicate(duped_obj, :frozen?) - assert_equal(duped_obj.instance_variable_get(:@a), 1) - end - - def test_user_flags - assert_separately([], <<-EOS) - # - class Array - undef initialize_copy - def initialize_copy(*); end - end - x = [1, 2, 3].dup - assert_equal [], x, '[Bug #14847]' - EOS - - assert_separately([], <<-EOS) - # - class Array - undef initialize_copy - def initialize_copy(*); end - end - x = [1,2,3,4,5,6,7][1..-2].dup - x.push(1,1,1,1,1) - assert_equal [1, 1, 1, 1, 1], x, '[Bug #14847]' - EOS - - assert_separately([], <<-EOS) - # - class Hash - undef initialize_copy - def initialize_copy(*); end - end - h = {} - h.default_proc = proc { raise } - h = h.dup - assert_equal nil, h[:not_exist], '[Bug #14847]' - EOS - end -end diff --git a/test/ruby/test_econv.rb b/test/ruby/test_econv.rb index 1d0641e918..1aad0de347 100644 --- a/test/ruby/test_econv.rb +++ b/test/ruby/test_econv.rb @@ -931,7 +931,7 @@ class TestEncodingConverter < Test::Unit::TestCase def test_default_external Encoding.list.grep(->(enc) {/\AISO-8859-\d+\z/i =~ enc.name}) do |enc| - assert_separately(%W[-d - #{enc.name}], <<-EOS, ignore_stderr: true) + assert_separately(%W[--disable=gems -d - #{enc.name}], <<-EOS, ignore_stderr: true) Encoding.default_external = ext = ARGV[0] Encoding.default_internal = int ='utf-8' assert_nothing_raised do diff --git a/test/ruby/test_encoding.rb b/test/ruby/test_encoding.rb index f2c609a4cd..4a6dd932ed 100644 --- a/test/ruby/test_encoding.rb +++ b/test/ruby/test_encoding.rb @@ -55,6 +55,39 @@ class TestEncoding < Test::Unit::TestCase assert_raise(TypeError, bug5150) {Encoding.find(1)} end + def test_replicate + assert_separately([], "#{<<~'END;'}") + assert_instance_of(Encoding, Encoding::UTF_8.replicate("UTF-8-ANOTHER#{Time.now.to_f}")) + assert_instance_of(Encoding, Encoding::ISO_2022_JP.replicate("ISO-2022-JP-ANOTHER#{Time.now.to_f}")) + bug3127 = '[ruby-dev:40954]' + assert_raise(TypeError, bug3127) {Encoding::UTF_8.replicate(0)} + assert_raise_with_message(ArgumentError, /\bNUL\b/, bug3127) {Encoding::UTF_8.replicate("\0")} + END; + end + + def test_extra_encoding + assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") + begin; + 200.times {|i| + Encoding::UTF_8.replicate("dummy#{i}") + } + e = Encoding.list.last + format = "%d".force_encoding(e) + assert_equal("0", format % 0) + assert_equal(e, format.dup.encoding) + assert_equal(e, (format*1).encoding) + + assert_equal(e, (("x"*30).force_encoding(e)*1).encoding) + GC.start + + name = "A" * 64 + Encoding.list.each do |enc| + assert_raise(ArgumentError) {enc.replicate(name)} + name.succ! + end + end; + end + def test_dummy_p assert_equal(true, Encoding::ISO_2022_JP.dummy?) assert_equal(false, Encoding::UTF_8.dummy?) @@ -106,7 +139,7 @@ class TestEncoding < Test::Unit::TestCase end def test_errinfo_after_autoload - assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") + assert_separately(%w[--disable=gems], "#{<<~"begin;"}\n#{<<~'end;'}") bug9038 = '[ruby-core:57949] [Bug #9038]' begin; e = assert_raise_with_message(SyntaxError, /unknown regexp option - Q/, bug9038) { diff --git a/test/ruby/test_enum.rb b/test/ruby/test_enum.rb index f7c8f012d8..b0c43b9a7f 100644 --- a/test/ruby/test_enum.rb +++ b/test/ruby/test_enum.rb @@ -234,8 +234,6 @@ class TestEnumerable < Test::Unit::TestCase assert_equal(24, @obj.inject(2) {|z, x| z * x }) assert_equal(24, assert_warning(/given block not used/) {@obj.inject(2, :*) {|z, x| z * x }}) assert_equal(nil, @empty.inject() {9}) - - assert_raise(ArgumentError) {@obj.inject} end FIXNUM_MIN = RbConfig::LIMITS['FIXNUM_MIN'] @@ -1334,16 +1332,4 @@ class TestEnumerable < Test::Unit::TestCase assert_equal([], @obj.filter_map { nil }) assert_instance_of(Enumerator, @obj.filter_map) end - - def test_ruby_svar - klass = Class.new do - include Enumerable - def each - %w(bar baz).each{|e| yield e} - end - end - svars = [] - klass.new.grep(/(b.)/) { svars << $1 } - assert_equal(["ba", "ba"], svars) - end end diff --git a/test/ruby/test_enumerator.rb b/test/ruby/test_enumerator.rb index bbaa91b703..c823b79c6d 100644 --- a/test/ruby/test_enumerator.rb +++ b/test/ruby/test_enumerator.rb @@ -244,26 +244,6 @@ class TestEnumerator < Test::Unit::TestCase assert_equal(res, exc.result) end - def test_stopiteration_rescue - e = [1].each - res = e.each {} - e.next - exc0 = assert_raise(StopIteration) { e.peek } - assert_include(exc0.backtrace.first, "test_enumerator.rb:#{__LINE__-1}:") - assert_nil(exc0.cause) - assert_equal(res, exc0.result) - - exc1 = assert_raise(StopIteration) { e.next } - assert_include(exc1.backtrace.first, "test_enumerator.rb:#{__LINE__-1}:") - assert_same(exc0, exc1.cause) - assert_equal(res, exc1.result) - - exc2 = assert_raise(StopIteration) { e.next } - assert_include(exc2.backtrace.first, "test_enumerator.rb:#{__LINE__-1}:") - assert_same(exc0, exc2.cause) - assert_equal(res, exc2.result) - end - def test_next_values o = Object.new def o.each @@ -926,86 +906,4 @@ class TestEnumerator < Test::Unit::TestCase e.chain.each(&->{}) assert_equal(true, e.is_lambda) end - - def test_product - ## - ## Enumerator::Product - ## - - # 0-dimensional - e = Enumerator::Product.new - assert_instance_of(Enumerator::Product, e) - assert_kind_of(Enumerator, e) - assert_equal(1, e.size) - elts = [] - e.each { |x| elts << x } - assert_equal [[]], elts - assert_equal elts, e.to_a - heads = [] - e.each { |x,| heads << x } - assert_equal [nil], heads - - # 1-dimensional - e = Enumerator::Product.new(1..3) - assert_instance_of(Enumerator::Product, e) - assert_kind_of(Enumerator, e) - assert_equal(3, e.size) - elts = [] - e.each { |x| elts << x } - assert_equal [[1], [2], [3]], elts - assert_equal elts, e.to_a - - # 2-dimensional - e = Enumerator::Product.new(1..3, %w[a b]) - assert_instance_of(Enumerator::Product, e) - assert_kind_of(Enumerator, e) - assert_equal(3 * 2, e.size) - elts = [] - e.each { |x| elts << x } - assert_equal [[1, "a"], [1, "b"], [2, "a"], [2, "b"], [3, "a"], [3, "b"]], elts - assert_equal elts, e.to_a - heads = [] - e.each { |x,| heads << x } - assert_equal [1, 1, 2, 2, 3, 3], heads - - # Reject keyword arguments - assert_raise(ArgumentError) { - Enumerator::Product.new(1..3, foo: 1, bar: 2) - } - - ## - ## Enumerator.product - ## - - # without a block - e = Enumerator.product(1..3, %w[a b]) - assert_instance_of(Enumerator::Product, e) - - # with a block - elts = [] - ret = Enumerator.product(1..3) { |x| elts << x } - assert_equal(nil, ret) - assert_equal [[1], [2], [3]], elts - assert_equal elts, Enumerator.product(1..3).to_a - - # an infinite enumerator and a finite enumerable - e = Enumerator.product(1.., 'a'..'c') - assert_equal(Float::INFINITY, e.size) - assert_equal [[1, "a"], [1, "b"], [1, "c"], [2, "a"]], e.take(4) - - # an infinite enumerator and an unknown enumerator - e = Enumerator.product(1.., Enumerator.new { |y| y << 'a' << 'b' }) - assert_equal(Float::INFINITY, e.size) - assert_equal [[1, "a"], [1, "b"], [2, "a"], [2, "b"]], e.take(4) - - # an infinite enumerator and an unknown enumerator - e = Enumerator.product(1..3, Enumerator.new { |y| y << 'a' << 'b' }) - assert_equal(nil, e.size) - assert_equal [[1, "a"], [1, "b"], [2, "a"], [2, "b"]], e.take(4) - - # Reject keyword arguments - assert_raise(ArgumentError) { - Enumerator.product(1..3, foo: 1, bar: 2) - } - end end diff --git a/test/ruby/test_env.rb b/test/ruby/test_env.rb index cdadeac148..87ccd5102b 100644 --- a/test/ruby/test_env.rb +++ b/test/ruby/test_env.rb @@ -69,20 +69,25 @@ class TestEnv < Test::Unit::TestCase end def test_clone - message = /Cannot clone ENV/ - assert_raise_with_message(TypeError, message) { + warning = /ENV\.clone is deprecated; use ENV\.to_h instead/ + clone = assert_deprecated_warning(warning) { ENV.clone } - assert_raise_with_message(TypeError, message) { + assert_same(ENV, clone) + + clone = assert_deprecated_warning(warning) { ENV.clone(freeze: false) } - assert_raise_with_message(TypeError, message) { + assert_same(ENV, clone) + + clone = assert_deprecated_warning(warning) { ENV.clone(freeze: nil) } - assert_raise_with_message(TypeError, message) { + assert_same(ENV, clone) + + assert_raise(TypeError) { ENV.clone(freeze: true) } - assert_raise(ArgumentError) { ENV.clone(freeze: 1) } @@ -489,20 +494,12 @@ class TestEnv < Test::Unit::TestCase ENV["baz"] = "qux" ENV.update({"baz"=>"quux","a"=>"b"}) check(ENV.to_hash.to_a, [%w(foo bar), %w(baz quux), %w(a b)]) - ENV.update - check(ENV.to_hash.to_a, [%w(foo bar), %w(baz quux), %w(a b)]) - ENV.update({"foo"=>"zot"}, {"c"=>"d"}) - check(ENV.to_hash.to_a, [%w(foo zot), %w(baz quux), %w(a b), %w(c d)]) ENV.clear ENV["foo"] = "bar" ENV["baz"] = "qux" ENV.update({"baz"=>"quux","a"=>"b"}) {|k, v1, v2| k + "_" + v1 + "_" + v2 } check(ENV.to_hash.to_a, [%w(foo bar), %w(baz baz_qux_quux), %w(a b)]) - ENV.update {|k, v1, v2| k + "_" + v1 + "_" + v2 } - check(ENV.to_hash.to_a, [%w(foo bar), %w(baz baz_qux_quux), %w(a b)]) - ENV.update({"foo"=>"zot"}, {"c"=>"d"}) {|k, v1, v2| k + "_" + v1 + "_" + v2 } - check(ENV.to_hash.to_a, [%w(foo foo_bar_zot), %w(baz baz_qux_quux), %w(a b), %w(c d)]) end def test_huge_value @@ -683,6 +680,37 @@ class TestEnv < Test::Unit::TestCase end; end + def test_clone_in_ractor + assert_ractor(<<-"end;") + r = Ractor.new do + original_warning_state = Warning[:deprecated] + Warning[:deprecated] = false + + begin + Ractor.yield ENV.clone.object_id + Ractor.yield ENV.clone(freeze: false).object_id + Ractor.yield ENV.clone(freeze: nil).object_id + + #{str_for_yielding_exception_class("ENV.clone(freeze: true)")} + #{str_for_yielding_exception_class("ENV.clone(freeze: 1)")} + #{str_for_yielding_exception_class("ENV.clone(foo: false)")} + #{str_for_yielding_exception_class("ENV.clone(1)")} + #{str_for_yielding_exception_class("ENV.clone(1, foo: false)")} + + ensure + Warning[:deprecated] = original_warning_state + end + end + assert_equal(ENV.object_id, r.take) + assert_equal(ENV.object_id, r.take) + assert_equal(ENV.object_id, r.take) + #{str_for_assert_raise_on_yielded_exception_class(TypeError, "r")} + 4.times do + #{str_for_assert_raise_on_yielded_exception_class(ArgumentError, "r")} + end + end; + end + def test_has_value_in_ractor assert_ractor(<<-"end;") r = Ractor.new do diff --git a/test/ruby/test_eval.rb b/test/ruby/test_eval.rb index 082d1dc03c..d55977c986 100644 --- a/test/ruby/test_eval.rb +++ b/test/ruby/test_eval.rb @@ -488,9 +488,6 @@ class TestEval < Test::Unit::TestCase end end assert_equal(feature6609, feature6609_method) - ensure - Object.undef_method(:feature6609_block) rescue nil - Object.undef_method(:feature6609_method) rescue nil end def test_eval_using_integer_as_binding @@ -547,8 +544,8 @@ class TestEval < Test::Unit::TestCase end def test_eval_location_binding - assert_equal(["(eval at #{__FILE__}:#{__LINE__})", 1], eval("[__FILE__, __LINE__]", nil)) - assert_equal(["(eval at #{__FILE__}:#{__LINE__})", 1], eval("[__FILE__, __LINE__]", binding)) + assert_equal(['(eval)', 1], eval("[__FILE__, __LINE__]", nil)) + assert_equal(['(eval)', 1], eval("[__FILE__, __LINE__]", binding)) assert_equal(['foo', 1], eval("[__FILE__, __LINE__]", nil, 'foo')) assert_equal(['foo', 1], eval("[__FILE__, __LINE__]", binding, 'foo')) assert_equal(['foo', 2], eval("[__FILE__, __LINE__]", nil, 'foo', 2)) diff --git a/test/ruby/test_exception.rb b/test/ruby/test_exception.rb index 07b39d1217..ffca877f1e 100644 --- a/test/ruby/test_exception.rb +++ b/test/ruby/test_exception.rb @@ -265,7 +265,7 @@ class TestException < Test::Unit::TestCase v = assert_throw(:extdep, bug18562) do require t.path - rescue rescue_all + rescue rescue_all => e assert(false, "should not reach here") end @@ -444,7 +444,7 @@ class TestException < Test::Unit::TestCase end def test_thread_signal_location - # pend('TODO: a known bug [Bug #14474]') + skip _, stderr, _ = EnvUtil.invoke_ruby(%w"--disable-gems -d", <<-RUBY, false, true) Thread.start do Thread.current.report_on_exception = false @@ -478,12 +478,6 @@ end.join def to_s; ""; end end assert_equal(e.inspect, e.new.inspect) - - # https://bugs.ruby-lang.org/issues/18170#note-13 - assert_equal('#<Exception:"foo\nbar">', Exception.new("foo\nbar").inspect) - assert_equal('#<Exception: foo bar>', Exception.new("foo bar").inspect) - assert_equal('#<Exception: foo\bar>', Exception.new("foo\\bar").inspect) - assert_equal('#<Exception: "foo\nbar">', Exception.new('"foo\nbar"').inspect) end def test_to_s @@ -588,7 +582,7 @@ end.join end def test_ensure_after_nomemoryerror - omit "Forcing NoMemoryError causes problems in some environments" + skip "Forcing NoMemoryError causes problems in some environments" assert_separately([], "$_ = 'a' * 1_000_000_000_000_000_000") rescue NoMemoryError assert_raise(NoMemoryError) do @@ -685,7 +679,7 @@ end.join def test_machine_stackoverflow bug9109 = '[ruby-dev:47804] [Bug #9109]' - assert_separately([], <<-SRC) + assert_separately(%w[--disable-gem], <<-SRC) assert_raise(SystemStackError, #{bug9109.dump}) { h = {a: ->{h[:a].call}} h[:a].call @@ -696,7 +690,7 @@ end.join def test_machine_stackoverflow_by_define_method bug9454 = '[ruby-core:60113] [Bug #9454]' - assert_separately([], <<-SRC) + assert_separately(%w[--disable-gem], <<-SRC) assert_raise(SystemStackError, #{bug9454.dump}) { define_method(:foo) {self.foo} self.foo @@ -813,7 +807,6 @@ end.join cause = ArgumentError.new("foobar") e = assert_raise(RuntimeError) {raise msg, cause: cause} assert_same(cause, e.cause) - assert_raise(TypeError) {raise msg, {cause: cause}} end def test_cause_with_no_arguments @@ -998,12 +991,11 @@ $stderr = $stdout; raise "\x82\xa0"') do |outs, errs, status| end assert_not_nil(e) assert_include(e.message, "\0") - # Disabled by [Feature #18367] - #assert_in_out_err([], src, [], [], *args, **opts) do |_, err,| - # err.each do |e| - # assert_not_include(e, "\0") - # end - #end + assert_in_out_err([], src, [], [], *args, **opts) do |_, err,| + err.each do |e| + assert_not_include(e, "\0") + end + end e end @@ -1059,7 +1051,7 @@ $stderr = $stdout; raise "\x82\xa0"') do |outs, errs, status| warning << [str, category] end else - define_method(:warn) do |str, category: nil| + define_method(:warn) do |str| warning << str end end @@ -1093,17 +1085,25 @@ $stderr = $stdout; raise "\x82\xa0"') do |outs, errs, status| end def test_warn_deprecated_backwards_compatibility_category - omit "no method to test" - - warning = capture_warning_warn { } + warning = capture_warning_warn { Dir.exists?("non-existent") } assert_match(/deprecated/, warning[0]) end def test_warn_deprecated_category - omit "no method to test" + warning = capture_warning_warn(category: true) { Dir.exists?("non-existent") } + + assert_equal :deprecated, warning[0][1] + end + + def test_warn_deprecated_to_remove_backwards_compatibility_category + warning = capture_warning_warn { Object.new.tainted? } + + assert_match(/deprecated/, warning[0]) + end - warning = capture_warning_warn(category: true) { } + def test_warn_deprecated_to_remove_category + warning = capture_warning_warn(category: true) { Object.new.tainted? } assert_equal :deprecated, warning[0][1] end @@ -1266,7 +1266,7 @@ $stderr = $stdout; raise "\x82\xa0"') do |outs, errs, status| begin; class Bug < RuntimeError def backtrace - File.readlines(IO::NULL) + IO.readlines(IO::NULL) end end bug = Bug.new '[ruby-core:85939] [Bug #14577]' @@ -1310,7 +1310,7 @@ $stderr = $stdout; raise "\x82\xa0"') do |outs, errs, status| def test_backtrace_in_eval bug = '[ruby-core:84434] [Bug #14229]' - assert_in_out_err(['-e', 'eval("raise")'], "", [], /^\(eval at .*\):1:/, bug) + assert_in_out_err(['-e', 'eval("raise")'], "", [], /^\(eval\):1:/, bug) end def test_full_message @@ -1440,99 +1440,4 @@ $stderr = $stdout; raise "\x82\xa0"') do |outs, errs, status| end end; end - - def test_detailed_message - e = RuntimeError.new("message") - assert_equal("message (RuntimeError)", e.detailed_message) - assert_equal("\e[1mmessage (\e[1;4mRuntimeError\e[m\e[1m)\e[m", e.detailed_message(highlight: true)) - - e = RuntimeError.new("foo\nbar\nbaz") - assert_equal("foo (RuntimeError)\nbar\nbaz", e.detailed_message) - assert_equal("\e[1mfoo (\e[1;4mRuntimeError\e[m\e[1m)\e[m\n\e[1mbar\e[m\n\e[1mbaz\e[m", e.detailed_message(highlight: true)) - - e = RuntimeError.new("") - assert_equal("unhandled exception", e.detailed_message) - assert_equal("\e[1;4munhandled exception\e[m", e.detailed_message(highlight: true)) - - e = RuntimeError.new - assert_equal("RuntimeError (RuntimeError)", e.detailed_message) - assert_equal("\e[1mRuntimeError (\e[1;4mRuntimeError\e[m\e[1m)\e[m", e.detailed_message(highlight: true)) - end - - def test_full_message_with_custom_detailed_message - e = RuntimeError.new("message") - opt_ = nil - e.define_singleton_method(:detailed_message) do |**opt| - opt_ = opt - "BOO!" - end - assert_match("BOO!", e.full_message.lines.first) - assert_equal({ highlight: Exception.to_tty? }, opt_) - end - - def test_full_message_with_encoding - message = "\u{dc}bersicht" - begin - begin - raise message - rescue => e - raise "\n#{e.message}" - end - rescue => e - end - assert_include(e.full_message, message) - end - - def test_syntax_error_detailed_message - Dir.mktmpdir do |dir| - File.write(File.join(dir, "detail.rb"), "#{<<~"begin;"}\n#{<<~'end;'}") - begin; - class SyntaxError - def detailed_message(**) - Thread.new {}.join - "<#{super}>\n""<#{File.basename(__FILE__)}>" - rescue ThreadError => e - e.message - end - end - end; - pattern = /^<detail\.rb>/ - assert_in_out_err(%W[-r#{dir}/detail -], "1+", [], pattern) - - File.write(File.join(dir, "main.rb"), "#{<<~"begin;"}\n#{<<~'end;'}") - begin; - 1 + - end; - assert_in_out_err(%W[-r#{dir}/detail #{dir}/main.rb]) do |stdout, stderr,| - assert_empty(stdout) - assert_not_empty(stderr.grep(pattern)) - error, = stderr.grep(/unexpected end-of-input/) - assert_not_nil(error) - assert_match(/<.*unexpected end-of-input.*>/, error) - end - end - end - - def test_syntax_error_path - e = assert_raise(SyntaxError) { - eval("1+", nil, "test_syntax_error_path.rb") - } - assert_equal("test_syntax_error_path.rb", e.path) - - Dir.mktmpdir do |dir| - lib = File.join(dir, "syntax_error-path.rb") - File.write(lib, "#{<<~"begin;"}\n#{<<~'end;'}") - begin; - class SyntaxError - def detailed_message(**) - STDERR.puts "\n""path=#{path}\n" - super - end - end - end; - main = File.join(dir, "syntax_error.rb") - File.write(main, "1+\n") - assert_in_out_err(%W[-r#{lib} #{main}], "", [], [:*, "\n""path=#{main}\n", :*]) - end - end end diff --git a/test/ruby/test_fiber.rb b/test/ruby/test_fiber.rb index cb6e846bc6..e4b7322bd9 100644 --- a/test/ruby/test_fiber.rb +++ b/test/ruby/test_fiber.rb @@ -34,7 +34,7 @@ class TestFiber < Test::Unit::TestCase end def test_many_fibers - omit 'This is unstable on GitHub Actions --jit-wait. TODO: debug it' if defined?(RubyVM::RJIT) && RubyVM::RJIT.enabled? + skip 'This is unstable on GitHub Actions --jit-wait. TODO: debug it' if defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? max = 1000 assert_equal(max, max.times{ Fiber.new{} @@ -381,7 +381,7 @@ class TestFiber < Test::Unit::TestCase def test_fork_from_fiber - omit 'fork not supported' unless Process.respond_to?(:fork) + skip 'fork not supported' unless Process.respond_to?(:fork) pid = nil bug5700 = '[ruby-core:41456]' assert_nothing_raised(bug5700) do diff --git a/test/ruby/test_file.rb b/test/ruby/test_file.rb index 409d21fc4e..d570b6f6fb 100644 --- a/test/ruby/test_file.rb +++ b/test/ruby/test_file.rb @@ -273,7 +273,7 @@ class TestFile < Test::Unit::TestCase begin File.symlink(tst, a) rescue Errno::EACCES, Errno::EPERM - omit "need privilege" + skip "need privilege" end assert_equal(File.join(realdir, tst), File.realpath(a)) File.unlink(a) @@ -317,7 +317,7 @@ class TestFile < Test::Unit::TestCase Dir.mktmpdir('rubytest-realpath') {|tmpdir| Dir.chdir(tmpdir) do Dir.mkdir('foo') - omit "cannot run mklink" unless system('mklink /j bar foo > nul') + skip "cannot run mklink" unless system('mklink /j bar foo > nul') assert_equal(File.realpath('foo'), File.realpath('bar')) end } @@ -460,48 +460,6 @@ class TestFile < Test::Unit::TestCase end end - def test_file_open_newline_option - Dir.mktmpdir(__method__.to_s) do |tmpdir| - path = File.join(tmpdir, "foo") - test = lambda do |newline| - File.open(path, "wt", newline: newline) do |f| - f.write "a\n" - f.puts "b" - end - File.binread(path) - end - assert_equal("a\nb\n", test.(:lf)) - assert_equal("a\nb\n", test.(:universal)) - assert_equal("a\r\nb\r\n", test.(:crlf)) - assert_equal("a\rb\r", test.(:cr)) - - test = lambda do |newline| - File.open(path, "rt", newline: newline) do |f| - f.read - end - end - - File.binwrite(path, "a\nb\n") - assert_equal("a\nb\n", test.(:lf)) - assert_equal("a\nb\n", test.(:universal)) - assert_equal("a\nb\n", test.(:crlf)) - assert_equal("a\nb\n", test.(:cr)) - - File.binwrite(path, "a\r\nb\r\n") - assert_equal("a\r\nb\r\n", test.(:lf)) - assert_equal("a\nb\n", test.(:universal)) - # Work on both Windows and non-Windows - assert_include(["a\r\nb\r\n", "a\nb\n"], test.(:crlf)) - assert_equal("a\r\nb\r\n", test.(:cr)) - - File.binwrite(path, "a\rb\r") - assert_equal("a\rb\r", test.(:lf)) - assert_equal("a\nb\n", test.(:universal)) - assert_equal("a\rb\r", test.(:crlf)) - assert_equal("a\rb\r", test.(:cr)) - end - end - def test_open_nul Dir.mktmpdir(__method__.to_s) do |tmpdir| path = File.join(tmpdir, "foo") @@ -517,17 +475,17 @@ class TestFile < Test::Unit::TestCase begin io = File.open(tmpdir, File::RDWR | File::TMPFILE) rescue Errno::EINVAL - omit 'O_TMPFILE not supported (EINVAL)' + skip 'O_TMPFILE not supported (EINVAL)' rescue Errno::EISDIR - omit 'O_TMPFILE not supported (EISDIR)' + skip 'O_TMPFILE not supported (EISDIR)' rescue Errno::EOPNOTSUPP - omit 'O_TMPFILE not supported (EOPNOTSUPP)' + skip 'O_TMPFILE not supported (EOPNOTSUPP)' end io.write "foo" io.flush assert_equal 3, io.size - assert_nil io.path + assert_raise(IOError) { io.path } ensure io&.close end diff --git a/test/ruby/test_file_exhaustive.rb b/test/ruby/test_file_exhaustive.rb index fbb18f07f9..a960ef0d74 100644 --- a/test/ruby/test_file_exhaustive.rb +++ b/test/ruby/test_file_exhaustive.rb @@ -638,7 +638,7 @@ class TestFileExhaustive < Test::Unit::TestCase end def test_birthtime - omit if RUBY_PLATFORM =~ /android/ + skip if RUBY_PLATFORM =~ /android/ [regular_file, utf8_file].each do |file| t1 = File.birthtime(file) t2 = File.open(file) {|f| f.birthtime} @@ -649,7 +649,7 @@ class TestFileExhaustive < Test::Unit::TestCase # ignore unsupporting filesystems rescue Errno::EPERM # Docker prohibits statx syscall by the default. - omit("statx(2) is prohibited by seccomp") + skip("statx(2) is prohibited by seccomp") end assert_raise(Errno::ENOENT) { File.birthtime(nofile) } end if File.respond_to?(:birthtime) @@ -771,7 +771,7 @@ class TestFileExhaustive < Test::Unit::TestCase def test_readlink_junction base = File.basename(nofile) err = IO.popen(%W"cmd.exe /c mklink /j #{base} .", chdir: @dir, err: %i[child out], &:read) - omit err unless $?.success? + skip err unless $?.success? assert_equal(@dir, File.readlink(nofile)) end @@ -870,10 +870,9 @@ class TestFileExhaustive < Test::Unit::TestCase bug9934 = '[ruby-core:63114] [Bug #9934]' require "objspace" path = File.expand_path("/foo") - assert_operator(ObjectSpace.memsize_of(path), :<=, path.bytesize + GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE], bug9934) + assert_operator(ObjectSpace.memsize_of(path), :<=, path.bytesize + GC::INTERNAL_CONSTANTS[:RVALUE_SIZE], bug9934) path = File.expand_path("/a"*25) - assert_operator(ObjectSpace.memsize_of(path), :<=, - (path.bytesize + 1) * 2 + GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE], bug9934) + assert_equal(path.bytesize+1 + GC::INTERNAL_CONSTANTS[:RVALUE_SIZE], ObjectSpace.memsize_of(path), bug9934) end def test_expand_path_encoding @@ -1118,7 +1117,7 @@ class TestFileExhaustive < Test::Unit::TestCase def test_expand_path_for_existent_username user = ENV['USER'] - omit "ENV['USER'] is not set" unless user + skip "ENV['USER'] is not set" unless user assert_equal(ENV['HOME'], File.expand_path("~#{user}")) end unless DRIVE @@ -1407,8 +1406,6 @@ class TestFileExhaustive < Test::Unit::TestCase end def test_flock_exclusive - omit "[Bug #18613]" if /freebsd/ =~ RUBY_PLATFORM - timeout = EnvUtil.apply_timeout_scale(0.1).to_s File.open(regular_file, "r+") do |f| f.flock(File::LOCK_EX) @@ -1438,8 +1435,6 @@ class TestFileExhaustive < Test::Unit::TestCase end def test_flock_shared - omit "[Bug #18613]" if /freebsd/ =~ RUBY_PLATFORM - timeout = EnvUtil.apply_timeout_scale(0.1).to_s File.open(regular_file, "r+") do |f| f.flock(File::LOCK_SH) @@ -1517,32 +1512,29 @@ class TestFileExhaustive < Test::Unit::TestCase assert_equal(File.zero?(f), test(?z, f), f) stat = File.stat(f) - unless stat.chardev? - # null device may be accessed by other processes - assert_equal(stat.atime, File.atime(f), f) - assert_equal(stat.ctime, File.ctime(f), f) - assert_equal(stat.mtime, File.mtime(f), f) - end - assert_bool_equal(stat.blockdev?, File.blockdev?(f), f) - assert_bool_equal(stat.chardev?, File.chardev?(f), f) - assert_bool_equal(stat.directory?, File.directory?(f), f) - assert_bool_equal(stat.file?, File.file?(f), f) - assert_bool_equal(stat.setgid?, File.setgid?(f), f) - assert_bool_equal(stat.grpowned?, File.grpowned?(f), f) - assert_bool_equal(stat.sticky?, File.sticky?(f), f) - assert_bool_equal(File.lstat(f).symlink?, File.symlink?(f), f) - assert_bool_equal(stat.owned?, File.owned?(f), f) - assert_bool_equal(stat.pipe?, File.pipe?(f), f) - assert_bool_equal(stat.readable?, File.readable?(f), f) - assert_bool_equal(stat.readable_real?, File.readable_real?(f), f) + assert_equal(stat.atime, File.atime(f), f) + assert_equal(stat.ctime, File.ctime(f), f) + assert_equal(stat.mtime, File.mtime(f), f) + assert_equal(stat.blockdev?, File.blockdev?(f), f) + assert_equal(stat.chardev?, File.chardev?(f), f) + assert_equal(stat.directory?, File.directory?(f), f) + assert_equal(stat.file?, File.file?(f), f) + assert_equal(stat.setgid?, File.setgid?(f), f) + assert_equal(stat.grpowned?, File.grpowned?(f), f) + assert_equal(stat.sticky?, File.sticky?(f), f) + assert_equal(File.lstat(f).symlink?, File.symlink?(f), f) + assert_equal(stat.owned?, File.owned?(f), f) + assert_equal(stat.pipe?, File.pipe?(f), f) + assert_equal(stat.readable?, File.readable?(f), f) + assert_equal(stat.readable_real?, File.readable_real?(f), f) assert_equal(stat.size?, File.size?(f), f) - assert_bool_equal(stat.socket?, File.socket?(f), f) - assert_bool_equal(stat.setuid?, File.setuid?(f), f) - assert_bool_equal(stat.writable?, File.writable?(f), f) - assert_bool_equal(stat.writable_real?, File.writable_real?(f), f) - assert_bool_equal(stat.executable?, File.executable?(f), f) - assert_bool_equal(stat.executable_real?, File.executable_real?(f), f) - assert_bool_equal(stat.zero?, File.zero?(f), f) + assert_equal(stat.socket?, File.socket?(f), f) + assert_equal(stat.setuid?, File.setuid?(f), f) + assert_equal(stat.writable?, File.writable?(f), f) + assert_equal(stat.writable_real?, File.writable_real?(f), f) + assert_equal(stat.executable?, File.executable?(f), f) + assert_equal(stat.executable_real?, File.executable_real?(f), f) + assert_equal(stat.zero?, File.zero?(f), f) end assert_equal(false, test(?-, @dir, fn1)) assert_equal(true, test(?-, fn1, fn1)) @@ -1795,8 +1787,4 @@ class TestFileExhaustive < Test::Unit::TestCase dir = File.expand_path("/bar") assert_equal(File.join(dir, "~foo"), File.absolute_path("~foo", dir)) end - - def assert_bool_equal(expected, result, *messages) - assert_equal(expected, true & result, *messages) - end end diff --git a/test/ruby/test_float.rb b/test/ruby/test_float.rb index b91b904d1e..57a46fce92 100644 --- a/test/ruby/test_float.rb +++ b/test/ruby/test_float.rb @@ -141,9 +141,6 @@ class TestFloat < Test::Unit::TestCase assert_raise(ArgumentError){Float("1__1")} assert_raise(ArgumentError){Float("1.")} assert_raise(ArgumentError){Float("1.e+00")} - assert_raise(ArgumentError){Float("0x.1")} - assert_raise(ArgumentError){Float("0x1.")} - assert_raise(ArgumentError){Float("0x1.0")} assert_raise(ArgumentError){Float("0x1.p+0")} # add expected behaviour here. assert_equal(10, Float("1_0")) @@ -227,12 +224,6 @@ class TestFloat < Test::Unit::TestCase assert_equal(-3.5, (-11.5).remainder(-4)) assert_predicate(Float::NAN.remainder(4), :nan?) assert_predicate(4.remainder(Float::NAN), :nan?) - - ten = Object.new - def ten.coerce(other) - [other, 10] - end - assert_equal(4, 14.0.remainder(ten)) end def test_to_s @@ -492,17 +483,6 @@ class TestFloat < Test::Unit::TestCase assert_equal(-1.26, -1.255.round(2)) end - def test_round_half_even_with_precision - assert_equal(767573.18759, 767573.1875850001.round(5, half: :even)) - assert_equal(767573.18758, 767573.187585.round(5, half: :even)) - assert_equal(767573.18758, 767573.1875849998.round(5, half: :even)) - assert_equal(767573.18758, 767573.187575.round(5, half: :even)) - assert_equal(-767573.18759, -767573.1875850001.round(5, half: :even)) - assert_equal(-767573.18758, -767573.187585.round(5, half: :even)) - assert_equal(-767573.18758, -767573.1875849998.round(5, half: :even)) - assert_equal(-767573.18758, -767573.187575.round(5, half: :even)) - end - def test_floor_with_precision assert_equal(+0.0, +0.001.floor(1)) assert_equal(-0.1, -0.001.floor(1)) diff --git a/test/ruby/test_frozen.rb b/test/ruby/test_frozen.rb deleted file mode 100644 index 2918a2afd8..0000000000 --- a/test/ruby/test_frozen.rb +++ /dev/null @@ -1,30 +0,0 @@ -# frozen_string_literal: false -require 'test/unit' - -class TestFrozen < Test::Unit::TestCase - def test_setting_ivar_on_frozen_obj - obj = Object.new - obj.freeze - assert_raise(FrozenError) { obj.instance_variable_set(:@a, 1) } - end - - def test_setting_ivar_on_frozen_obj_with_ivars - obj = Object.new - obj.instance_variable_set(:@a, 1) - obj.freeze - assert_raise(FrozenError) { obj.instance_variable_set(:@b, 1) } - end - - def test_setting_ivar_on_frozen_string - str = "str" - str.freeze - assert_raise(FrozenError) { str.instance_variable_set(:@a, 1) } - end - - def test_setting_ivar_on_frozen_string_with_ivars - str = "str" - str.instance_variable_set(:@a, 1) - str.freeze - assert_raise(FrozenError) { str.instance_variable_set(:@b, 1) } - end -end diff --git a/test/ruby/test_gc.rb b/test/ruby/test_gc.rb index 567e7b5d80..fa81bcb1ad 100644 --- a/test/ruby/test_gc.rb +++ b/test/ruby/test_gc.rb @@ -54,7 +54,7 @@ class TestGc < Test::Unit::TestCase def test_start_full_mark return unless use_rgengc? - omit 'stress' if GC.stress + skip 'stress' if GC.stress 3.times { GC.start } # full mark and next time it should be minor mark GC.start(full_mark: false) @@ -65,7 +65,7 @@ class TestGc < Test::Unit::TestCase end def test_start_immediate_sweep - omit 'stress' if GC.stress + skip 'stress' if GC.stress GC.start(immediate_sweep: false) assert_equal false, GC.latest_gc_info(:immediate_sweep) @@ -117,7 +117,7 @@ class TestGc < Test::Unit::TestCase end def test_stat_single - omit 'stress' if GC.stress + skip 'stress' if GC.stress stat = GC.stat assert_equal stat[:count], GC.stat(:count) @@ -125,11 +125,9 @@ class TestGc < Test::Unit::TestCase end def test_stat_constraints - omit 'stress' if GC.stress + skip 'stress' if GC.stress stat = GC.stat - # marking_time + sweeping_time could differ from time by 1 because they're stored in nanoseconds - assert_in_delta stat[:time], stat[:marking_time] + stat[:sweeping_time], 1 assert_equal stat[:total_allocated_pages], stat[:heap_allocated_pages] + stat[:total_freed_pages] assert_operator stat[:heap_sorted_length], :>=, stat[:heap_eden_pages] + stat[:heap_allocatable_pages], "stat is: " + stat.inspect assert_equal stat[:heap_available_slots], stat[:heap_live_slots] + stat[:heap_free_slots] + stat[:heap_final_slots] @@ -141,99 +139,15 @@ class TestGc < Test::Unit::TestCase end end - def test_stat_heap - omit 'stress' if GC.stress - - stat_heap = {} - stat = {} - # Initialize to prevent GC in future calls - GC.stat_heap(0, stat_heap) - GC.stat(stat) - - GC::INTERNAL_CONSTANTS[:SIZE_POOL_COUNT].times do |i| - GC.stat_heap(i, stat_heap) - GC.stat(stat) - - assert_equal GC::INTERNAL_CONSTANTS[:RVALUE_SIZE] * (2**i), stat_heap[:slot_size] - assert_operator stat_heap[:heap_allocatable_pages], :<=, stat[:heap_allocatable_pages] - assert_operator stat_heap[:heap_eden_pages], :<=, stat[:heap_eden_pages] - assert_operator stat_heap[:heap_eden_slots], :>=, 0 - assert_operator stat_heap[:heap_tomb_pages], :<=, stat[:heap_tomb_pages] - assert_operator stat_heap[:heap_tomb_slots], :>=, 0 - assert_operator stat_heap[:total_allocated_pages], :>=, 0 - assert_operator stat_heap[:total_freed_pages], :>=, 0 - assert_operator stat_heap[:force_major_gc_count], :>=, 0 - assert_operator stat_heap[:force_incremental_marking_finish_count], :>=, 0 - assert_operator stat_heap[:total_allocated_objects], :>=, 0 - assert_operator stat_heap[:total_freed_objects], :>=, 0 - assert_operator stat_heap[:total_freed_objects], :<=, stat_heap[:total_allocated_objects] - end - - GC.stat_heap(0, stat_heap) - assert_equal stat_heap[:slot_size], GC.stat_heap(0, :slot_size) - assert_equal stat_heap[:slot_size], GC.stat_heap(0)[:slot_size] - - assert_raise(ArgumentError) { GC.stat_heap(-1) } - assert_raise(ArgumentError) { GC.stat_heap(GC::INTERNAL_CONSTANTS[:SIZE_POOL_COUNT]) } - end - - def test_stat_heap_all - stat_heap_all = {} - stat_heap = {} - - 2.times do - GC.stat_heap(0, stat_heap) - GC.stat_heap(nil, stat_heap_all) - end - - GC::INTERNAL_CONSTANTS[:SIZE_POOL_COUNT].times do |i| - GC.stat_heap(i, stat_heap) - - # Remove keys that can vary between invocations - %i(total_allocated_objects).each do |sym| - stat_heap[sym] = stat_heap_all[i][sym] = 0 - end - - assert_equal stat_heap, stat_heap_all[i] - end - - assert_raise(TypeError) { GC.stat_heap(nil, :slot_size) } - end - - def test_stat_heap_constraints - omit 'stress' if GC.stress - - stat = GC.stat - stat_heap = GC.stat_heap - 2.times do - GC.stat(stat) - GC.stat_heap(nil, stat_heap) - end - - stat_heap_sum = Hash.new(0) - stat_heap.values.each do |hash| - hash.each { |k, v| stat_heap_sum[k] += v } - end - - assert_equal stat[:heap_allocatable_pages], stat_heap_sum[:heap_allocatable_pages] - assert_equal stat[:heap_eden_pages], stat_heap_sum[:heap_eden_pages] - assert_equal stat[:heap_tomb_pages], stat_heap_sum[:heap_tomb_pages] - assert_equal stat[:heap_available_slots], stat_heap_sum[:heap_eden_slots] + stat_heap_sum[:heap_tomb_slots] - assert_equal stat[:total_allocated_pages], stat_heap_sum[:total_allocated_pages] - assert_equal stat[:total_freed_pages], stat_heap_sum[:total_freed_pages] - assert_equal stat[:total_allocated_objects], stat_heap_sum[:total_allocated_objects] - assert_equal stat[:total_freed_objects], stat_heap_sum[:total_freed_objects] - end - def test_latest_gc_info - omit 'stress' if GC.stress + skip 'stress' if GC.stress - assert_separately([], __FILE__, __LINE__, <<-'RUBY') - GC.start - count = GC.stat(:heap_free_slots) + GC.stat(:heap_allocatable_pages) * GC::INTERNAL_CONSTANTS[:HEAP_PAGE_OBJ_LIMIT] - count.times{ "a" + "b" } - assert_equal :newobj, GC.latest_gc_info[:gc_by] - RUBY + assert_separately %w[--disable-gem], __FILE__, __LINE__, <<-'eom' + GC.start + count = GC.stat(:heap_free_slots) + GC.stat(:heap_allocatable_pages) * GC::INTERNAL_CONSTANTS[:HEAP_PAGE_OBJ_LIMIT] + count.times{ "a" + "b" } + assert_equal :newobj, GC.latest_gc_info[:gc_by] + eom GC.latest_gc_info(h = {}) # allocate hash and rehearsal GC.start @@ -244,7 +158,6 @@ class TestGc < Test::Unit::TestCase assert_equal :force, h[:major_by] if use_rgengc? assert_equal :method, h[:gc_by] assert_equal true, h[:immediate_sweep] - assert_equal true, h.key?(:need_major_by) GC.stress = true assert_equal :force, GC.latest_gc_info[:major_by] @@ -262,81 +175,8 @@ class TestGc < Test::Unit::TestCase assert_raise_with_message(ArgumentError, /\u{30eb 30d3 30fc}/) {GC.latest_gc_info(:"\u{30eb 30d3 30fc}")} end - def test_latest_gc_info_need_major_by - return unless use_rgengc? - omit 'stress' if GC.stress - - 3.times { GC.start } - assert_nil GC.latest_gc_info(:need_major_by) - - # allocate objects until need_major_by is set or major GC happens - objects = [] - while GC.latest_gc_info(:need_major_by).nil? - objects.append(100.times.map { '*' }) - end - - # We need to ensure that no GC gets ran before the call to GC.start since - # it would trigger a major GC. Assertions could allocate objects and - # trigger a GC so we don't run assertions until we perform the major GC. - need_major_by = GC.latest_gc_info(:need_major_by) - GC.start(full_mark: false) # should be upgraded to major - major_by = GC.latest_gc_info(:major_by) - - assert_not_nil(need_major_by) - assert_not_nil(major_by) - end - - def test_latest_gc_info_weak_references_count - assert_separately([], __FILE__, __LINE__, <<~RUBY) - count = 10_000 - # Some weak references may be created, so allow some margin of error - error_tolerance = 100 - - # Run full GC to clear out weak references - GC.start - # Run full GC again to collect stats about weak references - GC.start - - before_weak_references_count = GC.latest_gc_info(:weak_references_count) - before_retained_weak_references_count = GC.latest_gc_info(:retained_weak_references_count) - - # Create some objects and place it in a WeakMap - wmap = ObjectSpace::WeakMap.new - ary = Array.new(count) - enum = count.times - enum.each.with_index do |i| - obj = Object.new - ary[i] = obj - wmap[obj] = nil - end - - # Run full GC to collect stats about weak references - GC.start - - assert_operator(GC.latest_gc_info(:weak_references_count), :>=, before_weak_references_count + count - error_tolerance) - assert_operator(GC.latest_gc_info(:retained_weak_references_count), :>=, before_retained_weak_references_count + count - error_tolerance) - assert_operator(GC.latest_gc_info(:retained_weak_references_count), :<=, GC.latest_gc_info(:weak_references_count)) - - before_weak_references_count = GC.latest_gc_info(:weak_references_count) - before_retained_weak_references_count = GC.latest_gc_info(:retained_weak_references_count) - - ary = nil - - # Free ary, which should empty out the wmap - GC.start - # Run full GC again to collect stats about weak references - GC.start - - assert_equal(0, wmap.size) - - assert_operator(GC.latest_gc_info(:weak_references_count), :<=, before_weak_references_count - count + error_tolerance) - assert_operator(GC.latest_gc_info(:retained_weak_references_count), :<=, before_retained_weak_references_count - count + error_tolerance) - assert_operator(GC.latest_gc_info(:retained_weak_references_count), :<=, GC.latest_gc_info(:weak_references_count)) - RUBY - end - def test_stress_compile_send - assert_in_out_err([], <<-EOS, [], [], "") + assert_in_out_err(%w[--disable-gems], <<-EOS, [], [], "") GC.stress = true begin eval("A::B.c(1, 1, d: 234)") @@ -346,7 +186,7 @@ class TestGc < Test::Unit::TestCase end def test_singleton_method - assert_in_out_err([], <<-EOS, [], [], "[ruby-dev:42832]") + assert_in_out_err(%w[--disable-gems], <<-EOS, [], [], "[ruby-dev:42832]") GC.stress = true 10.times do obj = Object.new @@ -358,7 +198,7 @@ class TestGc < Test::Unit::TestCase end def test_singleton_method_added - assert_in_out_err([], <<-EOS, [], [], "[ruby-dev:44436]") + assert_in_out_err(%w[--disable-gems], <<-EOS, [], [], "[ruby-dev:44436]") class BasicObject undef singleton_method_added def singleton_method_added(mid) @@ -376,21 +216,22 @@ class TestGc < Test::Unit::TestCase env = { "RUBY_GC_HEAP_INIT_SLOTS" => "100" } - assert_in_out_err([env, "-W0", "-e", "exit"], "", [], []) - assert_in_out_err([env, "-W:deprecated", "-e", "exit"], "", [], - /The environment variable RUBY_GC_HEAP_INIT_SLOTS is deprecated; use environment variables RUBY_GC_HEAP_%d_INIT_SLOTS instead/) + assert_in_out_err([env, "-W0", "-e", "exit"], "", [], [], "[Bug #19284]") - env = {} - GC.stat_heap.keys.each do |heap| - env["RUBY_GC_HEAP_#{heap}_INIT_SLOTS"] = "200000" - end - assert_normal_exit("exit", "", :child_env => env) + env = { + "RUBY_GC_MALLOC_LIMIT" => "60000000", + "RUBY_GC_HEAP_INIT_SLOTS" => "100000" + } + assert_normal_exit("exit", "[ruby-core:39777]", :child_env => env) - env = {} - GC.stat_heap.keys.each do |heap| - env["RUBY_GC_HEAP_#{heap}_INIT_SLOTS"] = "0" - end - assert_normal_exit("exit", "", :child_env => env) + env = { + "RUBYOPT" => "", + "RUBY_GC_HEAP_INIT_SLOTS" => "100000" + } + assert_in_out_err([env, "-e", "exit"], "", [], [], "[ruby-core:39795]") + assert_in_out_err([env, "-W0", "-e", "exit"], "", [], [], "[ruby-core:39795]") + assert_in_out_err([env, "-W1", "-e", "exit"], "", [], [], "[ruby-core:39795]") + assert_in_out_err([env, "-w", "-e", "exit"], "", [], /RUBY_GC_HEAP_INIT_SLOTS=100000/, "[ruby-core:39795]") env = { "RUBY_GC_HEAP_GROWTH_FACTOR" => "2.0", @@ -400,13 +241,16 @@ class TestGc < Test::Unit::TestCase assert_in_out_err([env, "-w", "-e", "exit"], "", [], /RUBY_GC_HEAP_GROWTH_FACTOR=2.0/, "") assert_in_out_err([env, "-w", "-e", "exit"], "", [], /RUBY_GC_HEAP_GROWTH_MAX_SLOTS=10000/, "[ruby-core:57928]") - if use_rgengc? - env = { - "RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR" => "0.4", - } - # always full GC when RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR < 1.0 - assert_in_out_err([env, "-e", "GC.start; 1000_000.times{Object.new}; p(GC.stat[:minor_gc_count] < GC.stat[:major_gc_count])"], "", ['true'], //, "") - end + env = { + "RUBY_GC_HEAP_INIT_SLOTS" => "100000", + "RUBY_GC_HEAP_FREE_SLOTS" => "10000", + "RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR" => "0.9", + } + assert_normal_exit("exit", "", :child_env => env) + assert_in_out_err([env, "-w", "-e", "exit"], "", [], /RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR=0\.9/, "") + + # always full GC when RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR < 1.0 + assert_in_out_err([env, "-e", "1000_000.times{Object.new}; p(GC.stat[:minor_gc_count] < GC.stat[:major_gc_count])"], "", ['true'], //, "") if use_rgengc? env = { "RUBY_GC_MALLOC_LIMIT" => "60000000", @@ -429,127 +273,6 @@ class TestGc < Test::Unit::TestCase assert_in_out_err([env, "-w", "-e", "exit"], "", [], /RUBY_GC_OLDMALLOC_LIMIT_MAX=16000000/, "") assert_in_out_err([env, "-w", "-e", "exit"], "", [], /RUBY_GC_OLDMALLOC_LIMIT_GROWTH_FACTOR=2.0/, "") end - - ["0.01", "0.1", "1.0"].each do |i| - env = {"RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR" => "0", "RUBY_GC_HEAP_REMEMBERED_WB_UNPROTECTED_OBJECTS_LIMIT_RATIO" => i} - assert_separately([env, "-W0"], __FILE__, __LINE__, <<~RUBY) - GC.disable - GC.start - assert_equal((GC.stat[:old_objects] * #{i}).to_i, GC.stat[:remembered_wb_unprotected_objects_limit]) - RUBY - end - end - - def test_gc_parameter_init_slots - assert_separately([], __FILE__, __LINE__, <<~RUBY) - # Constant from gc.c. - GC_HEAP_INIT_SLOTS = 10_000 - GC.stat_heap.each do |_, s| - multiple = s[:slot_size] / (GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE] + GC::INTERNAL_CONSTANTS[:RVALUE_OVERHEAD]) - # Allocatable pages are assumed to have lost 1 slot due to alignment. - slots_per_page = (GC::INTERNAL_CONSTANTS[:HEAP_PAGE_OBJ_LIMIT] / multiple) - 1 - - total_slots = s[:heap_eden_slots] + s[:heap_allocatable_pages] * slots_per_page - assert_operator(total_slots, :>=, GC_HEAP_INIT_SLOTS, s) - end - RUBY - - env = {} - # Make the heap big enough to ensure the heap never needs to grow. - sizes = GC.stat_heap.keys.reverse.map { |i| (i + 1) * 100_000 } - GC.stat_heap.keys.each do |heap| - env["RUBY_GC_HEAP_#{heap}_INIT_SLOTS"] = sizes[heap].to_s - end - assert_separately([env, "-W0"], __FILE__, __LINE__, <<~RUBY) - SIZES = #{sizes} - GC.stat_heap.each do |i, s| - multiple = s[:slot_size] / (GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE] + GC::INTERNAL_CONSTANTS[:RVALUE_OVERHEAD]) - # Allocatable pages are assumed to have lost 1 slot due to alignment. - slots_per_page = (GC::INTERNAL_CONSTANTS[:HEAP_PAGE_OBJ_LIMIT] / multiple) - 1 - - total_slots = s[:heap_eden_slots] + s[:heap_allocatable_pages] * slots_per_page - - # The delta is calculated as follows: - # - For allocated pages, each page can vary by 1 slot due to alignment. - # - For allocatable pages, we can end up with at most 1 extra page of slots. - assert_in_delta(SIZES[i], total_slots, s[:heap_eden_pages] + slots_per_page, s) - end - RUBY - - # Check that the configured sizes are "remembered" across GC invocations. - assert_separately([env, "-W0"], __FILE__, __LINE__, <<~RUBY) - SIZES = #{sizes} - - # Fill size pool 0 with transient objects. - ary = [] - while GC.stat_heap(0, :heap_allocatable_pages) != 0 - ary << Object.new - end - ary.clear - ary = nil - - # Clear all the objects that were allocated. - GC.start - - # Check that we still have the same number of slots as initially configured. - GC.stat_heap.each do |i, s| - multiple = s[:slot_size] / (GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE] + GC::INTERNAL_CONSTANTS[:RVALUE_OVERHEAD]) - # Allocatable pages are assumed to have lost 1 slot due to alignment. - slots_per_page = (GC::INTERNAL_CONSTANTS[:HEAP_PAGE_OBJ_LIMIT] / multiple) - 1 - - total_slots = s[:heap_eden_slots] + s[:heap_allocatable_pages] * slots_per_page - - # The delta is calculated as follows: - # - For allocated pages, each page can vary by 1 slot due to alignment. - # - For allocatable pages, we can end up with at most 1 extra page of slots. - assert_in_delta(SIZES[i], total_slots, s[:heap_eden_pages] + slots_per_page, s) - end - RUBY - - # Check that we don't grow the heap in minor GC if we have alloctable pages. - env["RUBY_GC_HEAP_FREE_SLOTS_MIN_RATIO"] = "0.3" - env["RUBY_GC_HEAP_FREE_SLOTS_GOAL_RATIO"] = "0.99" - env["RUBY_GC_HEAP_FREE_SLOTS_MAX_RATIO"] = "1.0" - env["RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR"] = "100" # Large value to disable major GC - assert_separately([env, "-W0"], __FILE__, __LINE__, <<~RUBY) - SIZES = #{sizes} - - # Run a major GC to clear out dead objects. - GC.start - - # Disable GC so we can control when GC is ran. - GC.disable - - # Run minor GC enough times so that we don't grow the heap because we - # haven't yet ran RVALUE_OLD_AGE minor GC cycles. - GC::INTERNAL_CONSTANTS[:RVALUE_OLD_AGE].times { GC.start(full_mark: false) } - - # Fill size pool 0 to over 50% full so that the number of allocatable - # pages that will be created will be over the number in heap_allocatable_pages - # (calculated using RUBY_GC_HEAP_FREE_SLOTS_MIN_RATIO). - # 70% was chosen here to guarantee that. - ary = [] - while GC.stat_heap(0, :heap_allocatable_pages) > - (GC.stat_heap(0, :heap_allocatable_pages) + GC.stat_heap(0, :heap_eden_pages)) * 0.3 - ary << Object.new - end - - GC.start(full_mark: false) - - # Check that we still have the same number of slots as initially configured. - GC.stat_heap.each do |i, s| - multiple = s[:slot_size] / (GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE] + GC::INTERNAL_CONSTANTS[:RVALUE_OVERHEAD]) - # Allocatable pages are assumed to have lost 1 slot due to alignment. - slots_per_page = (GC::INTERNAL_CONSTANTS[:HEAP_PAGE_OBJ_LIMIT] / multiple) - 1 - - total_slots = s[:heap_eden_slots] + s[:heap_allocatable_pages] * slots_per_page - - # The delta is calculated as follows: - # - For allocated pages, each page can vary by 1 slot due to alignment. - # - For allocatable pages, we can end up with at most 1 extra page of slots. - assert_in_delta(SIZES[i], total_slots, s[:heap_eden_pages] + slots_per_page, s) - end - RUBY end def test_profiler_enabled @@ -562,20 +285,20 @@ class TestGc < Test::Unit::TestCase end def test_profiler_clear - omit "for now" - assert_separately([], __FILE__, __LINE__, <<-'RUBY', timeout: 30) - GC::Profiler.enable + skip "for now" + assert_separately %w[--disable-gem], __FILE__, __LINE__, <<-'eom', timeout: 30 + GC::Profiler.enable - GC.start - assert_equal(1, GC::Profiler.raw_data.size) - GC::Profiler.clear - assert_equal(0, GC::Profiler.raw_data.size) + GC.start + assert_equal(1, GC::Profiler.raw_data.size) + GC::Profiler.clear + assert_equal(0, GC::Profiler.raw_data.size) - 200.times{ GC.start } - assert_equal(200, GC::Profiler.raw_data.size) - GC::Profiler.clear - assert_equal(0, GC::Profiler.raw_data.size) - RUBY + 200.times{ GC.start } + assert_equal(200, GC::Profiler.raw_data.size) + GC::Profiler.clear + assert_equal(0, GC::Profiler.raw_data.size) + eom end def test_profiler_total_time @@ -589,62 +312,28 @@ class TestGc < Test::Unit::TestCase end def test_finalizing_main_thread - assert_in_out_err([], <<-EOS, ["\"finalize\""], [], "[ruby-dev:46647]") + assert_in_out_err(%w[--disable-gems], <<-EOS, ["\"finalize\""], [], "[ruby-dev:46647]") ObjectSpace.define_finalizer(Thread.main) { p 'finalize' } EOS end def test_expand_heap - assert_separately([], __FILE__, __LINE__, <<~'RUBY') - GC.start - base_length = GC.stat[:heap_eden_pages] - (base_length * 500).times{ 'a' } - GC.start - base_length = GC.stat[:heap_eden_pages] - (base_length * 500).times{ 'a' } - GC.start - assert_in_epsilon base_length, (v = GC.stat[:heap_eden_pages]), 1/8r, - "invalid heap expanding (base_length: #{base_length}, GC.stat[:heap_eden_pages]: #{v})" - - a = [] - (base_length * 500).times{ a << 'a'; nil } - GC.start - assert_operator base_length, :<, GC.stat[:heap_eden_pages] + 1 - RUBY - end - - def test_thrashing_for_young_objects - # This test prevents bugs like [Bug #18929] - - assert_separately([], __FILE__, __LINE__, <<-'RUBY') - # Grow the heap - @ary = 100_000.times.map { Object.new } - - # Warmup to make sure heap stabilizes - 1_000_000.times { Object.new } - - before_stats = GC.stat - before_stat_heap = GC.stat_heap - - 1_000_000.times { Object.new } - - # Previous loop may have caused GC to be in an intermediate state, - # running a minor GC here will guarantee that GC will be complete - GC.start(full_mark: false) - - after_stats = GC.stat - after_stat_heap = GC.stat_heap - - # Debugging output to for failures in trunk-repeat50@phosphorus-docker - debug_msg = "before_stats: #{before_stats}\nbefore_stat_heap: #{before_stat_heap}\nafter_stats: #{after_stats}\nafter_stat_heap: #{after_stat_heap}" + assert_separately %w[--disable-gem], __FILE__, __LINE__, <<-'eom' + GC.start + base_length = GC.stat[:heap_eden_pages] + (base_length * 500).times{ 'a' } + GC.start + base_length = GC.stat[:heap_eden_pages] + (base_length * 500).times{ 'a' } + GC.start + assert_in_epsilon base_length, (v = GC.stat[:heap_eden_pages]), 1/8r, + "invalid heap expanding (base_length: #{base_length}, GC.stat[:heap_eden_pages]: #{v})" - # Should not be thrashing in page creation - assert_equal before_stats[:heap_allocated_pages], after_stats[:heap_allocated_pages], debug_msg - assert_equal 0, after_stats[:heap_tomb_pages], debug_msg - assert_equal 0, after_stats[:total_freed_pages], debug_msg - # Only young objects, so should not trigger major GC - assert_equal before_stats[:major_gc_count], after_stats[:major_gc_count], debug_msg - RUBY + a = [] + (base_length * 500).times{ a << 'a'; nil } + GC.start + assert_operator base_length, :<, GC.stat[:heap_eden_pages] + 1 + eom end def test_gc_internals @@ -706,11 +395,11 @@ class TestGc < Test::Unit::TestCase end def test_finalizer_passed_object_id - assert_in_out_err([], <<~RUBY, ["true"], []) + assert_in_out_err(%w[--disable-gems], <<-EOS, ["true"], []) o = Object.new obj_id = o.object_id ObjectSpace.define_finalizer(o, ->(id){ p id == obj_id }) - RUBY + EOS end def test_verify_internal_consistency @@ -810,30 +499,4 @@ class TestGc < Test::Unit::TestCase Module.new.class_eval( (["# shareable_constant_value: literal"] + (0..100000).map {|i| "M#{ i } = {}" }).join("\n")) end - - def test_old_to_young_reference - original_gc_disabled = GC.disable - - require "objspace" - - old_obj = Object.new - 4.times { GC.start } - - assert_include ObjectSpace.dump(old_obj), '"old":true' - - young_obj = Object.new - old_obj.instance_variable_set(:@test, young_obj) - - # Not immediately promoted to old generation - 3.times do - assert_not_include ObjectSpace.dump(young_obj), '"old":true' - GC.start - end - - # Takes 4 GC to promote to old generation - GC.start - assert_include ObjectSpace.dump(young_obj), '"old":true' - ensure - GC.enable if !original_gc_disabled - end end diff --git a/test/ruby/test_gc_compact.rb b/test/ruby/test_gc_compact.rb index 8a3f1f145d..42ad028530 100644 --- a/test/ruby/test_gc_compact.rb +++ b/test/ruby/test_gc_compact.rb @@ -9,25 +9,31 @@ if RUBY_PLATFORM =~ /s390x/ end class TestGCCompact < Test::Unit::TestCase - module CompactionSupportInspector - def supports_auto_compact? - GC::OPTS.include?("GC_COMPACTION_SUPPORTED") + module SupportsCompact + def setup + skip "autocompact not supported on this platform" unless supports_auto_compact? + super end - end - module OmitUnlessCompactSupported - include CompactionSupportInspector + private - def setup - omit "autocompact not supported on this platform" unless supports_auto_compact? - super + def supports_auto_compact? + return true unless defined?(Etc::SC_PAGE_SIZE) + + begin + return GC::INTERNAL_CONSTANTS[:HEAP_PAGE_SIZE] % Etc.sysconf(Etc::SC_PAGE_SIZE) == 0 + rescue NotImplementedError + rescue ArgumentError + end + + true end end - include OmitUnlessCompactSupported + include SupportsCompact class AutoCompact < Test::Unit::TestCase - include OmitUnlessCompactSupported + include SupportsCompact def test_enable_autocompact before = GC.auto_compact @@ -72,7 +78,7 @@ class TestGCCompact < Test::Unit::TestCase n.times do break if count < GC.stat(:compact_count) list2 << Object.new - end and omit "implicit compaction didn't happen within #{n} objects" + end and skip "implicit compaction didn't happen within #{n} objects" compact_stats = GC.latest_compact_info refute_predicate compact_stats[:considered], :empty? refute_predicate compact_stats[:moved], :empty? @@ -81,41 +87,15 @@ class TestGCCompact < Test::Unit::TestCase end end - class CompactMethodsNotImplemented < Test::Unit::TestCase - include CompactionSupportInspector - - def assert_not_implemented(method, *args) - omit "autocompact is supported on this platform" if supports_auto_compact? - - assert_raise(NotImplementedError) { GC.send(method, *args) } - refute(GC.respond_to?(method), "GC.#{method} should be defined as rb_f_notimplement") - end - - def test_gc_compact_not_implemented - assert_not_implemented(:compact) - end - - def test_gc_auto_compact_get_not_implemented - assert_not_implemented(:auto_compact) - end - - def test_gc_auto_compact_set_not_implemented - assert_not_implemented(:auto_compact=, true) - end - - def test_gc_latest_compact_info_not_implemented - assert_not_implemented(:latest_compact_info) - end - - def test_gc_verify_compaction_references_not_implemented - assert_not_implemented(:verify_compaction_references) - end - end - def os_page_size return true unless defined?(Etc::SC_PAGE_SIZE) end + def setup + skip "autocompact not supported on this platform" unless supports_auto_compact? + super + end + def test_gc_compact_stats list = [] @@ -166,7 +146,7 @@ class TestGCCompact < Test::Unit::TestCase hash = list_of_objects.hash GC.verify_compaction_references(toward: :empty) assert_equal hash, list_of_objects.hash - GC.verify_compaction_references(expand_heap: false) + GC.verify_compaction_references(double_heap: false) assert_equal hash, list_of_objects.hash end @@ -191,283 +171,4 @@ class TestGCCompact < Test::Unit::TestCase GC.compact assert_equal count + 1, GC.stat(:compact_count) end - - def test_compacting_from_trace_point - obj = Object.new - def obj.tracee - :ret # expected to emit both line and call event from one instruction - end - - results = [] - TracePoint.new(:call, :line) do |tp| - results << tp.event - GC.verify_compaction_references - end.enable(target: obj.method(:tracee)) do - obj.tracee - end - - assert_equal([:call, :line], results) - end - - def test_updating_references_for_heap_allocated_shared_arrays - assert_separately(%w[-robjspace], "#{<<~"begin;"}\n#{<<~"end;"}", timeout: 10, signal: :SEGV) - begin; - ary = [] - 50.times { |i| ary << i } - - # Pointer in slice should point to buffer of ary - slice = ary[10..40] - - # Check that slice is pointing to buffer of ary - assert_include(ObjectSpace.dump(slice), '"shared":true') - - # Run compaction to re-embed ary - GC.verify_compaction_references(expand_heap: true, toward: :empty) - - # Assert that slice is pointer to updated buffer in ary - assert_equal(10, slice[0]) - # Check that slice is still pointing to buffer of ary - assert_include(ObjectSpace.dump(slice), '"shared":true') - end; - end - - def test_updating_references_for_embed_shared_arrays - omit if GC::INTERNAL_CONSTANTS[:SIZE_POOL_COUNT] == 1 - - assert_separately(%w[-robjspace], "#{<<~"begin;"}\n#{<<~"end;"}", timeout: 10, signal: :SEGV) - begin; - ary = Array.new(50) - 50.times { |i| ary[i] = i } - - # Ensure ary is embedded - assert_include(ObjectSpace.dump(ary), '"embedded":true') - - slice = ary[10..40] - - # Check that slice is pointing to buffer of ary - assert_include(ObjectSpace.dump(slice), '"shared":true') - - # Run compaction to re-embed ary - GC.verify_compaction_references(expand_heap: true, toward: :empty) - - # Assert that slice is pointer to updated buffer in ary - assert_equal(10, slice[0]) - # Check that slice is still pointing to buffer of ary - assert_include(ObjectSpace.dump(slice), '"shared":true') - end; - end - - def test_updating_references_for_heap_allocated_frozen_shared_arrays - assert_separately(%w[-robjspace], "#{<<~"begin;"}\n#{<<~"end;"}", timeout: 10, signal: :SEGV) - begin; - ary = [] - 50.times { |i| ary << i } - # Frozen arrays can become shared root without RARRAY_SHARED_ROOT_FLAG - ary.freeze - - slice = ary[10..40] - - # Check that slice is pointing to buffer of ary - assert_include(ObjectSpace.dump(slice), '"shared":true') - - # Run compaction to re-embed ary - GC.verify_compaction_references(expand_heap: true, toward: :empty) - - # Assert that slice is pointer to updated buffer in ary - assert_equal(10, slice[0]) - # Check that slice is still pointing to buffer of ary - assert_include(ObjectSpace.dump(slice), '"shared":true') - end; - end - - def test_updating_references_for_embed_frozen_shared_arrays - omit if GC::INTERNAL_CONSTANTS[:SIZE_POOL_COUNT] == 1 - - assert_separately(%w[-robjspace], "#{<<~"begin;"}\n#{<<~"end;"}", timeout: 10, signal: :SEGV) - begin; - ary = Array.new(50) - 50.times { |i| ary[i] = i } - # Frozen arrays can become shared root without RARRAY_SHARED_ROOT_FLAG - ary.freeze - - # Ensure ary is embedded - assert_include(ObjectSpace.dump(ary), '"embedded":true') - - slice = ary[10..40] - - # Check that slice is pointing to buffer of ary - assert_include(ObjectSpace.dump(slice), '"shared":true') - - # Run compaction to re-embed ary - GC.verify_compaction_references(expand_heap: true, toward: :empty) - - # Assert that slice is pointer to updated buffer in ary - assert_equal(10, slice[0]) - # Check that slice is still pointing to buffer of ary - assert_include(ObjectSpace.dump(slice), '"shared":true') - end; - end - - def test_moving_arrays_down_size_pools - omit if GC::INTERNAL_CONSTANTS[:SIZE_POOL_COUNT] == 1 - - assert_separately(%w[-robjspace], "#{<<~"begin;"}\n#{<<~"end;"}", timeout: 10, signal: :SEGV) - begin; - ARY_COUNT = 500 - - GC.verify_compaction_references(expand_heap: true, toward: :empty) - - arys = ARY_COUNT.times.map do - ary = "abbbbbbbbbb".chars - ary.uniq! - end - - stats = GC.verify_compaction_references(expand_heap: true, toward: :empty) - assert_operator(stats.dig(:moved_down, :T_ARRAY) || 0, :>=, ARY_COUNT) - refute_empty(arys.keep_if { |o| ObjectSpace.dump(o).include?('"embedded":true') }) - end; - end - - def test_moving_arrays_up_size_pools - omit if GC::INTERNAL_CONSTANTS[:SIZE_POOL_COUNT] == 1 - - assert_separately(%w[-robjspace], "#{<<~"begin;"}\n#{<<~"end;"}", timeout: 10, signal: :SEGV) - begin; - ARY_COUNT = 500 - - GC.verify_compaction_references(expand_heap: true, toward: :empty) - - ary = "hello".chars - arys = ARY_COUNT.times.map do - x = [] - ary.each { |e| x << e } - x - end - - stats = GC.verify_compaction_references(expand_heap: true, toward: :empty) - assert_operator(stats.dig(:moved_up, :T_ARRAY) || 0, :>=, ARY_COUNT) - refute_empty(arys.keep_if { |o| ObjectSpace.dump(o).include?('"embedded":true') }) - end; - end - - def test_moving_objects_between_size_pools - omit if GC::INTERNAL_CONSTANTS[:SIZE_POOL_COUNT] == 1 - omit "Flaky on Solaris" if /solaris/i =~ RUBY_PLATFORM - - assert_separately(%w[-robjspace], "#{<<~"begin;"}\n#{<<~"end;"}", timeout: 10, signal: :SEGV) - begin; - class Foo - def add_ivars - 10.times do |i| - instance_variable_set("@foo" + i.to_s, 0) - end - end - end - - OBJ_COUNT = 500 - - GC.verify_compaction_references(expand_heap: true, toward: :empty) - - ary = OBJ_COUNT.times.map { Foo.new } - ary.each(&:add_ivars) - - GC.start - Foo.new.add_ivars - - stats = GC.verify_compaction_references(expand_heap: true, toward: :empty) - - assert_operator(stats.dig(:moved_up, :T_OBJECT) || 0, :>=, OBJ_COUNT) - refute_empty(ary.keep_if { |o| ObjectSpace.dump(o).include?('"embedded":true') }) - end; - end - - def test_moving_strings_up_size_pools - omit if GC::INTERNAL_CONSTANTS[:SIZE_POOL_COUNT] == 1 - - assert_separately(%w[-robjspace], "#{<<~"begin;"}\n#{<<~"end;"}", timeout: 10, signal: :SEGV) - begin; - STR_COUNT = 500 - - GC.verify_compaction_references(expand_heap: true, toward: :empty) - - str = "a" * GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE] - ary = STR_COUNT.times.map { "" << str } - - stats = GC.verify_compaction_references(expand_heap: true, toward: :empty) - - assert_operator(stats[:moved_up][:T_STRING], :>=, STR_COUNT) - refute_empty(ary.keep_if { |o| ObjectSpace.dump(o).include?('"embedded":true') }) - end; - end - - def test_moving_strings_down_size_pools - omit if GC::INTERNAL_CONSTANTS[:SIZE_POOL_COUNT] == 1 - - assert_separately(%w[-robjspace], "#{<<~"begin;"}\n#{<<~"end;"}", timeout: 10, signal: :SEGV) - begin; - STR_COUNT = 500 - - GC.verify_compaction_references(expand_heap: true, toward: :empty) - - ary = STR_COUNT.times.map { ("a" * GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE]).squeeze! } - - stats = GC.verify_compaction_references(expand_heap: true, toward: :empty) - - assert_operator(stats[:moved_down][:T_STRING], :>=, STR_COUNT) - refute_empty(ary.keep_if { |o| ObjectSpace.dump(o).include?('"embedded":true') }) - end; - end - - def test_moving_hashes_down_size_pools - omit if GC::INTERNAL_CONSTANTS[:SIZE_POOL_COUNT] == 1 - # AR and ST hashes are in the same size pool on 32 bit - omit unless RbConfig::SIZEOF["uint64_t"] <= RbConfig::SIZEOF["void*"] - # This test fails on Solaris SPARC with the following error and I can't figure out why: - # TestGCCompact#test_moving_hashes_down_size_pools - # Expected 499 to be >= 500. - omit if /sparc-solaris/ =~ RUBY_PLATFORM - - assert_separately(%w[-robjspace], "#{<<~"begin;"}\n#{<<~"end;"}", timeout: 10, signal: :SEGV) - begin; - HASH_COUNT = 500 - - GC.verify_compaction_references(expand_heap: true, toward: :empty) - - base_hash = { a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8 } - ary = HASH_COUNT.times.map { base_hash.dup } - ary.each { |h| h[:i] = 9 } - - stats = GC.verify_compaction_references(expand_heap: true, toward: :empty) - - assert_operator(stats[:moved_down][:T_HASH], :>=, 500) - end; - end - - def test_moving_objects_between_size_pools_keeps_shape_frozen_status - # [Bug #19536] - assert_separately([], "#{<<~"begin;"}\n#{<<~"end;"}") - begin; - class A - def add_ivars - @a = @b = @c = @d = 1 - end - - def set_a - @a = 10 - end - end - - a = A.new - a.add_ivars - a.freeze - - b = A.new - b.add_ivars - b.set_a # Set the inline cache in set_a - - GC.verify_compaction_references(expand_heap: true, toward: :empty) - - assert_raise(FrozenError) { a.set_a } - end; - end end diff --git a/test/ruby/test_hash.rb b/test/ruby/test_hash.rb index 9121f3539e..683ec3855d 100644 --- a/test/ruby/test_hash.rb +++ b/test/ruby/test_hash.rb @@ -219,15 +219,6 @@ class TestHash < Test::Unit::TestCase assert_equal('default', h['spurious']) end - def test_st_literal_memory_leak - assert_no_memory_leak([], "", "#{<<~'end;'}", rss: true) - 1_000_000.times do - # >8 element hashes are ST allocated rather than AR allocated - {a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8, i: 9} - end - end; - end - def test_try_convert assert_equal({1=>2}, Hash.try_convert({1=>2})) assert_equal(nil, Hash.try_convert("1=>2")) @@ -313,20 +304,6 @@ class TestHash < Test::Unit::TestCase assert_equal before, ObjectSpace.count_objects[:T_STRING] end - def test_AREF_fstring_key_default_proc - assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") - begin; - h = Hash.new do |h, k| - k.frozen? - end - - str = "foo" - refute str.frozen? # assumes this file is frozen_string_literal: false - refute h[str] - refute h["foo"] - end; - end - def test_ASET_fstring_key a, b = {}, {} assert_equal 1, a["abc"] = 1 @@ -859,16 +836,6 @@ class TestHash < Test::Unit::TestCase assert(true) end - def test_replace_st_with_ar - # ST hash - h1 = { a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8, i: 9 } - # AR hash - h2 = { a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7 } - # Replace ST hash with AR hash - h1.replace(h2) - assert_equal(h2, h1) - end - def test_shift h = @h.dup @@ -1081,14 +1048,14 @@ class TestHash < Test::Unit::TestCase h = @cls.new {|hh, k| :foo } h[1] = 2 assert_equal([1, 2], h.shift) - assert_nil(h.shift) - assert_nil(h.shift) + assert_equal(:foo, h.shift) + assert_equal(:foo, h.shift) h = @cls.new(:foo) h[1] = 2 assert_equal([1, 2], h.shift) - assert_nil(h.shift) - assert_nil(h.shift) + assert_equal(:foo, h.shift) + assert_equal(:foo, h.shift) h =@cls[1=>2] h.each { assert_equal([1, 2], h.shift) } @@ -1099,7 +1066,7 @@ class TestHash < Test::Unit::TestCase def h.default(k = nil) super.upcase end - assert_nil(h.shift) + assert_equal("FOO", h.shift) end def test_shift_for_empty_hash @@ -1325,7 +1292,7 @@ class TestHash < Test::Unit::TestCase end def test_replace_memory_leak - assert_no_memory_leak([], "#{<<-"begin;"}", "#{<<-'end;'}", rss: true) + assert_no_memory_leak([], "#{<<-"begin;"}", "#{<<-'end;'}") h = ("aa".."zz").each_with_index.to_h 10_000.times {h.dup} begin; @@ -1575,17 +1542,6 @@ class TestHash < Test::Unit::TestCase end end - def hash_iter_recursion(h, level) - return if level == 0 - h.each_key {} - h.each_value { hash_iter_recursion(h, level - 1) } - end - - def test_iterlevel_in_ivar_bug19589 - h = { a: nil } - hash_iter_recursion(h, 200) - end - def test_threaded_iter_level bug9105 = '[ruby-dev:47807] [Bug #9105]' h = @cls[1=>2] @@ -1777,6 +1733,15 @@ class TestHash < Test::Unit::TestCase assert_no_memory_leak([], prepare, code, bug9187) end + def test_memory_size_after_delete + require 'objspace' + h = {} + 1000.times {|i| h[i] = true} + big = ObjectSpace.memsize_of(h) + 1000.times {|i| h.delete(i)} + assert_operator ObjectSpace.memsize_of(h), :<, big/10 + end + def test_wrapper bug9381 = '[ruby-core:59638] [Bug #9381]' @@ -2210,27 +2175,6 @@ class TestHash < Test::Unit::TestCase end end - # Previously this test would fail because rb_hash inside opt_aref would look - # at the current method name - def test_hash_recursion_independent_of_mid - o = Class.new do - def hash(h, k) - h[k] - end - - def any_other_name(h, k) - h[k] - end - end.new - - rec = []; rec << rec - - h = @cls[] - h[rec] = 1 - assert o.hash(h, rec) - assert o.any_other_name(h, rec) - end - def test_any_hash_fixable 20.times do assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") diff --git a/test/ruby/test_integer.rb b/test/ruby/test_integer.rb index 31cb8d6cf5..2f3f00ecda 100644 --- a/test/ruby/test_integer.rb +++ b/test/ruby/test_integer.rb @@ -138,6 +138,20 @@ class TestInteger < Test::Unit::TestCase assert_equal(1234, Integer(1234)) assert_equal(1, Integer(1.234)) + # base argument + assert_equal(1234, Integer("1234", 10)) + assert_equal(668, Integer("1234", 8)) + assert_equal(4660, Integer("1234", 16)) + assert_equal(49360, Integer("1234", 36)) + # decimal, not octal + assert_equal(1234, Integer("01234", 10)) + assert_raise(ArgumentError) { Integer("0x123", 10) } + assert_raise(ArgumentError) { Integer(1234, 10) } + assert_raise(ArgumentError) { Integer(12.34, 10) } + assert_raise(ArgumentError) { Integer(Object.new, 1) } + + assert_raise(ArgumentError) { Integer(1, 1, 1) } + assert_equal(2 ** 50, Integer(2.0 ** 50)) assert_raise(TypeError) { Integer(nil) } @@ -231,39 +245,6 @@ class TestInteger < Test::Unit::TestCase end; end - def test_Integer_when_to_str - def (obj = Object.new).to_str - "0x10" - end - assert_equal(16, Integer(obj)) - end - - def test_Integer_with_base - assert_equal(1234, Integer("1234", 10)) - assert_equal(668, Integer("1234", 8)) - assert_equal(4660, Integer("1234", 16)) - assert_equal(49360, Integer("1234", 36)) - # decimal, not octal - assert_equal(1234, Integer("01234", 10)) - assert_raise(ArgumentError) { Integer("0x123", 10) } - assert_raise(ArgumentError) { Integer(1234, 10) } - assert_raise(ArgumentError) { Integer(12.34, 10) } - assert_raise(ArgumentError) { Integer(Object.new, 1) } - - assert_raise(ArgumentError) { Integer(1, 1, 1) } - - def (base = Object.new).to_int - 8 - end - assert_equal(8, Integer("10", base)) - - assert_raise(TypeError) { Integer("10", "8") } - def (base = Object.new).to_int - "8" - end - assert_raise(TypeError) { Integer("10", base) } - end - def test_int_p assert_not_predicate(1.0, :integer?) assert_predicate(1, :integer?) @@ -321,34 +302,23 @@ class TestInteger < Test::Unit::TestCase begin; called = false Integer.class_eval do - alias old_succ succ - undef succ - define_method(:succ){|x| called = true; x+1} + alias old_plus + + undef + + define_method(:+){|x| called = true; 1} alias old_lt < undef < define_method(:<){|x| called = true} end - - fix = 1 - fix.times{break 0} - fix_called = called - - called = false - big = 2**65 big.times{break 0} - big_called = called - Integer.class_eval do - undef succ - alias succ old_succ + undef + + alias + old_plus undef < alias < old_lt end - - # Asssert that Fixnum and Bignum behave consistently bug18377 = "[ruby-core:106361]" - assert_equal(fix_called, big_called, bug18377) + assert_equal(false, called, bug18377) end; end @@ -732,25 +702,4 @@ class TestInteger < Test::Unit::TestCase def o.to_int; Object.new; end assert_raise_with_message(TypeError, /can't convert Object to Integer/) {Integer.try_convert(o)} end - - def test_ceildiv - assert_equal(0, 0.ceildiv(3)) - assert_equal(1, 1.ceildiv(3)) - assert_equal(1, 3.ceildiv(3)) - assert_equal(2, 4.ceildiv(3)) - - assert_equal(-1, 4.ceildiv(-3)) - assert_equal(-1, -4.ceildiv(3)) - assert_equal(2, -4.ceildiv(-3)) - - assert_equal(3, 3.ceildiv(1.2)) - assert_equal(3, 3.ceildiv(6/5r)) - - assert_equal(10, (10**100-11).ceildiv(10**99-1)) - assert_equal(11, (10**100-9).ceildiv(10**99-1)) - - o = Object.new - def o.coerce(other); [other, 10]; end - assert_equal(124, 1234.ceildiv(o)) - end end diff --git a/test/ruby/test_integer_comb.rb b/test/ruby/test_integer_comb.rb index 150f45cfd7..1ad13dd31b 100644 --- a/test/ruby/test_integer_comb.rb +++ b/test/ruby/test_integer_comb.rb @@ -408,32 +408,19 @@ class TestIntegerComb < Test::Unit::TestCase end def test_remainder - coerce = EnvUtil.labeled_class("CoerceNum") do - def initialize(num) - @num = num - end - def coerce(other) - [other, @num] - end - def inspect - "#{self.class.name}(#@num)" - end - alias to_s inspect - end - VS.each {|a| - (VS + VS.map {|b| [coerce.new(b), b]}).each {|b, i = b| - if i == 0 + VS.each {|b| + if b == 0 assert_raise(ZeroDivisionError) { a.divmod(b) } else - r = assert_nothing_raised(ArgumentError, "#{a}.remainder(#{b})") {a.remainder(b)} + r = a.remainder(b) assert_kind_of(Integer, r) if a < 0 - assert_operator(-i.abs, :<, r, "#{a}.remainder(#{b})") + assert_operator(-b.abs, :<, r, "#{a}.remainder(#{b})") assert_operator(0, :>=, r, "#{a}.remainder(#{b})") elsif 0 < a assert_operator(0, :<=, r, "#{a}.remainder(#{b})") - assert_operator(i.abs, :>, r, "#{a}.remainder(#{b})") + assert_operator(b.abs, :>, r, "#{a}.remainder(#{b})") else assert_equal(0, r, "#{a}.remainder(#{b})") end diff --git a/test/ruby/test_io.rb b/test/ruby/test_io.rb index 7689b52e23..4f54052d3b 100644 --- a/test/ruby/test_io.rb +++ b/test/ruby/test_io.rb @@ -312,7 +312,7 @@ class TestIO < Test::Unit::TestCase w.print "a\n\nb\n\n" w.close end, proc do |r| - assert_equal("a\n\nb\n\n", r.gets(nil, chomp: true), "[Bug #18770]") + assert_equal "a\n\nb\n", r.gets(nil, chomp: true) assert_nil r.gets("") r.close end) @@ -655,8 +655,8 @@ class TestIO < Test::Unit::TestCase if have_nonblock? def test_copy_stream_no_busy_wait - omit "RJIT has busy wait on GC. This sometimes fails with --jit." if defined?(RubyVM::RJIT) && RubyVM::RJIT.enabled? - omit "multiple threads already active" if Thread.list.size > 1 + skip "MJIT has busy wait on GC. This sometimes fails with --jit." if defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? + skip "multiple threads already active" if Thread.list.size > 1 msg = 'r58534 [ruby-core:80969] [Backport #13533]' IO.pipe do |r,w| @@ -675,7 +675,7 @@ class TestIO < Test::Unit::TestCase begin w2.nonblock = true rescue Errno::EBADF - omit "nonblocking IO for pipe is not implemented" + skip "nonblocking IO for pipe is not implemented" end s = w2.syswrite("a" * 100000) t = Thread.new { sleep 0.1; r2.read } @@ -779,7 +779,7 @@ class TestIO < Test::Unit::TestCase r1.nonblock = true w2.nonblock = true rescue Errno::EBADF - omit "nonblocking IO for pipe is not implemented" + skip "nonblocking IO for pipe is not implemented" end t1 = Thread.new { w1 << megacontent; w1.close } t2 = Thread.new { r2.read } @@ -843,7 +843,7 @@ class TestIO < Test::Unit::TestCase assert_equal("bcd", r.read) end) rescue NotImplementedError - omit "pread(2) is not implemtented." + skip "pread(2) is not implemtented." end } end @@ -900,10 +900,6 @@ class TestIO < Test::Unit::TestCase end if defined? UNIXSocket def test_copy_stream_socket4 - if RUBY_PLATFORM =~ /mingw|mswin/ - omit "pread(2) is not implemented." - end - with_bigsrc {|bigsrc, bigcontent| File.open(bigsrc) {|f| assert_equal(0, f.pos) @@ -920,13 +916,9 @@ class TestIO < Test::Unit::TestCase } } } - end + end if defined? UNIXSocket def test_copy_stream_socket5 - if RUBY_PLATFORM =~ /mingw|mswin/ - omit "pread(2) is not implemented." - end - with_bigsrc {|bigsrc, bigcontent| File.open(bigsrc) {|f| assert_equal(bigcontent[0,100], f.read(100)) @@ -944,13 +936,9 @@ class TestIO < Test::Unit::TestCase } } } - end + end if defined? UNIXSocket def test_copy_stream_socket6 - if RUBY_PLATFORM =~ /mingw|mswin/ - omit "pread(2) is not implemented." - end - mkcdtmpdir { megacontent = "abc" * 1234567 File.open("megasrc", "w") {|f| f << megacontent } @@ -959,7 +947,7 @@ class TestIO < Test::Unit::TestCase begin s1.nonblock = true rescue Errno::EBADF - omit "nonblocking IO for pipe is not implemented" + skip "nonblocking IO for pipe is not implemented" end t1 = Thread.new { s2.read } t2 = Thread.new { @@ -971,13 +959,9 @@ class TestIO < Test::Unit::TestCase assert_equal(megacontent, result) } } - end + end if defined? UNIXSocket def test_copy_stream_socket7 - if RUBY_PLATFORM =~ /mingw|mswin/ - omit "pread(2) is not implemented." - end - GC.start mkcdtmpdir { megacontent = "abc" * 1234567 @@ -987,7 +971,7 @@ class TestIO < Test::Unit::TestCase begin s1.nonblock = true rescue Errno::EBADF - omit "nonblocking IO for pipe is not implemented" + skip "nonblocking IO for pipe is not implemented" end trapping_usr2 do |rd| nr = 30 @@ -1012,7 +996,7 @@ class TestIO < Test::Unit::TestCase end } } - end + end if defined? UNIXSocket and IO.method_defined?("nonblock=") def test_copy_stream_strio src = StringIO.new("abcd") @@ -1457,16 +1441,6 @@ class TestIO < Test::Unit::TestCase End end - def test_dup_timeout - with_pipe do |r, w| - r.timeout = 0.1 - r2 = r.dup - assert_equal(0.1, r2.timeout) - ensure - r2&.close - end - end - def test_inspect with_pipe do |r, w| assert_match(/^#<IO:fd \d+>$/, r.inspect) @@ -1623,28 +1597,6 @@ class TestIO < Test::Unit::TestCase end end - def test_read_nonblock_file - make_tempfile do |path| - File.open(path, 'r') do |file| - file.read_nonblock(4) - end - end - end - - def test_write_nonblock_file - make_tempfile do |path| - File.open(path, 'w') do |file| - file.write_nonblock("Ruby") - end - end - end - - def test_explicit_path - io = IO.for_fd(0, path: "Fake Path", autoclose: false) - assert_match %r"Fake Path", io.inspect - assert_equal "Fake Path", io.path - end - def test_write_nonblock_simple_no_exceptions pipe(proc do |w| w.write_nonblock('1', exception: false) @@ -1679,7 +1631,7 @@ class TestIO < Test::Unit::TestCase end if have_nonblock? def test_read_nonblock_no_exceptions - omit '[ruby-core:90895] RJIT worker may leave fd open in a forked child' if defined?(RubyVM::RJIT) && RubyVM::RJIT.enabled? # TODO: consider acquiring GVL from RJIT worker. + skip '[ruby-core:90895] MJIT worker may leave fd open in a forked child' if defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? # TODO: consider acquiring GVL from MJIT worker. with_pipe {|r, w| assert_equal :wait_readable, r.read_nonblock(4096, exception: false) w.puts "HI!" @@ -1942,20 +1894,6 @@ class TestIO < Test::Unit::TestCase assert_equal("baz\n", e.next) assert_raise(StopIteration) { e.next } end) - - pipe(proc do |w| - w.write "foo\n" - w.close - end, proc do |r| - assert_equal(["foo\n"], r.each_line(nil, chomp: true).to_a, "[Bug #18770]") - end) - - pipe(proc do |w| - w.write "foo\n" - w.close - end, proc do |r| - assert_equal(["fo", "o\n"], r.each_line(nil, 2, chomp: true).to_a, "[Bug #18770]") - end) end def test_each_byte2 @@ -2261,14 +2199,6 @@ class TestIO < Test::Unit::TestCase end) end - def test_sysread_with_negative_length - make_tempfile {|t| - open(t.path) do |f| - assert_raise(ArgumentError) { f.sysread(-1) } - end - } - end - def test_flag make_tempfile {|t| assert_raise(ArgumentError) do @@ -2347,9 +2277,9 @@ class TestIO < Test::Unit::TestCase end def test_autoclose_true_closed_by_finalizer - # http://ci.rvm.jp/results/trunk-rjit@silicon-docker/1465760 - # http://ci.rvm.jp/results/trunk-rjit@silicon-docker/1469765 - omit 'this randomly fails with RJIT' if defined?(RubyVM::RJIT) && RubyVM::RJIT.enabled? + # http://ci.rvm.jp/results/trunk-mjit@silicon-docker/1465760 + # http://ci.rvm.jp/results/trunk-mjit@silicon-docker/1469765 + skip 'this randomly fails with MJIT' if defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? feature2250 = '[ruby-core:26222]' pre = 'ft2250' @@ -2361,7 +2291,7 @@ class TestIO < Test::Unit::TestCase t.close rescue Errno::EBADF end - omit "expect IO object was GC'ed but not recycled yet" + skip "expect IO object was GC'ed but not recycled yet" rescue WeakRef::RefError assert_raise(Errno::EBADF, feature2250) {t.close} end @@ -2377,7 +2307,7 @@ class TestIO < Test::Unit::TestCase begin w.close t.close - omit "expect IO object was GC'ed but not recycled yet" + skip "expect IO object was GC'ed but not recycled yet" rescue WeakRef::RefError assert_nothing_raised(Errno::EBADF, feature2250) {t.close} end @@ -2412,19 +2342,15 @@ class TestIO < Test::Unit::TestCase end def test_open_pipe - assert_deprecated_warning(/Kernel#open with a leading '\|'/) do # https://bugs.ruby-lang.org/issues/19630 - open("|" + EnvUtil.rubybin, "r+") do |f| - f.puts "puts 'foo'" - f.close_write - assert_equal("foo\n", f.read) - end + open("|" + EnvUtil.rubybin, "r+") do |f| + f.puts "puts 'foo'" + f.close_write + assert_equal("foo\n", f.read) end end def test_read_command - assert_deprecated_warning(/IO process creation with a leading '\|'/) do # https://bugs.ruby-lang.org/issues/19630 - assert_equal("foo\n", IO.read("|echo foo")) - end + assert_equal("foo\n", IO.read("|echo foo")) assert_raise(Errno::ENOENT, Errno::EINVAL) do File.read("|#{EnvUtil.rubybin} -e puts") end @@ -2438,9 +2364,7 @@ class TestIO < Test::Unit::TestCase Class.new(IO).binread("|#{EnvUtil.rubybin} -e puts") end assert_raise(Errno::ESPIPE) do - assert_deprecated_warning(/IO process creation with a leading '\|'/) do # https://bugs.ruby-lang.org/issues/19630 - IO.read("|echo foo", 1, 1) - end + IO.read("|echo foo", 1, 1) end end @@ -2625,16 +2549,11 @@ class TestIO < Test::Unit::TestCase def test_foreach a = [] - - assert_deprecated_warning(/IO process creation with a leading '\|'/) do # https://bugs.ruby-lang.org/issues/19630 - IO.foreach("|" + EnvUtil.rubybin + " -e 'puts :foo; puts :bar; puts :baz'") {|x| a << x } - end + IO.foreach("|" + EnvUtil.rubybin + " -e 'puts :foo; puts :bar; puts :baz'") {|x| a << x } assert_equal(["foo\n", "bar\n", "baz\n"], a) a = [] - assert_deprecated_warning(/IO process creation with a leading '\|'/) do # https://bugs.ruby-lang.org/issues/19630 - IO.foreach("|" + EnvUtil.rubybin + " -e 'puts :zot'", :open_args => ["r"]) {|x| a << x } - end + IO.foreach("|" + EnvUtil.rubybin + " -e 'puts :zot'", :open_args => ["r"]) {|x| a << x } assert_equal(["zot\n"], a) make_tempfile {|t| @@ -2669,8 +2588,6 @@ class TestIO < Test::Unit::TestCase bug = '[ruby-dev:31525]' assert_raise(ArgumentError, bug) {IO.foreach} - assert_raise(ArgumentError, "[Bug #18767] [ruby-core:108499]") {IO.foreach(__FILE__, 0){}} - a = nil assert_nothing_raised(ArgumentError, bug) {a = IO.foreach(t.path).to_a} assert_equal(["foo\n", "bar\n", "baz\n"], a, bug) @@ -2679,8 +2596,6 @@ class TestIO < Test::Unit::TestCase assert_raise_with_message(IOError, /not opened for reading/, bug6054) do IO.foreach(t.path, mode:"w").next end - - assert_raise(ArgumentError, "[Bug #18771] [ruby-core:108503]") {IO.foreach(t, "\n", 10, true){}} } end @@ -2690,7 +2605,6 @@ class TestIO < Test::Unit::TestCase assert_equal(["foo\nb", "ar\nb", "az\n"], IO.readlines(t.path, "b")) assert_equal(["fo", "o\n", "ba", "r\n", "ba", "z\n"], IO.readlines(t.path, 2)) assert_equal(["fo", "o\n", "b", "ar", "\nb", "az", "\n"], IO.readlines(t.path, "b", 2)) - assert_raise(ArgumentError, "[Bug #18771] [ruby-core:108503]") {IO.readlines(t, "\n", 10, true){}} } end @@ -2756,7 +2670,7 @@ class TestIO < Test::Unit::TestCase end def test_puts_parallel - omit "not portable" + skip "not portable" pipe(proc do |w| threads = [] 100.times do @@ -2877,9 +2791,6 @@ class TestIO < Test::Unit::TestCase assert_equal("foo\nbar\nbaz\n", File.read(t.path)) assert_equal("foo\nba", File.read(t.path, 6)) assert_equal("bar\n", File.read(t.path, 4, 4)) - - assert_raise(ArgumentError) { File.read(t.path, -1) } - assert_raise(ArgumentError) { File.read(t.path, 1, -1) } } end @@ -3186,8 +3097,6 @@ __END__ end def test_cross_thread_close_stdio - omit "[Bug #18613]" if /freebsd/ =~ RUBY_PLATFORM - assert_separately([], <<-'end;') IO.pipe do |r,w| $stdin.reopen(r) @@ -3395,7 +3304,7 @@ __END__ begin f = File.open('/dev/tty') rescue Errno::ENOENT, Errno::ENXIO => e - omit e.message + skip e.message else tiocgwinsz=0x5413 winsize="" @@ -3521,10 +3430,10 @@ __END__ with_pipe do |r,w| # Linux 2.6.15 and earlier returned EINVAL instead of ESPIPE assert_raise(Errno::ESPIPE, Errno::EINVAL) { - r.advise(:willneed) or omit "fadvise(2) is not implemented" + r.advise(:willneed) or skip "fadvise(2) is not implemented" } assert_raise(Errno::ESPIPE, Errno::EINVAL) { - w.advise(:willneed) or omit "fadvise(2) is not implemented" + w.advise(:willneed) or skip "fadvise(2) is not implemented" } end end if /linux/ =~ RUBY_PLATFORM @@ -3664,14 +3573,14 @@ __END__ f.write('1') pos = f.tell rescue Errno::ENOSPC - omit "non-sparse file system" + skip "non-sparse file system" rescue SystemCallError else assert_equal(0x1_0000_0000, pos, msg) end end; rescue Timeout::Error - omit "Timeout because of slow file writing" + skip "Timeout because of slow file writing" end } end if /mswin|mingw/ =~ RUBY_PLATFORM @@ -3825,7 +3734,7 @@ __END__ end def test_race_gets_and_close - opt = { signal: :ABRT, timeout: 10 } + opt = { signal: :ABRT, timeout: 200 } assert_separately([], "#{<<-"begin;"}\n#{<<-"end;"}", **opt) bug13076 = '[ruby-core:78845] [Bug #13076]' begin; @@ -3856,8 +3765,6 @@ __END__ end def test_race_closed_stream - omit "[Bug #18613]" if /freebsd/ =~ RUBY_PLATFORM - assert_separately([], "#{<<-"begin;"}\n#{<<-"end;"}") begin; bug13158 = '[ruby-core:79262] [Bug #13158]' @@ -3952,8 +3859,6 @@ __END__ end def test_closed_stream_in_rescue - omit "[Bug #18613]" if /freebsd/ =~ RUBY_PLATFORM - assert_separately([], "#{<<-"begin;"}\n#{<<~"end;"}") begin; 10.times do @@ -3987,7 +3892,7 @@ __END__ assert_raise(EOFError) { f.pread(1, f.size) } end } - end + end if IO.method_defined?(:pread) def test_pwrite make_tempfile { |t| @@ -3996,7 +3901,7 @@ __END__ assert_equal("ooo", f.pread(3, 4)) end } - end + end if IO.method_defined?(:pread) and IO.method_defined?(:pwrite) def test_select_exceptfds if Etc.uname[:sysname] == 'SunOS' @@ -4022,9 +3927,6 @@ __END__ noex = Thread.new do # everything right and never see exceptions :) until sig_rd.wait_readable(0) IO.pipe do |r, w| - assert_nil r.timeout - assert_nil w.timeout - th = Thread.new { r.read(1) } w.write(dot) diff --git a/test/ruby/test_io_buffer.rb b/test/ruby/test_io_buffer.rb index c3ab09f27e..c1034efe34 100644 --- a/test/ruby/test_io_buffer.rb +++ b/test/ruby/test_io_buffer.rb @@ -124,20 +124,6 @@ class TestIOBuffer < Test::Unit::TestCase end end - def test_string - result = IO::Buffer.string(12) do |buffer| - buffer.set_string("Hello World!") - end - - assert_equal "Hello World!", result - end - - def test_string_negative - assert_raise ArgumentError do - IO::Buffer.string(-1) - end - end - def test_resize_mapped buffer = IO::Buffer.new @@ -201,26 +187,16 @@ class TestIOBuffer < Test::Unit::TestCase assert_equal("Hello World", buffer.get_string(8, 11)) end - def test_slice_arguments - buffer = IO::Buffer.for("Hello World") - - slice = buffer.slice - assert_equal "Hello World", slice.get_string - - slice = buffer.slice(2) - assert_equal("llo World", slice.get_string) - end - - def test_slice_bounds_error + def test_slice_bounds buffer = IO::Buffer.new(128) assert_raise ArgumentError do buffer.slice(128, 10) end - assert_raise ArgumentError do - buffer.slice(-10, 10) - end + # assert_raise RuntimeError do + # pp buffer.slice(-10, 10) + # end end def test_locked @@ -285,59 +261,17 @@ class TestIOBuffer < Test::Unit::TestCase :F64 => [-1.0, 0.0, 0.5, 1.0, 128.0], } - def test_get_set_value + def test_get_set_primitives buffer = IO::Buffer.new(128) - RANGES.each do |data_type, values| + RANGES.each do |type, values| values.each do |value| - buffer.set_value(data_type, 0, value) - assert_equal value, buffer.get_value(data_type, 0), "Converting #{value} as #{data_type}." + buffer.set_value(type, 0, value) + assert_equal value, buffer.get_value(type, 0), "Converting #{value} as #{type}." end end end - def test_get_set_values - buffer = IO::Buffer.new(128) - - RANGES.each do |data_type, values| - format = [data_type] * values.size - - buffer.set_values(format, 0, values) - assert_equal values, buffer.get_values(format, 0), "Converting #{values} as #{format}." - end - end - - def test_values - buffer = IO::Buffer.new(128) - - RANGES.each do |data_type, values| - format = [data_type] * values.size - - buffer.set_values(format, 0, values) - assert_equal values, buffer.values(data_type, 0, values.size), "Reading #{values} as #{format}." - end - end - - def test_each - buffer = IO::Buffer.new(128) - - RANGES.each do |data_type, values| - format = [data_type] * values.size - data_type_size = IO::Buffer.size_of(data_type) - values_with_offsets = values.map.with_index{|value, index| [index * data_type_size, value]} - - buffer.set_values(format, 0, values) - assert_equal values_with_offsets, buffer.each(data_type, 0, values.size).to_a, "Reading #{values} as #{data_type}." - end - end - - def test_each_byte - string = "The quick brown fox jumped over the lazy dog." - buffer = IO::Buffer.for(string) - - assert_equal string.bytes, buffer.each_byte.to_a - end - def test_clear buffer = IO::Buffer.new(16) buffer.set_string("Hello World!") @@ -369,38 +303,17 @@ class TestIOBuffer < Test::Unit::TestCase input.close end - def hello_world_tempfile + def test_read io = Tempfile.new io.write("Hello World") io.seek(0) - yield io - ensure - io&.close! - end - - def test_read - hello_world_tempfile do |io| - buffer = IO::Buffer.new(128) - buffer.read(io) - assert_equal "Hello", buffer.get_string(0, 5) - end - end - - def test_read_with_with_length - hello_world_tempfile do |io| - buffer = IO::Buffer.new(128) - buffer.read(io, 5) - assert_equal "Hello", buffer.get_string(0, 5) - end - end + buffer = IO::Buffer.new(128) + buffer.read(io, 5) - def test_read_with_with_offset - hello_world_tempfile do |io| - buffer = IO::Buffer.new(128) - buffer.read(io, nil, 6) - assert_equal "Hello", buffer.get_string(6, 5) - end + assert_equal "Hello", buffer.get_string(0, 5) + ensure + io.close! end def test_write @@ -408,7 +321,7 @@ class TestIOBuffer < Test::Unit::TestCase buffer = IO::Buffer.new(128) buffer.set_string("Hello") - buffer.write(io) + buffer.write(io, 5) io.seek(0) assert_equal "Hello", io.read(5) @@ -422,7 +335,7 @@ class TestIOBuffer < Test::Unit::TestCase io.seek(0) buffer = IO::Buffer.new(128) - buffer.pread(io, 6, 5) + buffer.pread(io, 5, 6) assert_equal "World", buffer.get_string(0, 5) assert_equal 0, io.tell @@ -430,41 +343,12 @@ class TestIOBuffer < Test::Unit::TestCase io.close! end - def test_pread_offset - io = Tempfile.new - io.write("Hello World") - io.seek(0) - - buffer = IO::Buffer.new(128) - buffer.pread(io, 6, 5, 6) - - assert_equal "World", buffer.get_string(6, 5) - assert_equal 0, io.tell - ensure - io.close! - end - def test_pwrite io = Tempfile.new buffer = IO::Buffer.new(128) buffer.set_string("World") - buffer.pwrite(io, 6, 5) - - assert_equal 0, io.tell - - io.seek(6) - assert_equal "World", io.read(5) - ensure - io.close! - end - - def test_pwrite_offset - io = Tempfile.new - - buffer = IO::Buffer.new(128) - buffer.set_string("Hello World") - buffer.pwrite(io, 6, 5, 6) + buffer.pwrite(io, 5, 6) assert_equal 0, io.tell @@ -473,39 +357,4 @@ class TestIOBuffer < Test::Unit::TestCase ensure io.close! end - - def test_operators - source = IO::Buffer.for("1234123412") - mask = IO::Buffer.for("133\x00") - - assert_equal IO::Buffer.for("123\x00123\x0012"), (source & mask) - assert_equal IO::Buffer.for("1334133413"), (source | mask) - assert_equal IO::Buffer.for("\x00\x01\x004\x00\x01\x004\x00\x01"), (source ^ mask) - assert_equal IO::Buffer.for("\xce\xcd\xcc\xcb\xce\xcd\xcc\xcb\xce\xcd"), ~source - end - - def test_inplace_operators - source = IO::Buffer.for("1234123412") - mask = IO::Buffer.for("133\x00") - - assert_equal IO::Buffer.for("123\x00123\x0012"), source.dup.and!(mask) - assert_equal IO::Buffer.for("1334133413"), source.dup.or!(mask) - assert_equal IO::Buffer.for("\x00\x01\x004\x00\x01\x004\x00\x01"), source.dup.xor!(mask) - assert_equal IO::Buffer.for("\xce\xcd\xcc\xcb\xce\xcd\xcc\xcb\xce\xcd"), source.dup.not! - end - - def test_shared - message = "Hello World" - buffer = IO::Buffer.new(64, IO::Buffer::MAPPED | IO::Buffer::SHARED) - - pid = fork do - buffer.set_string(message) - end - - Process.wait(pid) - string = buffer.get_string(0, message.bytesize) - assert_equal message, string - rescue NotImplementedError - omit "Fork/shared memory is not supported." - end end diff --git a/test/ruby/test_io_m17n.rb b/test/ruby/test_io_m17n.rb index b01d627d92..27b16a2a36 100644 --- a/test/ruby/test_io_m17n.rb +++ b/test/ruby/test_io_m17n.rb @@ -1142,94 +1142,12 @@ EOT IO.pipe do |r, w| assert_nothing_raised(bug5567) do assert_warning(/Unsupported/, bug5567) {r.set_encoding("fffffffffffxx")} - w.puts("foo") - assert_equal("foo\n", r.gets) assert_warning(/Unsupported/, bug5567) {r.set_encoding("fffffffffffxx", "us-ascii")} - w.puts("bar") - assert_equal("bar\n", r.gets) assert_warning(/Unsupported/, bug5567) {r.set_encoding("us-ascii", "fffffffffffxx")} - w.puts("zot") - begin - assert_equal("zot\n", r.gets) - rescue Encoding::ConverterNotFoundError => e - assert_match(/\((\S+) to \1\)/, e.message) - end end end end - def test_set_encoding_argument_parsing - File.open(File::NULL) do |f| - f.set_encoding('binary') - assert_equal(Encoding::ASCII_8BIT, f.external_encoding) - end - - File.open(File::NULL) do |f| - f.set_encoding(Encoding.find('binary')) - assert_equal(Encoding::ASCII_8BIT, f.external_encoding) - end - - File.open(File::NULL) do |f| - f.set_encoding('binary:utf-8') - assert_equal(nil, f.internal_encoding) - assert_equal(Encoding::ASCII_8BIT, f.external_encoding) - end - - File.open(File::NULL) do |f| - f.set_encoding('binary', 'utf-8') - assert_equal(nil, f.internal_encoding) - assert_equal(Encoding::ASCII_8BIT, f.external_encoding) - end - - File.open(File::NULL) do |f| - f.set_encoding(Encoding.find('binary'), Encoding.find('utf-8')) - assert_equal(nil, f.internal_encoding) - assert_equal(Encoding::ASCII_8BIT, f.external_encoding) - end - - File.open(File::NULL) do |f| - f.set_encoding('binary', Encoding.find('utf-8')) - assert_equal(nil, f.internal_encoding) - assert_equal(Encoding::ASCII_8BIT, f.external_encoding) - end - - File.open(File::NULL) do |f| - f.set_encoding(Encoding.find('binary'), 'utf-8') - assert_equal(nil, f.internal_encoding) - assert_equal(Encoding::ASCII_8BIT, f.external_encoding) - end - - File.open(File::NULL) do |f| - f.set_encoding('iso-8859-1:utf-8') - assert_equal(Encoding::UTF_8, f.internal_encoding) - assert_equal(Encoding::ISO_8859_1, f.external_encoding) - end - - File.open(File::NULL) do |f| - f.set_encoding('iso-8859-1', 'utf-8') - assert_equal(Encoding::UTF_8, f.internal_encoding) - assert_equal(Encoding::ISO_8859_1, f.external_encoding) - end - - File.open(File::NULL) do |f| - f.set_encoding(Encoding.find('iso-8859-1'), Encoding.find('utf-8')) - assert_equal(Encoding::UTF_8, f.internal_encoding) - assert_equal(Encoding::ISO_8859_1, f.external_encoding) - end - - File.open(File::NULL) do |f| - f.set_encoding('iso-8859-1', Encoding.find('utf-8')) - assert_equal(Encoding::UTF_8, f.internal_encoding) - assert_equal(Encoding::ISO_8859_1, f.external_encoding) - end - - File.open(File::NULL) do |f| - f.set_encoding(Encoding.find('iso-8859-1'), 'utf-8') - assert_equal(Encoding::UTF_8, f.internal_encoding) - assert_equal(Encoding::ISO_8859_1, f.external_encoding) - end - end - def test_textmode_twice assert_raise(ArgumentError) { open(__FILE__, "rt", textmode: true) {|f| @@ -1396,27 +1314,23 @@ EOT end def test_open_pipe_r_enc - EnvUtil.suppress_warning do # https://bugs.ruby-lang.org/issues/19630 - open("|#{EnvUtil.rubybin} -e 'putc 255'", "r:ascii-8bit") {|f| - assert_equal(Encoding::ASCII_8BIT, f.external_encoding) - assert_equal(nil, f.internal_encoding) - s = f.read - assert_equal(Encoding::ASCII_8BIT, s.encoding) - assert_equal("\xff".force_encoding("ascii-8bit"), s) - } - end + open("|#{EnvUtil.rubybin} -e 'putc 255'", "r:ascii-8bit") {|f| + assert_equal(Encoding::ASCII_8BIT, f.external_encoding) + assert_equal(nil, f.internal_encoding) + s = f.read + assert_equal(Encoding::ASCII_8BIT, s.encoding) + assert_equal("\xff".force_encoding("ascii-8bit"), s) + } end def test_open_pipe_r_enc2 - EnvUtil.suppress_warning do # https://bugs.ruby-lang.org/issues/19630 - open("|#{EnvUtil.rubybin} -e 'putc \"\\u3042\"'", "r:UTF-8") {|f| - assert_equal(Encoding::UTF_8, f.external_encoding) - assert_equal(nil, f.internal_encoding) - s = f.read - assert_equal(Encoding::UTF_8, s.encoding) - assert_equal("\u3042", s) - } - end + open("|#{EnvUtil.rubybin} -e 'putc \"\\u3042\"'", "r:UTF-8") {|f| + assert_equal(Encoding::UTF_8, f.external_encoding) + assert_equal(nil, f.internal_encoding) + s = f.read + assert_equal(Encoding::UTF_8, s.encoding) + assert_equal("\u3042", s) + } end def test_s_foreach_enc diff --git a/test/ruby/test_io_timeout.rb b/test/ruby/test_io_timeout.rb deleted file mode 100644 index e017395980..0000000000 --- a/test/ruby/test_io_timeout.rb +++ /dev/null @@ -1,58 +0,0 @@ -# frozen_string_literal: false - -require 'io/nonblock' - -class TestIOTimeout < Test::Unit::TestCase - def with_pipe - omit "UNIXSocket is not defined!" unless defined?(UNIXSocket) - - begin - i, o = UNIXSocket.pair - - yield i, o - ensure - i.close - o.close - end - end - - def test_timeout_attribute - with_pipe do |i, o| - assert_nil i.timeout - - i.timeout = 10 - assert_equal 10, i.timeout - assert_nil o.timeout - - o.timeout = 20 - assert_equal 20, o.timeout - assert_equal 10, i.timeout - end - end - - def test_timeout_read_exception - with_pipe do |i, o| - i.timeout = 0.0001 - - assert_raise(IO::TimeoutError) {i.read} - end - end - - def test_timeout_gets_exception - with_pipe do |i, o| - i.timeout = 0.0001 - - assert_raise(IO::TimeoutError) {i.gets} - end - end - - def test_timeout_puts - with_pipe do |i, o| - i.timeout = 0.0001 - o.puts("Hello World") - o.close - - assert_equal "Hello World", i.gets.chomp - end - end -end diff --git a/test/ruby/test_iseq.rb b/test/ruby/test_iseq.rb index 80fe9b0f06..f01d36cc5a 100644 --- a/test/ruby/test_iseq.rb +++ b/test/ruby/test_iseq.rb @@ -162,7 +162,7 @@ class TestISeq < Test::Unit::TestCase end obj = Object.new def obj.foo(*) nil.instance_eval{ ->{super} } end - assert_raise_with_message(Ractor::IsolationError, /refer unshareable object \[\] from variable `\*'/) do + assert_raise_with_message(Ractor::IsolationError, /hidden variable/) do Ractor.make_shareable(obj.foo) end end @@ -355,13 +355,6 @@ class TestISeq < Test::Unit::TestCase end end - # [Bug #19173] - def test_compile_error - assert_raise SyntaxError do - RubyVM::InstructionSequence.compile 'using Module.new; yield' - end - end - def test_compile_file_error Tempfile.create(%w"test_iseq .rb") do |f| f.puts "end" @@ -399,18 +392,10 @@ class TestISeq < Test::Unit::TestCase def anon_star(*); end - def test_anon_rest_param_in_disasm + def test_anon_param_in_disasm iseq = RubyVM::InstructionSequence.of(method(:anon_star)) param_names = iseq.to_a[iseq.to_a.index(:method) + 1] - assert_equal [:*], param_names - end - - def anon_keyrest(**); end - - def test_anon_keyrest_param_in_disasm - iseq = RubyVM::InstructionSequence.of(method(:anon_keyrest)) - param_names = iseq.to_a[iseq.to_a.index(:method) + 1] - assert_equal [:**], param_names + assert_equal [2], param_names end def anon_block(&); end @@ -497,8 +482,7 @@ class TestISeq < Test::Unit::TestCase [7, :line], [9, :return]]], [["ensure in foo@2", [[7, :line]]]], - [["rescue in foo@4", [[5, :line], - [5, :rescue]]]]]], + [["rescue in foo@4", [[5, :line]]]]]], [["<class:D>@17", [[17, :class], [18, :end]]]]], collect_iseq.call(sample_iseq) end @@ -547,7 +531,7 @@ class TestISeq < Test::Unit::TestCase bin = assert_nothing_raised(mesg) do iseq.to_binary rescue RuntimeError => e - omit e.message if /compile with coverage/ =~ e.message + skip e.message if /compile with coverage/ =~ e.message raise end 10.times do @@ -638,8 +622,6 @@ class TestISeq < Test::Unit::TestCase } lines - ensure - Object.send(:remove_const, :A) rescue nil end def test_to_binary_line_tracepoint @@ -760,25 +742,4 @@ class TestISeq < Test::Unit::TestCase assert_equal :new, r.take RUBY end - - def test_ever_condition_loop - assert_ruby_status([], "BEGIN {exit}; while true && true; end") - end - - def test_unreachable_syntax_error - mesg = /Invalid break/ - assert_syntax_error("false and break", mesg) - assert_syntax_error("if false and break; end", mesg) - end - - def test_unreachable_pattern_matching - assert_in_out_err([], "#{<<~"begin;"}\n#{<<~'end;'}", %w[1]) - begin; - if true or {a: 0} in {a:} - p 1 - else - p a - end - end; - end end diff --git a/test/ruby/test_jit.rb b/test/ruby/test_jit.rb new file mode 100644 index 0000000000..07ac76210d --- /dev/null +++ b/test/ruby/test_jit.rb @@ -0,0 +1,1273 @@ +# frozen_string_literal: true +require 'test/unit' +require 'tmpdir' +require_relative '../lib/jit_support' + +# Test for --jit option +class TestJIT < Test::Unit::TestCase + include JITSupport + + IGNORABLE_PATTERNS = [ + /\AJIT recompile: .+\n\z/, + /\AJIT inline: .+\n\z/, + /\AJIT cancel: .+\n\z/, + /\ASuccessful MJIT finish\n\z/, + ] + MAX_CACHE_PATTERNS = [ + /\AJIT compaction \([^)]+\): .+\n\z/, + /\AToo many JIT code, but skipped unloading units for JIT compaction\n\z/, + /\ANo units can be unloaded -- .+\n\z/, + ] + + # trace_* insns are not compiled for now... + TEST_PENDING_INSNS = RubyVM::INSTRUCTION_NAMES.select { |n| n.start_with?('trace_') }.map(&:to_sym) + [ + # not supported yet + :defineclass, + + # to be tested + :invokebuiltin, + + # never used + :opt_invokebuiltin_delegate, + ].each do |insn| + if !RubyVM::INSTRUCTION_NAMES.include?(insn.to_s) + warn "instruction #{insn.inspect} is not defined but included in TestJIT::TEST_PENDING_INSNS" + end + end + + def self.untested_insns + @untested_insns ||= (RubyVM::INSTRUCTION_NAMES.map(&:to_sym) - TEST_PENDING_INSNS) + end + + def self.setup + return if defined?(@setup_hooked) + @setup_hooked = true + + # ci.rvm.jp caches its build environment. Clean up temporary files left by SEGV. + if ENV['RUBY_DEBUG']&.include?('ci') + Dir.glob("#{ENV.fetch('TMPDIR', '/tmp')}/_ruby_mjit_p*u*.*").each do |file| + puts "test/ruby/test_jit.rb: removing #{file}" + File.unlink(file) + end + end + + # ruby -w -Itest/lib test/ruby/test_jit.rb + if $VERBOSE + pid = $$ + at_exit do + if pid == $$ && !TestJIT.untested_insns.empty? + warn "you may want to add tests for following insns, when you have a chance: #{TestJIT.untested_insns.join(' ')}" + end + end + end + end + + def setup + unless JITSupport.supported? + skip 'JIT seems not supported on this platform' + end + self.class.setup + end + + def test_compile_insn_nop + assert_compile_once('nil rescue true', result_inspect: 'nil', insns: %i[nop]) + end + + def test_compile_insn_local + assert_compile_once("#{<<~"begin;"}\n#{<<~"end;"}", result_inspect: '1', insns: %i[setlocal_WC_0 getlocal_WC_0]) + begin; + foo = 1 + foo + end; + + insns = %i[setlocal getlocal setlocal_WC_0 getlocal_WC_0 setlocal_WC_1 getlocal_WC_1] + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", success_count: 3, stdout: '168', insns: insns) + begin; + def foo + a = 0 + [1, 2].each do |i| + a += i + [3, 4].each do |j| + a *= j + end + end + a + end + + print foo + end; + end + + def test_compile_insn_blockparam + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: '3', success_count: 2, insns: %i[getblockparam setblockparam]) + begin; + def foo(&b) + a = b + b = 2 + a.call + 2 + end + + print foo { 1 } + end; + end + + def test_compile_insn_getblockparamproxy + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: '4', success_count: 3, insns: %i[getblockparamproxy]) + begin; + def bar(&b) + b.call + end + + def foo(&b) + bar(&b) * bar(&b) + end + + print foo { 2 } + end; + end + + def test_compile_insn_getspecial + assert_compile_once('$1', result_inspect: 'nil', insns: %i[getspecial]) + end + + def test_compile_insn_setspecial + assert_compile_once("#{<<~"begin;"}\n#{<<~"end;"}", result_inspect: 'true', insns: %i[setspecial]) + begin; + true if nil.nil?..nil.nil? + end; + end + + def test_compile_insn_instancevariable + assert_compile_once("#{<<~"begin;"}\n#{<<~"end;"}", result_inspect: '1', insns: %i[getinstancevariable setinstancevariable]) + begin; + @foo = 1 + @foo + end; + + # optimized getinstancevariable call + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: '33', success_count: 1, min_calls: 2) + begin; + class A + def initialize + @a = 1 + @b = 2 + end + + def three + @a + @b + end + end + + a = A.new + print(a.three) # set ic + print(a.three) # inlined ic + end; + end + + def test_compile_insn_classvariable + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: '1', success_count: 1, insns: %i[getclassvariable setclassvariable]) + begin; + class Foo + def self.foo + @@foo = 1 + @@foo + end + end + + print Foo.foo + end; + end + + def test_compile_insn_constant + assert_compile_once("#{<<~"begin;"}\n#{<<~"end;"}", result_inspect: '1', insns: %i[getconstant setconstant]) + begin; + FOO = 1 + FOO + end; + end + + def test_compile_insn_global + assert_compile_once("#{<<~"begin;"}\n#{<<~"end;"}", result_inspect: '1', insns: %i[getglobal setglobal]) + begin; + $foo = 1 + $foo + end; + end + + def test_compile_insn_putnil + assert_compile_once('nil', result_inspect: 'nil', insns: %i[putnil]) + end + + def test_compile_insn_putself + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: 'hello', success_count: 1, insns: %i[putself]) + begin; + proc { print "hello" }.call + end; + end + + def test_compile_insn_putobject + assert_compile_once('0', result_inspect: '0', insns: %i[putobject_INT2FIX_0_]) + assert_compile_once('1', result_inspect: '1', insns: %i[putobject_INT2FIX_1_]) + assert_compile_once('2', result_inspect: '2', insns: %i[putobject]) + end + + def test_compile_insn_definemethod_definesmethod + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: 'helloworld', success_count: 3, insns: %i[definemethod definesmethod]) + begin; + print 1.times.map { + def method_definition + 'hello' + end + + def self.smethod_definition + 'world' + end + + method_definition + smethod_definition + }.join + end; + end + + def test_compile_insn_putspecialobject + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: 'a', success_count: 2, insns: %i[putspecialobject]) + begin; + print 1.times.map { + def a + 'a' + end + + alias :b :a + + b + }.join + end; + end + + def test_compile_insn_putstring_concatstrings_objtostring + assert_compile_once('"a#{}b" + "c"', result_inspect: '"abc"', insns: %i[putstring concatstrings objtostring]) + end + + def test_compile_insn_toregexp + assert_compile_once('/#{true}/ =~ "true"', result_inspect: '0', insns: %i[toregexp]) + end + + def test_compile_insn_newarray + assert_compile_once("#{<<~"begin;"}\n#{<<~"end;"}", result_inspect: '[1, 2, 3]', insns: %i[newarray]) + begin; + a, b, c = 1, 2, 3 + [a, b, c] + end; + end + + def test_compile_insn_newarraykwsplat + assert_compile_once('[**{ x: 1 }]', result_inspect: '[{:x=>1}]', insns: %i[newarraykwsplat]) + end + + def test_compile_insn_intern_duparray + assert_compile_once('[:"#{0}"] + [1,2,3]', result_inspect: '[:"0", 1, 2, 3]', insns: %i[intern duparray]) + end + + def test_compile_insn_expandarray + assert_compile_once('y = [ true, false, nil ]; x, = y; x', result_inspect: 'true', insns: %i[expandarray]) + end + + def test_compile_insn_concatarray + assert_compile_once('["t", "r", *x = "u", "e"].join', result_inspect: '"true"', insns: %i[concatarray]) + end + + def test_compile_insn_splatarray + assert_compile_once('[*(1..2)]', result_inspect: '[1, 2]', insns: %i[splatarray]) + end + + def test_compile_insn_newhash + assert_compile_once('a = 1; { a: a }', result_inspect: '{:a=>1}', insns: %i[newhash]) + end + + def test_compile_insn_duphash + assert_compile_once('{ a: 1 }', result_inspect: '{:a=>1}', insns: %i[duphash]) + end + + def test_compile_insn_newrange + assert_compile_once('a = 1; 0..a', result_inspect: '0..1', insns: %i[newrange]) + end + + def test_compile_insn_pop + assert_compile_once("#{<<~"begin;"}\n#{<<~"end;"}", result_inspect: '1', insns: %i[pop]) + begin; + a = false + b = 1 + a || b + end; + end + + def test_compile_insn_dup + assert_compile_once("#{<<~"begin;"}\n#{<<~"end;"}", result_inspect: '3', insns: %i[dup]) + begin; + a = 1 + a&.+(2) + end; + end + + def test_compile_insn_dupn + assert_compile_once("#{<<~"begin;"}\n#{<<~"end;"}", result_inspect: 'true', insns: %i[dupn]) + begin; + klass = Class.new + klass::X ||= true + end; + end + + def test_compile_insn_swap_topn + assert_compile_once('{}["true"] = true', result_inspect: 'true', insns: %i[swap topn]) + end + + def test_compile_insn_reput + skip "write test" + end + + def test_compile_insn_setn + assert_compile_once('[nil][0] = 1', result_inspect: '1', insns: %i[setn]) + end + + def test_compile_insn_adjuststack + assert_compile_once("#{<<~"begin;"}\n#{<<~"end;"}", result_inspect: 'true', insns: %i[adjuststack]) + begin; + x = [true] + x[0] ||= nil + x[0] + end; + end + + def test_compile_insn_defined + assert_compile_once('defined?(a)', result_inspect: 'nil', insns: %i[defined]) + end + + def test_compile_insn_checkkeyword + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: 'true', success_count: 1, insns: %i[checkkeyword]) + begin; + def test(x: rand) + x + end + print test(x: true) + end; + end + + def test_compile_insn_tracecoverage + skip "write test" + end + + def test_compile_insn_defineclass + skip "support this in mjit_compile (low priority)" + end + + def test_compile_insn_send + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: '1', success_count: 3, insns: %i[send]) + begin; + print proc { yield_self { 1 } }.call + end; + end + + def test_compile_insn_opt_str_freeze + assert_compile_once("#{<<~"begin;"}\n#{<<~"end;"}", result_inspect: '"foo"', insns: %i[opt_str_freeze]) + begin; + 'foo'.freeze + end; + end + + def test_compile_insn_opt_nil_p + assert_compile_once("#{<<~"begin;"}\n#{<<~"end;"}", result_inspect: 'false', insns: %i[opt_nil_p]) + begin; + nil.nil?.nil? + end; + end + + def test_compile_insn_opt_str_uminus + assert_compile_once("#{<<~"begin;"}\n#{<<~"end;"}", result_inspect: '"bar"', insns: %i[opt_str_uminus]) + begin; + -'bar' + end; + end + + def test_compile_insn_opt_newarray_max + assert_compile_once("#{<<~"begin;"}\n#{<<~"end;"}", result_inspect: '2', insns: %i[opt_newarray_max]) + begin; + a = 1 + b = 2 + [a, b].max + end; + end + + def test_compile_insn_opt_newarray_min + assert_compile_once("#{<<~"begin;"}\n#{<<~"end;"}", result_inspect: '1', insns: %i[opt_newarray_min]) + begin; + a = 1 + b = 2 + [a, b].min + end; + end + + def test_compile_insn_opt_send_without_block + assert_compile_once('print', result_inspect: 'nil', insns: %i[opt_send_without_block]) + end + + def test_compile_insn_invokesuper + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: '3', success_count: 4, insns: %i[invokesuper]) + begin; + mod = Module.new { + def test + super + 2 + end + } + klass = Class.new { + prepend mod + def test + 1 + end + } + print klass.new.test + end; + end + + def test_compile_insn_invokeblock_leave + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: '2', success_count: 2, insns: %i[invokeblock leave]) + begin; + def foo + yield + end + print foo { 2 } + end; + end + + def test_compile_insn_throw + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: '4', success_count: 2, insns: %i[throw]) + begin; + def test + proc do + if 1+1 == 1 + return 3 + else + return 4 + end + 5 + end.call + end + print test + end; + end + + def test_compile_insn_jump_branchif + assert_compile_once("#{<<~"begin;"}\n#{<<~'end;'}", result_inspect: 'nil', insns: %i[jump branchif]) + begin; + a = false + 1 + 1 while a + end; + end + + def test_compile_insn_branchunless + assert_compile_once("#{<<~"begin;"}\n#{<<~'end;'}", result_inspect: '1', insns: %i[branchunless]) + begin; + a = true + if a + 1 + else + 2 + end + end; + end + + def test_compile_insn_branchnil + assert_compile_once("#{<<~"begin;"}\n#{<<~'end;'}", result_inspect: '3', insns: %i[branchnil]) + begin; + a = 2 + a&.+(1) + end; + end + + def test_compile_insn_objtostring + assert_compile_once("#{<<~"begin;"}\n#{<<~'end;'}", result_inspect: '"42"', insns: %i[objtostring]) + begin; + a = '2' + "4#{a}" + end; + end + + def test_compile_insn_inlinecache + assert_compile_once('Struct', result_inspect: 'Struct', insns: %i[opt_getinlinecache opt_setinlinecache]) + end + + def test_compile_insn_once + assert_compile_once('/#{true}/o =~ "true" && $~.to_a', result_inspect: '["true"]', insns: %i[once]) + end + + def test_compile_insn_checkmatch_opt_case_dispatch + assert_compile_once("#{<<~"begin;"}\n#{<<~"end;"}", result_inspect: '"world"', insns: %i[opt_case_dispatch]) + begin; + case 'hello' + when 'hello' + 'world' + end + end; + end + + def test_compile_insn_opt_calc + assert_compile_once('4 + 2 - ((2 * 3 / 2) % 2)', result_inspect: '5', insns: %i[opt_plus opt_minus opt_mult opt_div opt_mod]) + assert_compile_once('4.0 + 2.0 - ((2.0 * 3.0 / 2.0) % 2.0)', result_inspect: '5.0', insns: %i[opt_plus opt_minus opt_mult opt_div opt_mod]) + assert_compile_once('4 + 2', result_inspect: '6') + end + + def test_compile_insn_opt_cmp + assert_compile_once('(1 == 1) && (1 != 2)', result_inspect: 'true', insns: %i[opt_eq opt_neq]) + end + + def test_compile_insn_opt_rel + assert_compile_once('1 < 2 && 1 <= 1 && 2 > 1 && 1 >= 1', result_inspect: 'true', insns: %i[opt_lt opt_le opt_gt opt_ge]) + end + + def test_compile_insn_opt_ltlt + assert_compile_once('[1] << 2', result_inspect: '[1, 2]', insns: %i[opt_ltlt]) + end + + def test_compile_insn_opt_and + assert_compile_once('1 & 3', result_inspect: '1', insns: %i[opt_and]) + end + + def test_compile_insn_opt_or + assert_compile_once('1 | 3', result_inspect: '3', insns: %i[opt_or]) + end + + def test_compile_insn_opt_aref + # optimized call (optimized JIT) -> send call + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: '21', success_count: 2, min_calls: 1, insns: %i[opt_aref]) + begin; + obj = Object.new + def obj.[](h) + h + end + + block = proc { |h| h[1] } + print block.call({ 1 => 2 }) + print block.call(obj) + end; + + # send call -> optimized call (send JIT) -> optimized call + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: '122', success_count: 2, min_calls: 2) + begin; + obj = Object.new + def obj.[](h) + h + end + + block = proc { |h| h[1] } + print block.call(obj) + print block.call({ 1 => 2 }) + print block.call({ 1 => 2 }) + end; + end + + def test_compile_insn_opt_aref_with + assert_compile_once("{ '1' => 2 }['1']", result_inspect: '2', insns: %i[opt_aref_with]) + end + + def test_compile_insn_opt_aset + assert_compile_once("#{<<~"begin;"}\n#{<<~"end;"}", result_inspect: '5', insns: %i[opt_aset opt_aset_with]) + begin; + hash = { '1' => 2 } + (hash['2'] = 2) + (hash[1.to_s] = 3) + end; + end + + def test_compile_insn_opt_length_size + assert_compile_once("#{<<~"begin;"}\n#{<<~"end;"}", result_inspect: '4', insns: %i[opt_length opt_size]) + begin; + array = [1, 2] + array.length + array.size + end; + end + + def test_compile_insn_opt_empty_p + assert_compile_once('[].empty?', result_inspect: 'true', insns: %i[opt_empty_p]) + end + + def test_compile_insn_opt_succ + assert_compile_once('1.succ', result_inspect: '2', insns: %i[opt_succ]) + end + + def test_compile_insn_opt_not + assert_compile_once('!!true', result_inspect: 'true', insns: %i[opt_not]) + end + + def test_compile_insn_opt_regexpmatch2 + assert_compile_once("/true/ =~ 'true'", result_inspect: '0', insns: %i[opt_regexpmatch2]) + assert_compile_once("'true' =~ /true/", result_inspect: '0', insns: %i[opt_regexpmatch2]) + end + + def test_compile_insn_opt_invokebuiltin_delegate_leave + iseq = eval(EnvUtil.invoke_ruby(['-e', <<~'EOS'], '', true).first) + p RubyVM::InstructionSequence.of("\x00".method(:unpack)).to_a + EOS + insns = collect_insns(iseq) + mark_tested_insn(:opt_invokebuiltin_delegate_leave, used_insns: insns) + assert_eval_with_jit('print "\x00".unpack("c")', stdout: '[0]', success_count: 1) + end + + def test_compile_insn_checkmatch + assert_compile_once("#{<<~"begin;"}\n#{<<~"end;"}", result_inspect: '"world"', insns: %i[checkmatch]) + begin; + ary = %w(hello good-bye) + case 'hello' + when *ary + 'world' + end + end; + end + + def test_jit_output + out, err = eval_with_jit('5.times { puts "MJIT" }', verbose: 1, min_calls: 5) + assert_equal("MJIT\n" * 5, out) + assert_match(/^#{JIT_SUCCESS_PREFIX}: block in <main>@-e:1 -> .+_ruby_mjit_p\d+u\d+\.c$/, err) + assert_match(/^Successful MJIT finish$/, err) + end + + def test_nothing_to_unload_with_jit_wait + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: 'hello', success_count: 11, max_cache: 10, ignorable_patterns: MAX_CACHE_PATTERNS) + begin; + def a1() a2() end + def a2() a3() end + def a3() a4() end + def a4() a5() end + def a5() a6() end + def a6() a7() end + def a7() a8() end + def a8() a9() end + def a9() a10() end + def a10() a11() end + def a11() print('hello') end + a1 + end; + end + + def test_unload_units_on_fiber + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: 'hello', success_count: 12, max_cache: 10, ignorable_patterns: MAX_CACHE_PATTERNS) + begin; + def a1() a2(false); a2(true) end + def a2(a) a3(a) end + def a3(a) a4(a) end + def a4(a) a5(a) end + def a5(a) a6(a) end + def a6(a) a7(a) end + def a7(a) a8(a) end + def a8(a) a9(a) end + def a9(a) a10(a) end + def a10(a) + if a + Fiber.new { a11 }.resume + end + end + def a11() print('hello') end + a1 + end; + end + + def test_unload_units_and_compaction + Dir.mktmpdir("jit_test_unload_units_") do |dir| + # MIN_CACHE_SIZE is 10 + out, err = eval_with_jit({"TMPDIR"=>dir}, "#{<<~"begin;"}\n#{<<~'end;'}", verbose: 1, min_calls: 1, max_cache: 10) + begin; + i = 0 + while i < 11 + eval(<<-EOS) + def mjit#{i} + print #{i} + end + mjit#{i} + EOS + i += 1 + end + + if defined?(fork) + # test the child does not try to delete files which are deleted by parent, + # and test possible deadlock on fork during MJIT unload and JIT compaction on child + Process.waitpid(Process.fork {}) + end + end; + + debug_info = %Q[stdout:\n"""\n#{out}\n"""\n\nstderr:\n"""\n#{err}"""\n] + assert_equal('012345678910', out, debug_info) + compactions, errs = err.lines.partition do |l| + l.match?(/\AJIT compaction \(\d+\.\dms\): Compacted \d+ methods /) + end + 10.times do |i| + assert_match(/\A#{JIT_SUCCESS_PREFIX}: mjit#{i}@\(eval\):/, errs[i], debug_info) + end + + assert_equal("No units can be unloaded -- incremented max-cache-size to 11 for --jit-wait\n", errs[10], debug_info) + assert_match(/\A#{JIT_SUCCESS_PREFIX}: mjit10@\(eval\):/, errs[11], debug_info) + # On --jit-wait, when the number of JIT-ed code reaches --jit-max-cache, + # it should trigger compaction. + unless RUBY_PLATFORM.match?(/mswin|mingw/) # compaction is not supported on Windows yet + assert_equal(1, compactions.size, debug_info) + end + + if RUBY_PLATFORM.match?(/mswin/) + # "Permission Denied" error is preventing to remove so file on AppVeyor/RubyCI. + skip 'Removing so file is randomly failing on AppVeyor/RubyCI mswin due to Permission Denied.' + else + # verify .c files are deleted on unload_units + assert_send([Dir, :empty?, dir], debug_info) + end + end + end + + def test_newarraykwsplat_on_stack + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: "[nil, [{:type=>:development}]]\n", success_count: 1, insns: %i[newarraykwsplat]) + begin; + def arr + [nil, [:type => :development]] + end + p arr + end; + end + + def test_local_stack_on_exception + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: '3', success_count: 2) + begin; + def b + raise + rescue + 2 + end + + def a + # Calling #b should be vm_exec, not direct mjit_exec. + # Otherwise `1` on local variable would be purged. + 1 + b + end + + print a + end; + end + + def test_local_stack_with_sp_motion_by_blockargs + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: '1', success_count: 2) + begin; + def b(base) + 1 + end + + # This method is simple enough to have false in catch_except_p. + # So local_stack_p would be true in JIT compiler. + def a + m = method(:b) + + # ci->flag has VM_CALL_ARGS_BLOCKARG and cfp->sp is moved in vm_caller_setup_arg_block. + # So, for this send insn, JIT-ed code should use cfp->sp instead of local variables for stack. + Module.module_eval(&m) + end + + print a + end; + end + + def test_catching_deep_exception + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: '1', success_count: 4) + begin; + def catch_true(paths, prefixes) # catch_except_p: TRUE + prefixes.each do |prefix| # catch_except_p: TRUE + paths.each do |path| # catch_except_p: FALSE + return path + end + end + end + + def wrapper(paths, prefixes) + catch_true(paths, prefixes) + end + + print wrapper(['1'], ['2']) + end; + end + + def test_inlined_builtin_methods + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: '', success_count: 1, min_calls: 2) + begin; + def test + float = 0.0 + float.abs + float.-@ + float.zero? + end + test + test + end; + end + + def test_inlined_c_method + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: "aaa", success_count: 2, recompile_count: 1, min_calls: 2) + begin; + def test(obj, recursive: nil) + if recursive + test(recursive) + end + obj.to_s + end + + print(test('a')) # set #to_s cc to String#to_s (expecting C method) + print(test('a')) # JIT with #to_s cc: String#to_s + # update #to_s cd->cc to Symbol#to_s, then go through the Symbol#to_s cd->cc + # after checking receiver class using inlined #to_s cc with String#to_s. + print(test('a', recursive: :foo)) + end; + end + + def test_inlined_exivar + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: "aaa", success_count: 3, recompile_count: 1, min_calls: 2) + begin; + class Foo < Hash + def initialize + @a = :a + end + + def bar + @a + end + end + + print(Foo.new.bar) + print(Foo.new.bar) # compile #initialize, #bar -> recompile #bar + print(Foo.new.bar) # compile #bar with exivar + end; + end + + def test_inlined_undefined_ivar + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: "bbb", success_count: 3, min_calls: 3) + begin; + class Foo + def initialize + @a = :a + end + + def bar + if @b.nil? + @b = :b + end + end + end + + print(Foo.new.bar) + print(Foo.new.bar) + print(Foo.new.bar) + end; + end + + def test_inlined_setivar_frozen + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: "FrozenError\n", success_count: 2, min_calls: 3) + begin; + class A + def a + @a = 1 + end + end + + a = A.new + a.a + a.a + a.a + a.freeze + begin + a.a + rescue FrozenError => e + p e.class + end + end; + end + + def test_inlined_getconstant + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: '11', success_count: 1, min_calls: 2) + begin; + FOO = 1 + def const + FOO + end + print const + print const + end; + end + + def test_attr_reader + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: "4nil\nnil\n6", success_count: 2, min_calls: 2) + begin; + class A + attr_reader :a, :b + + def initialize + @a = 2 + end + + def test + a + end + + def undefined + b + end + end + + a = A.new + print(a.test * a.test) + p(a.undefined) + p(a.undefined) + + # redefinition + def a.test + 3 + end + + print(2 * a.test) + end; + + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: "true", success_count: 1, min_calls: 2) + begin; + class Hoge + attr_reader :foo + + def initialize + @foo = [] + @bar = nil + end + end + + class Fuga < Hoge + def initialize + @bar = nil + @foo = [] + end + end + + def test(recv) + recv.foo.empty? + end + + hoge = Hoge.new + fuga = Fuga.new + + test(hoge) # VM: cc set index=1 + test(hoge) # JIT: compile with index=1 + test(fuga) # JIT -> VM: cc set index=2 + print test(hoge) # JIT: should use index=1, not index=2 in cc + end; + end + + def test_heap_promotion_of_ivar_in_the_middle_of_jit + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: "true\ntrue\n", success_count: 2, min_calls: 2) + begin; + class A + def initialize + @iv0 = nil + @iv1 = [] + @iv2 = nil + end + + def test(add) + @iv0.nil? + @iv2.nil? + add_ivar if add + @iv1.empty? + end + + def add_ivar + @iv3 = nil + end + end + + a = A.new + p a.test(false) + p a.test(true) + end; + end + + def test_jump_to_precompiled_branch + assert_eval_with_jit("#{<<~'begin;'}\n#{<<~'end;'}", stdout: ".0", success_count: 1, min_calls: 1) + begin; + def test(foo) + ".#{foo unless foo == 1}" if true + end + print test(0) + end; + end + + def test_clean_so + if RUBY_PLATFORM.match?(/mswin/) + skip 'Removing so file is randomly failing on AppVeyor/RubyCI mswin due to Permission Denied.' + end + Dir.mktmpdir("jit_test_clean_so_") do |dir| + code = "x = 0; 10.times {|i|x+=i}" + eval_with_jit({"TMPDIR"=>dir}, code) + assert_send([Dir, :empty?, dir]) + eval_with_jit({"TMPDIR"=>dir}, code, save_temps: true) + assert_not_send([Dir, :empty?, dir]) + end + end + + def test_clean_objects_on_exec + if /mswin|mingw/ =~ RUBY_PLATFORM + # TODO: check call stack and close handle of code which is not on stack, and remove objects on best-effort basis + skip 'Removing so file being used does not work on Windows' + end + Dir.mktmpdir("jit_test_clean_objects_on_exec_") do |dir| + eval_with_jit({"TMPDIR"=>dir}, "#{<<~"begin;"}\n#{<<~"end;"}", min_calls: 1) + begin; + def a; end; a + exec "true" + end; + error_message = "Undeleted files:\n #{Dir.glob("#{dir}/*").join("\n ")}\n" + assert_send([Dir, :empty?, dir], error_message) + end + end + + def test_lambda_longjmp + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: '5', success_count: 1) + begin; + fib = lambda do |x| + return x if x == 0 || x == 1 + fib.call(x-1) + fib.call(x-2) + end + print fib.call(5) + end; + end + + def test_stack_pointer_with_assignment + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: "nil\nnil\n", success_count: 1) + begin; + 2.times do + a, _ = nil + p a + end + end; + end + + def test_frame_omitted_inlining + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: "true\ntrue\ntrue\n", success_count: 1, min_calls: 2) + begin; + class Integer + remove_method :zero? + def zero? + self == 0 + end + end + + 3.times do + p 0.zero? + end + end; + end + + def test_block_handler_with_possible_frame_omitted_inlining + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: "70.0\n70.0\n70.0\n", success_count: 2, min_calls: 2) + begin; + def multiply(a, b) + a *= b + end + + 3.times do + p multiply(7.0, 10.0) + end + end; + end + + def test_builtin_frame_omitted_inlining + assert_eval_with_jit('0.zero?; 0.zero?; 3.times { p 0.zero? }', stdout: "true\ntrue\ntrue\n", success_count: 1, min_calls: 2) + end + + def test_program_counter_with_regexpmatch + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: "aa", success_count: 1) + begin; + 2.times do + break if /a/ =~ "ab" && !$~[0] + print $~[0] + end + end; + end + + def test_pushed_values_with_opt_aset_with + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: "{}{}", success_count: 1) + begin; + 2.times do + print(Thread.current["a"] = {}) + end + end; + end + + def test_pushed_values_with_opt_aref_with + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: "nil\nnil\n", success_count: 1) + begin; + 2.times do + p(Thread.current["a"]) + end + end; + end + + def test_mjit_pause_wait + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: '', success_count: 0, min_calls: 1) + begin; + RubyVM::MJIT.pause + proc {}.call + end; + end + + def test_not_cancel_by_tracepoint_class + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", success_count: 1, min_calls: 2) + begin; + TracePoint.new(:class) {}.enable + 2.times {} + end; + end + + def test_cancel_by_tracepoint + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", success_count: 0, min_calls: 2) + begin; + TracePoint.new(:line) {}.enable + 2.times {} + end; + end + + def test_caller_locations_without_catch_table + out, _ = eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", min_calls: 1) + begin; + def b # 2 + caller_locations.first # 3 + end # 4 + # 5 + def a # 6 + print # <-- don't leave PC here # 7 + b # 8 + end + puts a + puts a + end; + lines = out.lines + assert_equal("-e:8:in `a'\n", lines[0]) + assert_equal("-e:8:in `a'\n", lines[1]) + end + + def test_fork_with_mjit_worker_thread + Dir.mktmpdir("jit_test_fork_with_mjit_worker_thread_") do |dir| + # min_calls: 2 to skip fork block + out, err = eval_with_jit({ "TMPDIR" => dir }, "#{<<~"begin;"}\n#{<<~"end;"}", min_calls: 2, verbose: 1) + begin; + def before_fork; end + def after_fork; end + + before_fork; before_fork # the child should not delete this .o file + pid = Process.fork do # this child should not delete shared .pch file + sleep 2.0 # to prevent mixing outputs on Solaris + after_fork; after_fork # this child does not share JIT-ed after_fork with parent + end + after_fork; after_fork # this parent does not share JIT-ed after_fork with child + + Process.waitpid(pid) + end; + success_count = err.scan(/^#{JIT_SUCCESS_PREFIX}:/).size + debug_info = "stdout:\n```\n#{out}\n```\n\nstderr:\n```\n#{err}```\n" + assert_equal(3, success_count, debug_info) + + # assert no remove error + assert_equal("Successful MJIT finish\n" * 2, err.gsub(/^#{JIT_SUCCESS_PREFIX}:[^\n]+\n/, ''), debug_info) + + # ensure objects are deleted + assert_send([Dir, :empty?, dir], debug_info) + end + end if defined?(fork) + + private + + # The shortest way to test one proc + def assert_compile_once(script, result_inspect:, insns: [], uplevel: 1) + if script.match?(/\A\n.+\n\z/m) + script = script.gsub(/^/, ' ') + else + script = " #{script} " + end + assert_eval_with_jit("p proc {#{script}}.call", stdout: "#{result_inspect}\n", success_count: 1, insns: insns, uplevel: uplevel + 1) + end + + # Shorthand for normal test cases + def assert_eval_with_jit(script, stdout: nil, success_count:, recompile_count: nil, min_calls: 1, max_cache: 1000, insns: [], uplevel: 1, ignorable_patterns: []) + out, err = eval_with_jit(script, verbose: 1, min_calls: min_calls, max_cache: max_cache) + success_actual = err.scan(/^#{JIT_SUCCESS_PREFIX}:/).size + recompile_actual = err.scan(/^#{JIT_RECOMPILE_PREFIX}:/).size + # Add --mjit-verbose=2 logs for cl.exe because compiler's error message is suppressed + # for cl.exe with --mjit-verbose=1. See `start_process` in mjit_worker.c. + if RUBY_PLATFORM.match?(/mswin/) && success_count != success_actual + out2, err2 = eval_with_jit(script, verbose: 2, min_calls: min_calls, max_cache: max_cache) + end + + # Make sure that the script has insns expected to be tested + used_insns = method_insns(script) + insns.each do |insn| + mark_tested_insn(insn, used_insns: used_insns, uplevel: uplevel + 3) + end + + suffix = "script:\n#{code_block(script)}\nstderr:\n#{code_block(err)}#{( + "\nstdout(verbose=2 retry):\n#{code_block(out2)}\nstderr(verbose=2 retry):\n#{code_block(err2)}" if out2 || err2 + )}" + assert_equal( + success_count, success_actual, + "Expected #{success_count} times of JIT success, but succeeded #{success_actual} times.\n\n#{suffix}", + ) + if recompile_count + assert_equal( + recompile_count, recompile_actual, + "Expected #{success_count} times of JIT recompile, but recompiled #{success_actual} times.\n\n#{suffix}", + ) + end + if stdout + assert_equal(stdout, out, "Expected stdout #{out.inspect} to match #{stdout.inspect} with script:\n#{code_block(script)}") + end + err_lines = err.lines.reject! do |l| + l.chomp.empty? || l.match?(/\A#{JIT_SUCCESS_PREFIX}/) || (IGNORABLE_PATTERNS + ignorable_patterns).any? { |pat| pat.match?(l) } + end + unless err_lines.empty? + warn err_lines.join(''), uplevel: uplevel + end + end + + def mark_tested_insn(insn, used_insns:, uplevel: 1) + # Currently, this check emits a false-positive warning against opt_regexpmatch2, + # so the insn is excluded explicitly. See https://bugs.ruby-lang.org/issues/18269 + if !used_insns.include?(insn) && insn != :opt_regexpmatch2 + $stderr.puts + warn "'#{insn}' insn is not included in the script. Actual insns are: #{used_insns.join(' ')}\n", uplevel: uplevel + end + TestJIT.untested_insns.delete(insn) + end + + # Collect block's insns or defined method's insns, which are expected to be JIT-ed. + # Note that this intentionally excludes insns in script's toplevel because they are not JIT-ed. + def method_insns(script) + insns = [] + RubyVM::InstructionSequence.compile(script).to_a.last.each do |(insn, *args)| + case insn + when :send + insns += collect_insns(args.last) + when :definemethod, :definesmethod + insns += collect_insns(args[1]) + when :defineclass + insns += collect_insns(args[1]) + end + end + insns.uniq + end + + # Recursively collect insns in iseq_array + def collect_insns(iseq_array) + return [] if iseq_array.nil? + + insns = iseq_array.last.select { |x| x.is_a?(Array) }.map(&:first) + iseq_array.last.each do |(insn, *args)| + case insn + when :definemethod, :definesmethod, :send + insns += collect_insns(args.last) + end + end + insns + end +end diff --git a/test/ruby/test_jit_debug.rb b/test/ruby/test_jit_debug.rb new file mode 100644 index 0000000000..b8dc9416ef --- /dev/null +++ b/test/ruby/test_jit_debug.rb @@ -0,0 +1,17 @@ +require_relative 'test_jit' + +return unless defined?(TestJIT) +return if ENV.key?('APPVEYOR') +return if ENV.key?('RUBYCI_NICKNAME') +return if ENV['RUBY_DEBUG']&.include?('ci') # ci.rvm.jp +return if /mswin/ =~ RUBY_PLATFORM + +class TestJITDebug < TestJIT + @@test_suites.delete TestJIT if self.respond_to? :on_parallel_worker? + + def setup + super + # let `#eval_with_jit` use --mjit-debug + @mjit_debug = true + end +end diff --git a/test/ruby/test_keyword.rb b/test/ruby/test_keyword.rb index ef594bd52e..9094259bc2 100644 --- a/test/ruby/test_keyword.rb +++ b/test/ruby/test_keyword.rb @@ -190,53 +190,6 @@ class TestKeywordArguments < Test::Unit::TestCase assert_equal(["bar", 111111], f[str: "bar", num: 111111]) end - def test_unset_hash_flag - bug18625 = "[ruby-core: 107847]" - singleton_class.class_eval do - ruby2_keywords def foo(*args) - args - end - - def single(arg) - arg - end - - def splat(*args) - args.last - end - - def kwargs(**kw) - kw - end - end - - h = { a: 1 } - args = foo(**h) - marked = args.last - assert_equal(true, Hash.ruby2_keywords_hash?(marked)) - - after_usage = single(*args) - assert_equal(h, after_usage) - assert_same(marked, args.last) - assert_not_same(marked, after_usage) - assert_equal(false, Hash.ruby2_keywords_hash?(after_usage)) - - after_usage = splat(*args) - assert_equal(h, after_usage) - assert_same(marked, args.last) - assert_not_same(marked, after_usage, bug18625) - assert_equal(false, Hash.ruby2_keywords_hash?(after_usage), bug18625) - - after_usage = kwargs(*args) - assert_equal(h, after_usage) - assert_same(marked, args.last) - assert_not_same(marked, after_usage, bug18625) - assert_not_same(marked, after_usage) - assert_equal(false, Hash.ruby2_keywords_hash?(after_usage)) - - assert_equal(true, Hash.ruby2_keywords_hash?(marked)) - end - def test_keyword_splat_new kw = {} h = {a: 1} @@ -247,17 +200,17 @@ class TestKeywordArguments < Test::Unit::TestCase assert_not_same(kw, res) end - def self.yo(**kw) kw end - m = method(:yo) - assert_equal(false, yo(**{}).frozen?) - assert_equal_not_same(kw, yo(**kw)) - assert_equal_not_same(h, yo(**h)) - assert_equal(false, send(:yo, **{}).frozen?) - assert_equal_not_same(kw, send(:yo, **kw)) - assert_equal_not_same(h, send(:yo, **h)) - assert_equal(false, public_send(:yo, **{}).frozen?) - assert_equal_not_same(kw, public_send(:yo, **kw)) - assert_equal_not_same(h, public_send(:yo, **h)) + def self.y(**kw) kw end + m = method(:y) + assert_equal(false, y(**{}).frozen?) + assert_equal_not_same(kw, y(**kw)) + assert_equal_not_same(h, y(**h)) + assert_equal(false, send(:y, **{}).frozen?) + assert_equal_not_same(kw, send(:y, **kw)) + assert_equal_not_same(h, send(:y, **h)) + assert_equal(false, public_send(:y, **{}).frozen?) + assert_equal_not_same(kw, public_send(:y, **kw)) + assert_equal_not_same(h, public_send(:y, **h)) assert_equal(false, m.(**{}).frozen?) assert_equal_not_same(kw, m.(**kw)) assert_equal_not_same(h, m.(**h)) @@ -266,25 +219,25 @@ class TestKeywordArguments < Test::Unit::TestCase assert_equal_not_same(h, m.send(:call, **h)) m = method(:send) - assert_equal(false, m.(:yo, **{}).frozen?) - assert_equal_not_same(kw, m.(:yo, **kw)) - assert_equal_not_same(h, m.(:yo, **h)) - assert_equal(false, m.send(:call, :yo, **{}).frozen?) - assert_equal_not_same(kw, m.send(:call, :yo, **kw)) - assert_equal_not_same(h, m.send(:call, :yo, **h)) - - singleton_class.send(:remove_method, :yo) - define_singleton_method(:yo) { |**kw| kw } - m = method(:yo) - assert_equal(false, yo(**{}).frozen?) - assert_equal_not_same(kw, yo(**kw)) - assert_equal_not_same(h, yo(**h)) - assert_equal(false, send(:yo, **{}).frozen?) - assert_equal_not_same(kw, send(:yo, **kw)) - assert_equal_not_same(h, send(:yo, **h)) - assert_equal(false, public_send(:yo, **{}).frozen?) - assert_equal_not_same(kw, public_send(:yo, **kw)) - assert_equal_not_same(h, public_send(:yo, **h)) + assert_equal(false, m.(:y, **{}).frozen?) + assert_equal_not_same(kw, m.(:y, **kw)) + assert_equal_not_same(h, m.(:y, **h)) + assert_equal(false, m.send(:call, :y, **{}).frozen?) + assert_equal_not_same(kw, m.send(:call, :y, **kw)) + assert_equal_not_same(h, m.send(:call, :y, **h)) + + singleton_class.send(:remove_method, :y) + define_singleton_method(:y) { |**kw| kw } + m = method(:y) + assert_equal(false, y(**{}).frozen?) + assert_equal_not_same(kw, y(**kw)) + assert_equal_not_same(h, y(**h)) + assert_equal(false, send(:y, **{}).frozen?) + assert_equal_not_same(kw, send(:y, **kw)) + assert_equal_not_same(h, send(:y, **h)) + assert_equal(false, public_send(:y, **{}).frozen?) + assert_equal_not_same(kw, public_send(:y, **kw)) + assert_equal_not_same(h, public_send(:y, **h)) assert_equal(false, m.(**{}).frozen?) assert_equal_not_same(kw, m.(**kw)) assert_equal_not_same(h, m.(**h)) @@ -292,17 +245,17 @@ class TestKeywordArguments < Test::Unit::TestCase assert_equal_not_same(kw, m.send(:call, **kw)) assert_equal_not_same(h, m.send(:call, **h)) - yo = lambda { |**kw| kw } - m = yo.method(:call) - assert_equal(false, yo.(**{}).frozen?) - assert_equal_not_same(kw, yo.(**kw)) - assert_equal_not_same(h, yo.(**h)) - assert_equal(false, yo.send(:call, **{}).frozen?) - assert_equal_not_same(kw, yo.send(:call, **kw)) - assert_equal_not_same(h, yo.send(:call, **h)) - assert_equal(false, yo.public_send(:call, **{}).frozen?) - assert_equal_not_same(kw, yo.public_send(:call, **kw)) - assert_equal_not_same(h, yo.public_send(:call, **h)) + y = lambda { |**kw| kw } + m = y.method(:call) + assert_equal(false, y.(**{}).frozen?) + assert_equal_not_same(kw, y.(**kw)) + assert_equal_not_same(h, y.(**h)) + assert_equal(false, y.send(:call, **{}).frozen?) + assert_equal_not_same(kw, y.send(:call, **kw)) + assert_equal_not_same(h, y.send(:call, **h)) + assert_equal(false, y.public_send(:call, **{}).frozen?) + assert_equal_not_same(kw, y.public_send(:call, **kw)) + assert_equal_not_same(h, y.public_send(:call, **h)) assert_equal(false, m.(**{}).frozen?) assert_equal_not_same(kw, m.(**kw)) assert_equal_not_same(h, m.(**h)) @@ -310,17 +263,17 @@ class TestKeywordArguments < Test::Unit::TestCase assert_equal_not_same(kw, m.send(:call, **kw)) assert_equal_not_same(h, m.send(:call, **h)) - yo = :yo.to_proc - m = yo.method(:call) - assert_equal(false, yo.(self, **{}).frozen?) - assert_equal_not_same(kw, yo.(self, **kw)) - assert_equal_not_same(h, yo.(self, **h)) - assert_equal(false, yo.send(:call, self, **{}).frozen?) - assert_equal_not_same(kw, yo.send(:call, self, **kw)) - assert_equal_not_same(h, yo.send(:call, self, **h)) - assert_equal(false, yo.public_send(:call, self, **{}).frozen?) - assert_equal_not_same(kw, yo.public_send(:call, self, **kw)) - assert_equal_not_same(h, yo.public_send(:call, self, **h)) + y = :y.to_proc + m = y.method(:call) + assert_equal(false, y.(self, **{}).frozen?) + assert_equal_not_same(kw, y.(self, **kw)) + assert_equal_not_same(h, y.(self, **h)) + assert_equal(false, y.send(:call, self, **{}).frozen?) + assert_equal_not_same(kw, y.send(:call, self, **kw)) + assert_equal_not_same(h, y.send(:call, self, **h)) + assert_equal(false, y.public_send(:call, self, **{}).frozen?) + assert_equal_not_same(kw, y.public_send(:call, self, **kw)) + assert_equal_not_same(h, y.public_send(:call, self, **h)) assert_equal(false, m.(self, **{}).frozen?) assert_equal_not_same(kw, m.(self, **kw)) assert_equal_not_same(h, m.(self, **h)) @@ -329,20 +282,20 @@ class TestKeywordArguments < Test::Unit::TestCase assert_equal_not_same(h, m.send(:call, self, **h)) c = Class.new do - def yo(**kw) kw end + def y(**kw) kw end end o = c.new - def o.yo(**kw) super end - m = o.method(:yo) - assert_equal(false, o.yo(**{}).frozen?) - assert_equal_not_same(kw, o.yo(**kw)) - assert_equal_not_same(h, o.yo(**h)) - assert_equal(false, o.send(:yo, **{}).frozen?) - assert_equal_not_same(kw, o.send(:yo, **kw)) - assert_equal_not_same(h, o.send(:yo, **h)) - assert_equal(false, o.public_send(:yo, **{}).frozen?) - assert_equal_not_same(kw, o.public_send(:yo, **kw)) - assert_equal_not_same(h, o.public_send(:yo, **h)) + def o.y(**kw) super end + m = o.method(:y) + assert_equal(false, o.y(**{}).frozen?) + assert_equal_not_same(kw, o.y(**kw)) + assert_equal_not_same(h, o.y(**h)) + assert_equal(false, o.send(:y, **{}).frozen?) + assert_equal_not_same(kw, o.send(:y, **kw)) + assert_equal_not_same(h, o.send(:y, **h)) + assert_equal(false, o.public_send(:y, **{}).frozen?) + assert_equal_not_same(kw, o.public_send(:y, **kw)) + assert_equal_not_same(h, o.public_send(:y, **h)) assert_equal(false, m.(**{}).frozen?) assert_equal_not_same(kw, m.(**kw)) assert_equal_not_same(h, m.(**h)) @@ -350,17 +303,17 @@ class TestKeywordArguments < Test::Unit::TestCase assert_equal_not_same(kw, m.send(:call, **kw)) assert_equal_not_same(h, m.send(:call, **h)) - o.singleton_class.send(:remove_method, :yo) - def o.yo(**kw) super(**kw) end - assert_equal(false, o.yo(**{}).frozen?) - assert_equal_not_same(kw, o.yo(**kw)) - assert_equal_not_same(h, o.yo(**h)) - assert_equal(false, o.send(:yo, **{}).frozen?) - assert_equal_not_same(kw, o.send(:yo, **kw)) - assert_equal_not_same(h, o.send(:yo, **h)) - assert_equal(false, o.public_send(:yo, **{}).frozen?) - assert_equal_not_same(kw, o.public_send(:yo, **kw)) - assert_equal_not_same(h, o.public_send(:yo, **h)) + o.singleton_class.send(:remove_method, :y) + def o.y(**kw) super(**kw) end + assert_equal(false, o.y(**{}).frozen?) + assert_equal_not_same(kw, o.y(**kw)) + assert_equal_not_same(h, o.y(**h)) + assert_equal(false, o.send(:y, **{}).frozen?) + assert_equal_not_same(kw, o.send(:y, **kw)) + assert_equal_not_same(h, o.send(:y, **h)) + assert_equal(false, o.public_send(:y, **{}).frozen?) + assert_equal_not_same(kw, o.public_send(:y, **kw)) + assert_equal_not_same(h, o.public_send(:y, **h)) assert_equal(false, m.(**{}).frozen?) assert_equal_not_same(kw, m.(**kw)) assert_equal_not_same(h, m.(**h)) @@ -372,17 +325,17 @@ class TestKeywordArguments < Test::Unit::TestCase def method_missing(_, **kw) kw end end o = c.new - def o.yo(**kw) super end - m = o.method(:yo) - assert_equal(false, o.yo(**{}).frozen?) - assert_equal_not_same(kw, o.yo(**kw)) - assert_equal_not_same(h, o.yo(**h)) - assert_equal(false, o.send(:yo, **{}).frozen?) - assert_equal_not_same(kw, o.send(:yo, **kw)) - assert_equal_not_same(h, o.send(:yo, **h)) - assert_equal(false, o.public_send(:yo, **{}).frozen?) - assert_equal_not_same(kw, o.public_send(:yo, **kw)) - assert_equal_not_same(h, o.public_send(:yo, **h)) + def o.y(**kw) super end + m = o.method(:y) + assert_equal(false, o.y(**{}).frozen?) + assert_equal_not_same(kw, o.y(**kw)) + assert_equal_not_same(h, o.y(**h)) + assert_equal(false, o.send(:y, **{}).frozen?) + assert_equal_not_same(kw, o.send(:y, **kw)) + assert_equal_not_same(h, o.send(:y, **h)) + assert_equal(false, o.public_send(:y, **{}).frozen?) + assert_equal_not_same(kw, o.public_send(:y, **kw)) + assert_equal_not_same(h, o.public_send(:y, **h)) assert_equal(false, m.(**{}).frozen?) assert_equal_not_same(kw, m.(**kw)) assert_equal_not_same(h, m.(**h)) @@ -390,17 +343,17 @@ class TestKeywordArguments < Test::Unit::TestCase assert_equal_not_same(kw, m.send(:call, **kw)) assert_equal_not_same(h, m.send(:call, **h)) - o.singleton_class.send(:remove_method, :yo) - def o.yo(**kw) super(**kw) end - assert_equal(false, o.yo(**{}).frozen?) - assert_equal_not_same(kw, o.yo(**kw)) - assert_equal_not_same(h, o.yo(**h)) - assert_equal(false, o.send(:yo, **{}).frozen?) - assert_equal_not_same(kw, o.send(:yo, **kw)) - assert_equal_not_same(h, o.send(:yo, **h)) - assert_equal(false, o.public_send(:yo, **{}).frozen?) - assert_equal_not_same(kw, o.public_send(:yo, **kw)) - assert_equal_not_same(h, o.public_send(:yo, **h)) + o.singleton_class.send(:remove_method, :y) + def o.y(**kw) super(**kw) end + assert_equal(false, o.y(**{}).frozen?) + assert_equal_not_same(kw, o.y(**kw)) + assert_equal_not_same(h, o.y(**h)) + assert_equal(false, o.send(:y, **{}).frozen?) + assert_equal_not_same(kw, o.send(:y, **kw)) + assert_equal_not_same(h, o.send(:y, **h)) + assert_equal(false, o.public_send(:y, **{}).frozen?) + assert_equal_not_same(kw, o.public_send(:y, **kw)) + assert_equal_not_same(h, o.public_send(:y, **h)) assert_equal(false, m.(**{}).frozen?) assert_equal_not_same(kw, m.(**kw)) assert_equal_not_same(h, m.(**h)) @@ -436,27 +389,17 @@ class TestKeywordArguments < Test::Unit::TestCase assert_equal_not_same(h, m.(**h)) assert_equal_not_same(h, m.send(:call, **h)) - singleton_class.send(:remove_method, :yo) + singleton_class.send(:remove_method, :y) def self.method_missing(_, **kw) kw end - assert_equal(false, yo(**{}).frozen?) - assert_equal_not_same(kw, yo(**kw)) - assert_equal_not_same(h, yo(**h)) - assert_equal(false, send(:yo, **{}).frozen?) - assert_equal_not_same(kw, send(:yo, **kw)) - assert_equal_not_same(h, send(:yo, **h)) - assert_equal(false, public_send(:yo, **{}).frozen?) - assert_equal_not_same(kw, public_send(:yo, **kw)) - assert_equal_not_same(h, public_send(:yo, **h)) - - def self.yo(*a, **kw) = kw - assert_equal_not_same kw, yo(**kw) - assert_equal_not_same kw, yo(**kw, **kw) - - singleton_class.send(:remove_method, :yo) - def self.yo(opts) = opts - assert_equal_not_same h, yo(*[], **h) - a = [] - assert_equal_not_same h, yo(*a, **h) + assert_equal(false, y(**{}).frozen?) + assert_equal_not_same(kw, y(**kw)) + assert_equal_not_same(h, y(**h)) + assert_equal(false, send(:y, **{}).frozen?) + assert_equal_not_same(kw, send(:y, **kw)) + assert_equal_not_same(h, send(:y, **h)) + assert_equal(false, public_send(:y, **{}).frozen?) + assert_equal_not_same(kw, public_send(:y, **kw)) + assert_equal_not_same(h, public_send(:y, **h)) end def test_regular_kwsplat @@ -3595,7 +3538,7 @@ class TestKeywordArguments < Test::Unit::TestCase assert_equal(splat_expect, pr.call(a), bug8463) pr = proc {|a, **opt| next a, opt} - assert_equal([splat_expect, {}], pr.call(splat_expect), bug8463) + assert_equal(splat_expect.values_at(0, -1), pr.call(splat_expect), bug8463) end def req_plus_keyword(x, **h) diff --git a/test/ruby/test_lambda.rb b/test/ruby/test_lambda.rb index 7738034240..9949fab8c7 100644 --- a/test/ruby/test_lambda.rb +++ b/test/ruby/test_lambda.rb @@ -177,6 +177,32 @@ class TestLambdaParameters < Test::Unit::TestCase RUBY end + def pass_along(&block) + lambda(&block) + end + + def pass_along2(&block) + pass_along(&block) + end + + def test_create_non_lambda_for_proc_one_level + prev_warning, Warning[:deprecated] = Warning[:deprecated], false + f = pass_along {} + refute_predicate(f, :lambda?, '[Bug #15620]') + assert_nothing_raised(ArgumentError) { f.call(:extra_arg) } + ensure + Warning[:deprecated] = prev_warning + end + + def test_create_non_lambda_for_proc_two_levels + prev_warning, Warning[:deprecated] = Warning[:deprecated], false + f = pass_along2 {} + refute_predicate(f, :lambda?, '[Bug #15620]') + assert_nothing_raised(ArgumentError) { f.call(:extra_arg) } + ensure + Warning[:deprecated] = prev_warning + end + def test_instance_exec bug12568 = '[ruby-core:76300] [Bug #12568]' assert_nothing_raised(ArgumentError, bug12568) do diff --git a/test/ruby/test_lazy_enumerator.rb b/test/ruby/test_lazy_enumerator.rb index 22127e903a..2116d0ee31 100644 --- a/test/ruby/test_lazy_enumerator.rb +++ b/test/ruby/test_lazy_enumerator.rb @@ -282,11 +282,6 @@ class TestLazyEnumerator < Test::Unit::TestCase assert_equal(3, a.current) end - def test_zip_map_lambda_bug_19569 - ary = [1, 2, 3].to_enum.lazy.zip([:a, :b, :c]).map(&:last).to_a - assert_equal([:a, :b, :c], ary) - end - def test_take a = Step.new(1..10) assert_equal(1, a.take(5).first) @@ -300,26 +295,6 @@ class TestLazyEnumerator < Test::Unit::TestCase assert_equal(nil, a.current) end - def test_take_0_bug_18971 - def (bomb = Object.new.extend(Enumerable)).each - raise - end - [2..10, bomb].each do |e| - assert_equal([], e.lazy.take(0).map(&:itself).to_a) - assert_equal([], e.lazy.take(0).select(&:even?).to_a) - assert_equal([], e.lazy.take(0).select(&:odd?).to_a) - assert_equal([], e.lazy.take(0).reject(&:even?).to_a) - assert_equal([], e.lazy.take(0).reject(&:odd?).to_a) - assert_equal([], e.lazy.take(0).take(1).to_a) - assert_equal([], e.lazy.take(0).take(0).take(1).to_a) - assert_equal([], e.lazy.take(0).drop(0).to_a) - assert_equal([], e.lazy.take(0).find_all {|_| true}.to_a) - assert_equal([], e.lazy.take(0).zip((12..20)).to_a) - assert_equal([], e.lazy.take(0).uniq.to_a) - assert_equal([], e.lazy.take(0).sort.to_a) - end - end - def test_take_bad_arg a = Step.new(1..10) assert_raise(ArgumentError) { a.lazy.take(-1) } diff --git a/test/ruby/test_m17n.rb b/test/ruby/test_m17n.rb index 907360b3a6..c793520ac4 100644 --- a/test/ruby/test_m17n.rb +++ b/test/ruby/test_m17n.rb @@ -226,16 +226,38 @@ class TestM17N < Test::Unit::TestCase end end - def test_utf_dummy_are_like_regular_dummy_encodings - [Encoding::UTF_16, Encoding::UTF_32].each do |enc| - s = "\u3042".encode("UTF-32BE") - assert_equal(s.dup.force_encoding("ISO-2022-JP").inspect, s.dup.force_encoding(enc).inspect) - s = "\x00\x00\xFE\xFF" - assert_equal(s.dup.force_encoding("ISO-2022-JP").inspect, s.dup.force_encoding(enc).inspect) - - assert_equal [0, 0, 254, 255], "\x00\x00\xFE\xFF".force_encoding(enc).codepoints - assert_equal 0, "\x00\x00\xFE\xFF".force_encoding(enc).ord - assert_equal 255, "\xFF\xFE\x00\x00".force_encoding(enc).ord + STR_WITHOUT_BOM = "\u3042".freeze + STR_WITH_BOM = "\uFEFF\u3042".freeze + bug8940 = '[ruby-core:59757] [Bug #8940]' + bug9415 = '[ruby-dev:47895] [Bug #9415]' + %w/UTF-16 UTF-32/.each do |enc| + %w/BE LE/.each do |endian| + bom = "\uFEFF".encode("#{enc}#{endian}").force_encoding(enc) + + define_method("test_utf_16_32_inspect(#{enc}#{endian})") do + s = STR_WITHOUT_BOM.encode(enc + endian) + # When a UTF-16/32 string doesn't have a BOM, + # inspect as a dummy encoding string. + assert_equal(s.dup.force_encoding("ISO-2022-JP").inspect, + s.dup.force_encoding(enc).inspect) + assert_normal_exit("#{bom.b.dump}.force_encoding('#{enc}').inspect", bug8940) + end + + define_method("test_utf_16_32_codepoints(#{enc}#{endian})") do + assert_equal([0xFEFF], bom.codepoints, bug9415) + end + + define_method("test_utf_16_32_ord(#{enc}#{endian})") do + assert_equal(0xFEFF, bom.ord, bug9415) + end + + define_method("test_utf_16_32_inspect(#{enc}#{endian}-BOM)") do + s = STR_WITH_BOM.encode(enc + endian) + # When a UTF-16/32 string has a BOM, + # inspect as a particular encoding string. + assert_equal(s.inspect, + s.dup.force_encoding(enc).inspect) + end end end @@ -278,7 +300,7 @@ class TestM17N < Test::Unit::TestCase orig_int, Encoding.default_internal = Encoding.default_internal, nil orig_ext = Encoding.default_external - omit "https://bugs.ruby-lang.org/issues/18338" + skip "https://bugs.ruby-lang.org/issues/18338" o = Object.new @@ -870,22 +892,10 @@ class TestM17N < Test::Unit::TestCase assert_raise(Encoding::CompatibilityError) { "%s%s" % [s("\xc2\xa1"), e("\xc2\xa1")] } - - assert_equal("\u3042".encode('Windows-31J'), "%c" % "\u3042\u3044".encode('Windows-31J')) end def test_sprintf_p Encoding.list.each do |e| - unless e.ascii_compatible? - format = e.dummy? ? "%p".force_encoding(e) : "%p".encode(e) - assert_raise(Encoding::CompatibilityError) do - sprintf(format, nil) - end - assert_raise(Encoding::CompatibilityError) do - format % nil - end - next - end format = "%p".force_encoding(e) ['', 'a', "\xC2\xA1", "\x00"].each do |s| s.force_encoding(e) @@ -1090,23 +1100,7 @@ class TestM17N < Test::Unit::TestCase assert_nil(e("\xa1\xa2\xa3\xa4").index(e("\xa3"))) assert_nil(e("\xa1\xa2\xa3\xa4").rindex(e("\xa3"))) s = e("\xa3\xb0\xa3\xb1\xa3\xb2\xa3\xb3\xa3\xb4") - - a_with_e = /EUC-JP and ASCII-8BIT/ - assert_raise_with_message(Encoding::CompatibilityError, a_with_e) do - s.index(a("\xb1\xa3")) - end - assert_raise_with_message(Encoding::CompatibilityError, a_with_e) do - s.rindex(a("\xb1\xa3")) - end - - a_with_e = /ASCII-8BIT regexp with EUC-JP string/ - assert_raise_with_message(Encoding::CompatibilityError, a_with_e) do - s.index(Regexp.new(a("\xb1\xa3"))) - end - assert_raise_with_message(Encoding::CompatibilityError, a_with_e) do - s.rindex(Regexp.new(a("\xb1\xa3"))) - end - + assert_raise(Encoding::CompatibilityError){s.rindex(a("\xb1\xa3"))} bug11488 = '[ruby-core:70592] [Bug #11488]' each_encoding("abcdef", "def") do |str, substr| assert_equal(3, str.index(substr), bug11488) diff --git a/test/ruby/test_marshal.rb b/test/ruby/test_marshal.rb index 13645e3aa8..361d18dd4b 100644 --- a/test/ruby/test_marshal.rb +++ b/test/ruby/test_marshal.rb @@ -1,5 +1,6 @@ # frozen_string_literal: false require 'test/unit' +require 'tempfile' require_relative 'marshaltestlib' class TestMarshal < Test::Unit::TestCase @@ -32,7 +33,7 @@ class TestMarshal < Test::Unit::TestCase end def test_marshal - a = [1, 2, 3, 2**32, 2**64, [4,5,"foo"], {1=>"bar"}, 2.5, fact(30)] + a = [1, 2, 3, [4,5,"foo"], {1=>"bar"}, 2.5, fact(30)] assert_equal a, Marshal.load(Marshal.dump(a)) [[1,2,3,4], [81, 2, 118, 3146]].each { |w,x,y,z| @@ -46,26 +47,6 @@ class TestMarshal < Test::Unit::TestCase } end - def test_marshal_integers - a = [] - [-2, -1, 0, 1, 2].each do |i| - 0.upto(65).map do |exp| - a << 2**exp + i - end - end - assert_equal a, Marshal.load(Marshal.dump(a)) - - a = [2**32, []]*2 - assert_equal a, Marshal.load(Marshal.dump(a)) - - a = [2**32, 2**32, []]*2 - assert_equal a, Marshal.load(Marshal.dump(a)) - end - - def test_marshal_small_bignum_backref - assert_equal [2**32, 2**32], Marshal.load("\x04\b[\al+\b\x00\x00\x00\x00\x01\x00@\x06") - end - StrClone = String.clone def test_marshal_cloned_class assert_instance_of(StrClone, Marshal.load(Marshal.dump(StrClone.new("abc")))) @@ -91,14 +72,6 @@ class TestMarshal < Test::Unit::TestCase TestMarshal.instance_eval { remove_const :StructInvalidMembers } end - def test_load_range_as_struct - assert_raise(TypeError, 'GH-6832') do - # Can be obtained with: - # $ ruby -e 'Range = Struct.new(:a, :b, :c); p Marshal.dump(Range.new(nil, nil, nil))' - Marshal.load("\x04\bS:\nRange\b:\x06a0:\x06b0:\x06c0") - end - end - class C def initialize(str) @str = str @@ -313,10 +286,11 @@ class TestMarshal < Test::Unit::TestCase assert_equal(c, Marshal.load(Marshal.dump(c)), bug2109) assert_nothing_raised(ArgumentError, '[ruby-dev:40386]') do - re = IO.pipe do |r, w| - w.write("\x04\bI/\x00\x00\x06:\rencoding\"\rUS-ASCII") - # Marshal.load would not overread and block - Marshal.load(r) + re = Tempfile.create("marshal_regexp") do |f| + f.binmode.write("\x04\bI/\x00\x00\x06:\rencoding\"\rUS-ASCII") + f.rewind + re2 = Marshal.load(f) + re2 end assert_equal(//, re) end diff --git a/test/ruby/test_math.rb b/test/ruby/test_math.rb index 6e67099c6b..73f44c6ae3 100644 --- a/test/ruby/test_math.rb +++ b/test/ruby/test_math.rb @@ -5,7 +5,6 @@ class TestMath < Test::Unit::TestCase def assert_infinity(a, *rest) rest = ["not infinity: #{a.inspect}"] if rest.empty? assert_predicate(a, :infinite?, *rest) - assert_predicate(a, :positive?, *rest) end def assert_nan(a, *rest) @@ -166,9 +165,6 @@ class TestMath < Test::Unit::TestCase assert_nothing_raised { assert_nan(Math.log(0.0, 0.0)) } assert_nothing_raised { assert_nan(Math.log(Float::NAN)) } assert_nothing_raised { assert_nan(Math.log(1.0, Float::NAN)) } - assert_nothing_raised { assert_infinity(-Math.log(0)) } - assert_nothing_raised { assert_infinity(-Math.log(0, 2)) } - check(307.95368556425274, Math.log(2**1023, 10)) end def test_log2 @@ -183,7 +179,6 @@ class TestMath < Test::Unit::TestCase assert_raise_with_message(Math::DomainError, /\blog2\b/) { Math.log2(-1.0) } assert_raise_with_message(Math::DomainError, /\blog2\b/) { Math.log2(-Float::EPSILON) } assert_nothing_raised { assert_nan(Math.log2(Float::NAN)) } - assert_nothing_raised { assert_infinity(-Math.log2(0)) } end def test_log10 @@ -198,7 +193,6 @@ class TestMath < Test::Unit::TestCase assert_raise_with_message(Math::DomainError, /\blog10\b/) { Math.log10(-1.0) } assert_raise_with_message(Math::DomainError, /\blog10\b/) { Math.log10(-Float::EPSILON) } assert_nothing_raised { assert_nan(Math.log10(Float::NAN)) } - assert_nothing_raised { assert_infinity(-Math.log10(0)) } end def test_sqrt @@ -283,7 +277,8 @@ class TestMath < Test::Unit::TestCase assert_raise_with_message(Math::DomainError, /\bgamma\b/) { Math.gamma(-1.0) } x = Math.gamma(-0.0) mesg = "Math.gamma(-0.0) should be -INF" - assert_infinity(-x, mesg) + assert_infinity(x, mesg) + assert_predicate(x, :negative?, mesg) assert_nan(Math.gamma(Float::NAN)) end @@ -304,6 +299,7 @@ class TestMath < Test::Unit::TestCase x, sign = Math.lgamma(-0.0) mesg = "Math.lgamma(-0.0) should be [INF, -1]" assert_infinity(x, mesg) + assert_predicate(x, :positive?, mesg) assert_equal(-1, sign, mesg) x, sign = Math.lgamma(Float::NAN) assert_nan(x) diff --git a/test/ruby/test_method.rb b/test/ruby/test_method.rb index 9f34164a77..ac50a9d0b0 100644 --- a/test/ruby/test_method.rb +++ b/test/ruby/test_method.rb @@ -318,17 +318,6 @@ class TestMethod < Test::Unit::TestCase assert_equal(:foo, o.foo) end - PUBLIC_SINGLETON_TEST = Object.new - class << PUBLIC_SINGLETON_TEST - private - PUBLIC_SINGLETON_TEST.define_singleton_method(:dsm){} - def PUBLIC_SINGLETON_TEST.def; end - end - def test_define_singleton_method_public - assert_nil(PUBLIC_SINGLETON_TEST.dsm) - assert_nil(PUBLIC_SINGLETON_TEST.def) - end - def test_define_singleton_method_no_proc o = Object.new assert_raise(ArgumentError) { @@ -577,9 +566,9 @@ class TestMethod < Test::Unit::TestCase assert_equal([[:req, :a], [:rest, :b], [:req, :c]], method(:mo5).parameters) assert_equal([[:req, :a], [:rest, :b], [:req, :c], [:block, :d]], method(:mo6).parameters) assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:block, :e]], method(:mo7).parameters) - assert_equal([[:req, :a], [:opt, :b], [:rest, :*], [:req, :d], [:block, :e]], method(:mo8).parameters) + assert_equal([[:req, :a], [:opt, :b], [:rest], [:req, :d], [:block, :e]], method(:mo8).parameters) assert_equal([[:req], [:block, :b]], method(:ma1).parameters) - assert_equal([[:keyrest, :**]], method(:mk1).parameters) + assert_equal([[:keyrest]], method(:mk1).parameters) assert_equal([[:keyrest, :o]], method(:mk2).parameters) assert_equal([[:req, :a], [:keyrest, :o]], method(:mk3).parameters) assert_equal([[:opt, :a], [:keyrest, :o]], method(:mk4).parameters) @@ -603,9 +592,9 @@ class TestMethod < Test::Unit::TestCase assert_equal([[:req, :a], [:rest, :b], [:req, :c]], self.class.instance_method(:mo5).parameters) assert_equal([[:req, :a], [:rest, :b], [:req, :c], [:block, :d]], self.class.instance_method(:mo6).parameters) assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:block, :e]], self.class.instance_method(:mo7).parameters) - assert_equal([[:req, :a], [:opt, :b], [:rest, :*], [:req, :d], [:block, :e]], self.class.instance_method(:mo8).parameters) + assert_equal([[:req, :a], [:opt, :b], [:rest], [:req, :d], [:block, :e]], self.class.instance_method(:mo8).parameters) assert_equal([[:req], [:block, :b]], self.class.instance_method(:ma1).parameters) - assert_equal([[:keyrest, :**]], self.class.instance_method(:mk1).parameters) + assert_equal([[:keyrest]], self.class.instance_method(:mk1).parameters) assert_equal([[:keyrest, :o]], self.class.instance_method(:mk2).parameters) assert_equal([[:req, :a], [:keyrest, :o]], self.class.instance_method(:mk3).parameters) assert_equal([[:opt, :a], [:keyrest, :o]], self.class.instance_method(:mk4).parameters) @@ -630,7 +619,7 @@ class TestMethod < Test::Unit::TestCase assert_equal([[:req, :a], [:rest, :b], [:req, :c], [:block, :d]], method(:pmo6).parameters) assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:block, :e]], method(:pmo7).parameters) assert_equal([[:req], [:block, :b]], method(:pma1).parameters) - assert_equal([[:keyrest, :**]], method(:pmk1).parameters) + assert_equal([[:keyrest]], method(:pmk1).parameters) assert_equal([[:keyrest, :o]], method(:pmk2).parameters) assert_equal([[:req, :a], [:keyrest, :o]], method(:pmk3).parameters) assert_equal([[:opt, :a], [:keyrest, :o]], method(:pmk4).parameters) @@ -654,7 +643,7 @@ class TestMethod < Test::Unit::TestCase assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:block, :e]], self.class.instance_method(:pmo7).parameters) assert_equal([[:req], [:block, :b]], self.class.instance_method(:pma1).parameters) assert_equal([[:req], [:block, :b]], self.class.instance_method(:pma1).parameters) - assert_equal([[:keyrest, :**]], self.class.instance_method(:pmk1).parameters) + assert_equal([[:keyrest]], self.class.instance_method(:pmk1).parameters) assert_equal([[:keyrest, :o]], self.class.instance_method(:pmk2).parameters) assert_equal([[:req, :a], [:keyrest, :o]], self.class.instance_method(:pmk3).parameters) assert_equal([[:opt, :a], [:keyrest, :o]], self.class.instance_method(:pmk4).parameters) @@ -771,14 +760,6 @@ class TestMethod < Test::Unit::TestCase assert_raise(NoMethodError) { (self).mv2 } assert_nothing_raised { self.mv3 } - class << (obj = Object.new) - private def [](x) x end - def mv1(x) self[x] end - def mv2(x) (self)[x] end - end - assert_nothing_raised { obj.mv1(0) } - assert_raise(NoMethodError) { obj.mv2(0) } - v = Visibility.new assert_equal('method', defined?(v.mv1)) @@ -1215,6 +1196,25 @@ class TestMethod < Test::Unit::TestCase assert_nil(super_method) end + def test_method_visibility_predicates + v = Visibility.new + assert_equal(true, v.method(:mv1).public?) + assert_equal(true, v.method(:mv2).private?) + assert_equal(true, v.method(:mv3).protected?) + assert_equal(false, v.method(:mv2).public?) + assert_equal(false, v.method(:mv3).private?) + assert_equal(false, v.method(:mv1).protected?) + end + + def test_unbound_method_visibility_predicates + assert_equal(true, Visibility.instance_method(:mv1).public?) + assert_equal(true, Visibility.instance_method(:mv2).private?) + assert_equal(true, Visibility.instance_method(:mv3).protected?) + assert_equal(false, Visibility.instance_method(:mv2).public?) + assert_equal(false, Visibility.instance_method(:mv3).private?) + assert_equal(false, Visibility.instance_method(:mv1).protected?) + end + # Bug 18435 def test_instance_methods_owner_consistency a = Module.new { def method1; end } @@ -1244,12 +1244,12 @@ class TestMethod < Test::Unit::TestCase unbound = b.instance_method(:foo) assert_equal unbound, b.public_instance_method(:foo) - assert_equal "#<UnboundMethod: A#foo(arg=...) #{__FILE__}:#{line}>", unbound.inspect + assert_equal "#<UnboundMethod: B(A)#foo(arg=...) #{__FILE__}:#{line}>", unbound.inspect assert_equal [[:opt, :arg]], unbound.parameters a.remove_method(:foo) - assert_equal "#<UnboundMethod: A#foo(arg=...) #{__FILE__}:#{line}>", unbound.inspect + assert_equal "#<UnboundMethod: B(A)#foo(arg=...) #{__FILE__}:#{line}>", unbound.inspect assert_equal [[:opt, :arg]], unbound.parameters obj = b.new @@ -1289,7 +1289,7 @@ class TestMethod < Test::Unit::TestCase a.remove_method(:foo) - assert_equal "#<UnboundMethod: A#foo(arg=...) #{__FILE__}:#{line}>", unbound.inspect + assert_equal "#<UnboundMethod: B(A)#foo(arg=...) #{__FILE__}:#{line}>", unbound.inspect assert_equal [[:opt, :arg]], unbound.parameters assert_equal a0_foo, unbound.super_method @@ -1297,7 +1297,7 @@ class TestMethod < Test::Unit::TestCase assert_equal 1, unbound.bind_call(obj) assert_include b.instance_methods(false), :foo - assert_equal "#<UnboundMethod: A0#foo(arg1=..., arg2=...) #{__FILE__}:#{line0}>", b.instance_method(:foo).inspect + assert_equal "#<UnboundMethod: B(A0)#foo(arg1=..., arg2=...) #{__FILE__}:#{line0}>", b.instance_method(:foo).inspect end def test_zsuper_method_redefined_bind_call @@ -1322,7 +1322,6 @@ class TestMethod < Test::Unit::TestCase m2 = c2.instance_method(:foo) c1.class_exec do - remove_method :foo def foo [:bar2] end @@ -1363,7 +1362,7 @@ class TestMethod < Test::Unit::TestCase def test_splat_long_array if File.exist?('/etc/os-release') && File.read('/etc/os-release').include?('openSUSE Leap') # For RubyCI's openSUSE machine http://rubyci.s3.amazonaws.com/opensuseleap/ruby-trunk/recent.html, which tends to die with NoMemoryError here. - omit 'do not exhaust memory on RubyCI openSUSE Leap machine' + skip 'do not exhaust memory on RubyCI openSUSE Leap machine' end n = 10_000_000 assert_equal n , rest_parameter(*(1..n)).size, '[Feature #10440]' @@ -1431,25 +1430,25 @@ class TestMethod < Test::Unit::TestCase end def test_argument_error_location - body = <<~'END_OF_BODY' - eval <<~'EOS', nil, "main.rb" - $line_lambda = __LINE__; $f = lambda do - _x = 1 - end - $line_method = __LINE__; def foo - _x = 1 - end - begin - $f.call(1) - rescue ArgumentError => e - assert_equal "main.rb:#{$line_lambda}:in `block in <main>'", e.backtrace.first - end - begin - foo(1) - rescue ArgumentError => e - assert_equal "main.rb:#{$line_method}:in `foo'", e.backtrace.first - end - EOS + body = <<-'END_OF_BODY' + eval <<-'EOS' + $line_lambda = __LINE__; $f = lambda do + _x = 1 + end + $line_method = __LINE__; def foo + _x = 1 + end + begin + $f.call(1) + rescue ArgumentError => e + assert_equal "(eval):#{$line_lambda.to_s}:in `block in <main>'", e.backtrace.first + end + begin + foo(1) + rescue ArgumentError => e + assert_equal "(eval):#{$line_method}:in `foo'", e.backtrace.first + end + EOS END_OF_BODY assert_separately [], body @@ -1458,7 +1457,7 @@ class TestMethod < Test::Unit::TestCase end def test_zsuper_private_override_instance_method - assert_separately([], <<-'end;', timeout: 30) + assert_separately(%w(--disable-gems), <<-'end;', timeout: 30) # Bug #16942 [ruby-core:98691] module M def x @@ -1479,7 +1478,7 @@ class TestMethod < Test::Unit::TestCase end def test_override_optimized_method_on_class_using_prepend - assert_separately([], <<-'end;', timeout: 30) + assert_separately(%w(--disable-gems), <<-'end;', timeout: 30) # Bug #17725 [ruby-core:102884] $VERBOSE = nil String.prepend(Module.new) @@ -1565,7 +1564,7 @@ class TestMethod < Test::Unit::TestCase # use_symbol = Object.instance_methods[0].is_a?(Symbol) nummodule = nummethod = 0 mods = [] - ObjectSpace.each_object(Module) {|m| mods << m if String === m.name } + ObjectSpace.each_object(Module) {|m| mods << m if m.name } mods = mods.sort_by {|m| m.name } mods.each {|mod| nummodule += 1 diff --git a/test/ruby/test_module.rb b/test/ruby/test_module.rb index 81c5345a5f..b5414d139e 100644 --- a/test/ruby/test_module.rb +++ b/test/ruby/test_module.rb @@ -535,7 +535,7 @@ class TestModule < Test::Unit::TestCase super end end.new - assert_operator(m, :<, Enumerable) + assert_equal(true, m < Enumerable) end def test_prepend_self @@ -572,26 +572,6 @@ class TestModule < Test::Unit::TestCase assert_equal(2, a2.b) end - def test_ancestry_of_duped_classes - m = Module.new - sc = Class.new - a = Class.new(sc) do - def b; 2 end - prepend m - end - - a2 = a.dup.new - - assert_kind_of Object, a2 - assert_kind_of sc, a2 - refute_kind_of a, a2 - assert_kind_of m, a2 - - assert_kind_of Class, a2.class - assert_kind_of sc.singleton_class, a2.class - assert_same sc, a2.class.superclass - end - def test_gc_prepend_chain assert_separately([], <<-EOS) 10000.times { |i| @@ -776,25 +756,6 @@ class TestModule < Test::Unit::TestCase assert_equal([:m1, :m0, :m, :sc, :m1, :m0, :c], sc.new.m) end - def test_protected_include_into_included_module - m1 = Module.new do - def other_foo(other) - other.foo - end - - protected - def foo - :ok - end - end - m2 = Module.new - c1 = Class.new { include m2 } - c2 = Class.new { include m2 } - m2.include(m1) - - assert_equal :ok, c1.new.other_foo(c2.new) - end - def test_instance_methods assert_equal([:user, :user2], User.instance_methods(false).sort) assert_equal([:user, :user2, :mixin].sort, User.instance_methods(true).sort) @@ -994,15 +955,6 @@ class TestModule < Test::Unit::TestCase assert_equal([:bClass1], BClass.public_instance_methods(false)) end - def test_undefined_instance_methods - assert_equal([], AClass.undefined_instance_methods) - assert_equal([], BClass.undefined_instance_methods) - c = Class.new(AClass) {undef aClass} - assert_equal([:aClass], c.undefined_instance_methods) - c = Class.new(c) - assert_equal([], c.undefined_instance_methods) - end - def test_s_public o = (c = Class.new(AClass)).new assert_raise(NoMethodError, /private method/) {o.aClass1} @@ -1328,6 +1280,8 @@ class TestModule < Test::Unit::TestCase end end include LangModuleSpecInObject + module LangModuleTop + end puts "ok" if LangModuleSpecInObject::LangModuleTop == LangModuleTop INPUT @@ -1728,47 +1682,6 @@ class TestModule < Test::Unit::TestCase assert_equal("TestModule::C\u{df}", c.name, '[ruby-core:24600]') c = Module.new.module_eval("class X\u{df} < Module; self; end") assert_match(/::X\u{df}:/, c.new.to_s) - ensure - Object.send(:remove_const, "C\u{df}") - end - - - def test_const_added - eval(<<~RUBY) - module TestConstAdded - @memo = [] - class << self - attr_accessor :memo - - def const_added(sym) - memo << sym - end - end - CONST = 1 - module SubModule - end - - class SubClass - end - end - TestConstAdded::OUTSIDE_CONST = 2 - module TestConstAdded::OutsideSubModule; end - class TestConstAdded::OutsideSubClass; end - RUBY - TestConstAdded.const_set(:CONST_SET, 3) - assert_equal [ - :CONST, - :SubModule, - :SubClass, - :OUTSIDE_CONST, - :OutsideSubModule, - :OutsideSubClass, - :CONST_SET, - ], TestConstAdded.memo - ensure - if self.class.const_defined? :TestConstAdded - self.class.send(:remove_const, :TestConstAdded) - end end def test_method_added @@ -2352,18 +2265,6 @@ class TestModule < Test::Unit::TestCase assert_equal(:foo, removed) end - def test_frozen_prepend_remove_method - [Module, Class].each do |klass| - mod = klass.new do - prepend(Module.new) - def foo; end - end - mod.freeze - assert_raise(FrozenError, '[Bug #19166]') { mod.send(:remove_method, :foo) } - assert_equal([:foo], mod.instance_methods(false)) - end - end - def test_prepend_class_ancestors bug6658 = '[ruby-core:45919]' m = labeled_module("m") @@ -2870,7 +2771,6 @@ class TestModule < Test::Unit::TestCase def test_invalid_attr %W[ - foo= foo? @foo @@foo @@ -3175,7 +3075,6 @@ class TestModule < Test::Unit::TestCase end def test_redefinition_mismatch - omit "Investigating trunk-rjit failure on ci.rvm.jp" if defined?(RubyVM::RJIT) && RubyVM::RJIT.enabled? m = Module.new m.module_eval "A = 1", __FILE__, line = __LINE__ e = assert_raise_with_message(TypeError, /is not a module/) { @@ -3292,6 +3191,35 @@ class TestModule < Test::Unit::TestCase CODE end + def test_complemented_method_entry_memory_leak + # [Bug #19894] + assert_no_memory_leak([], <<~PREP, <<~CODE, rss: true) + code = proc do + $c = Class.new do + def foo; end + end + + $m = Module.new do + refine $c do + def foo; end + end + end + + Class.new do + using $m + + def initialize + o = $c.new + o.method(:foo).unbind + end + end.new + end + 1_000.times(&code) + PREP + 100_000.times(&code) + CODE + end + private def assert_top_method_is_private(method) @@ -3299,7 +3227,7 @@ class TestModule < Test::Unit::TestCase methods = singleton_class.private_instance_methods(false) assert_include(methods, :#{method}, ":#{method} should be private") - assert_raise_with_message(NoMethodError, /^private method `#{method}' called for /) { + assert_raise_with_message(NoMethodError, "private method `#{method}' called for main:Object") { recv = self recv.#{method} } diff --git a/test/ruby/test_nomethod_error.rb b/test/ruby/test_nomethod_error.rb index 0306535943..321b7ccab2 100644 --- a/test/ruby/test_nomethod_error.rb +++ b/test/ruby/test_nomethod_error.rb @@ -85,7 +85,7 @@ class TestNoMethodError < Test::Unit::TestCase bug3237 = '[ruby-core:29948]' str = "\u2600" id = :"\u2604" - msg = "undefined method `#{id}' for an instance of String" + msg = "undefined method `#{id}' for \"#{str}\":String" assert_raise_with_message(NoMethodError, Regexp.compile(Regexp.quote(msg)), bug3237) do str.__send__(id) end diff --git a/test/ruby/test_object.rb b/test/ruby/test_object.rb index 3c5b6424ba..83208bbcdb 100644 --- a/test/ruby/test_object.rb +++ b/test/ruby/test_object.rb @@ -422,18 +422,6 @@ class TestObject < Test::Unit::TestCase assert_equal(1+3+5+7+9, n) end - def test_max_shape_variation_with_performance_warnings - assert_in_out_err([], <<-INPUT, %w(), /Maximum shapes variations \(8\) reached by Foo, instance variables accesses will be slower\.$/) - $VERBOSE = false - Warning[:performance] = true - - class Foo; end - 10.times do |i| - Foo.new.instance_variable_set(:"@a\#{i}", nil) - end - INPUT - end - def test_redefine_method_under_verbose assert_in_out_err([], <<-INPUT, %w(2), /warning: method redefined; discarding old foo$/) $VERBOSE = true @@ -865,15 +853,6 @@ class TestObject < Test::Unit::TestCase x.instance_variable_set(:@bar, 42) assert_match(/\A#<Object:0x\h+ (?:@foo="value", @bar=42|@bar=42, @foo="value")>\z/, x.inspect) - # Bug: [ruby-core:19167] - x = Object.new - x.instance_variable_set(:@foo, NilClass) - assert_match(/\A#<Object:0x\h+ @foo=NilClass>\z/, x.inspect) - x.instance_variable_set(:@foo, TrueClass) - assert_match(/\A#<Object:0x\h+ @foo=TrueClass>\z/, x.inspect) - x.instance_variable_set(:@foo, FalseClass) - assert_match(/\A#<Object:0x\h+ @foo=FalseClass>\z/, x.inspect) - # #inspect does not call #to_s anymore feature6130 = '[ruby-core:43238]' x = Object.new @@ -946,19 +925,6 @@ class TestObject < Test::Unit::TestCase end end - def test_singleton_class_freeze - x = Object.new - xs = x.singleton_class - x.freeze - assert_predicate(xs, :frozen?) - - y = Object.new - ys = y.singleton_class - ys.prepend(Module.new) - y.freeze - assert_predicate(ys, :frozen?, '[Bug #19169]') - end - def test_redef_method_missing bug5473 = '[ruby-core:40287]' ['ArgumentError.new("bug5473")', 'ArgumentError, "bug5473"', '"bug5473"'].each do |code| @@ -1027,13 +993,4 @@ class TestObject < Test::Unit::TestCase end EOS end - - def test_frozen_inspect - obj = Object.new - obj.instance_variable_set(:@a, "a") - ins = obj.inspect - obj.freeze - - assert_equal(ins, obj.inspect) - end end diff --git a/test/ruby/test_objectspace.rb b/test/ruby/test_objectspace.rb index a7cfb064a8..e0f9eecd11 100644 --- a/test/ruby/test_objectspace.rb +++ b/test/ruby/test_objectspace.rb @@ -65,11 +65,6 @@ End assert_raise_with_message(TypeError, msg) {ObjectSpace._id2ref(Object.new)} end - def test_id2ref_invalid_symbol_id - msg = /is not symbol id value/ - assert_raise_with_message(RangeError, msg) { ObjectSpace._id2ref(:a.object_id + GC::INTERNAL_CONSTANTS[:RVALUE_SIZE]) } - end - def test_count_objects h = {} ObjectSpace.count_objects(h) diff --git a/test/ruby/test_optimization.rb b/test/ruby/test_optimization.rb index 8d669e502c..43795d150c 100644 --- a/test/ruby/test_optimization.rb +++ b/test/ruby/test_optimization.rb @@ -437,20 +437,6 @@ class TestRubyOptimization < Test::Unit::TestCase message(bug12565) {disasm(:add_one_and_two)}) end - def test_c_func_with_sp_offset_under_tailcall - tailcall("#{<<-"begin;"}\n#{<<~"end;"}") - begin; - def calc_one_plus_two - 1 + 2.abs - end - - def one_plus_two - calc_one_plus_two - end - end; - assert_equal(3, one_plus_two) - end - def test_tailcall_interrupted_by_sigint bug12576 = 'ruby-core:76327' script = "#{<<-"begin;"}\n#{<<~'end;'}" @@ -524,7 +510,7 @@ class TestRubyOptimization < Test::Unit::TestCase end def test_tailcall_not_to_grow_stack - omit 'currently JIT-ed code always creates a new stack frame' if defined?(RubyVM::RJIT) && RubyVM::RJIT.enabled? + skip 'currently JIT-ed code always creates a new stack frame' if defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? bug16161 = '[ruby-core:94881]' tailcall("#{<<-"begin;"}\n#{<<~"end;"}") diff --git a/test/ruby/test_pack.rb b/test/ruby/test_pack.rb index 27573ef457..9738f82b7e 100644 --- a/test/ruby/test_pack.rb +++ b/test/ruby/test_pack.rb @@ -4,36 +4,22 @@ require 'test/unit' class TestPack < Test::Unit::TestCase def test_pack - format = "c2x5CCxsdils_l_a6"; + $format = "c2x5CCxsdils_l_a6"; # Need the expression in here to force ary[5] to be numeric. This avoids # test2 failing because ary2 goes str->numeric->str and ary does not. ary = [1,-100,127,128,32767,987.654321098 / 100.0,12345,123456,-32767,-123456,"abcdef"] - x = ary.pack(format) - ary2 = x.unpack(format) + $x = ary.pack($format) + ary2 = $x.unpack($format) assert_equal(ary.length, ary2.length) assert_equal(ary.join(':'), ary2.join(':')) - assert_match(/def/, x) + assert_match(/def/, $x) - x = [-1073741825] - assert_equal(x, x.pack("q").unpack("q")) + $x = [-1073741825] + assert_equal($x, $x.pack("q").unpack("q")) - x = [-1] - assert_equal(x, x.pack("l").unpack("l")) - end - - def test_ascii_incompatible - assert_raise(Encoding::CompatibilityError) do - ["foo"].pack("u".encode("UTF-32BE")) - end - - assert_raise(Encoding::CompatibilityError) do - "foo".unpack("C".encode("UTF-32BE")) - end - - assert_raise(Encoding::CompatibilityError) do - "foo".unpack1("C".encode("UTF-32BE")) - end + $x = [-1] + assert_equal($x, $x.pack("l").unpack("l")) end def test_pack_n @@ -777,32 +763,58 @@ EXPECTED end def test_pack_garbage - assert_raise(ArgumentError, %r%unknown pack directive '\*' in '\*U'$%) do + verbose = $VERBOSE + $VERBOSE = false + + assert_silent do assert_equal "\000", [0].pack("*U") end + + $VERBOSE = true + + _, err = capture_output do + assert_equal "\000", [0].pack("*U") + end + + assert_match %r%unknown pack directive '\*' in '\*U'$%, err + ensure + $VERBOSE = verbose end def test_unpack_garbage - assert_raise(ArgumentError, %r%unknown unpack directive '\*' in '\*U'$%) do + verbose = $VERBOSE + $VERBOSE = false + + assert_silent do assert_equal [0], "\000".unpack("*U") end + + $VERBOSE = true + + _, err = capture_output do + assert_equal [0], "\000".unpack("*U") + end + + assert_match %r%unknown unpack directive '\*' in '\*U'$%, err + ensure + $VERBOSE = verbose end def test_invalid_warning - assert_raise(ArgumentError, /unknown pack directive ',' in ','/) { + assert_warning(/unknown pack directive ',' in ','/) { [].pack(",") } - assert_raise(ArgumentError, /\A[ -~]+\Z/) { + assert_warning(/\A[ -~]+\Z/) { [].pack("\x7f") } - assert_raise(ArgumentError, /\A(.* in '\u{3042}'\n)+\z/) { + assert_warning(/\A(.* in '\u{3042}'\n)+\z/) { [].pack("\u{3042}") } - assert_raise(ArgumentError, /\A.* in '.*U'\Z/) { + assert_warning(/\A.* in '.*U'\Z/) { assert_equal "\000", [0].pack("\0U") } - assert_raise(ArgumentError, /\A.* in '.*U'\Z/) { + assert_warning(/\A.* in '.*U'\Z/) { "\000".unpack("\0U") } end diff --git a/test/ruby/test_parse.rb b/test/ruby/test_parse.rb index 957a37eb81..2841e20f6d 100644 --- a/test/ruby/test_parse.rb +++ b/test/ruby/test_parse.rb @@ -14,7 +14,6 @@ class TestParse < Test::Unit::TestCase def test_error_line assert_syntax_error('------,,', /\n\z/, 'Message to pipe should end with a newline') - assert_syntax_error("{hello\n world}", /hello/) end def test_else_without_rescue @@ -681,16 +680,6 @@ FOO eval "x = <<""FOO\r\n1\r\nFOO" end assert_equal("1\n", x) - - assert_nothing_raised do - x = eval "<<' FOO'\n""[Bug #19539]\n"" FOO\n" - end - assert_equal("[Bug #19539]\n", x) - - assert_nothing_raised do - x = eval "<<-' FOO'\n""[Bug #19539]\n"" FOO\n" - end - assert_equal("[Bug #19539]\n", x) end def test_magic_comment @@ -1052,22 +1041,6 @@ x = __ENCODING__ assert_syntax_error(" 0b\n", /\^/) end - def test_unclosed_unicode_escape_at_eol_bug_19750 - assert_separately([], "#{<<-"begin;"}\n#{<<~'end;'}") - begin; - assert_syntax_error("/\\u", /too short escape sequence/) - assert_syntax_error("/\\u{", /unterminated regexp meets end of file/) - assert_syntax_error("/\\u{\\n", /invalid Unicode list/) - assert_syntax_error("/a#\\u{\\n/", /invalid Unicode list/) - re = eval("/a#\\u{\n$/x") - assert_match(re, 'a') - assert_not_match(re, 'a#') - re = eval("/a#\\u\n$/x") - assert_match(re, 'a') - assert_not_match(re, 'a#') - end; - end - def test_error_def_in_argument assert_separately([], "#{<<-"begin;"}\n#{<<~"end;"}") begin; @@ -1111,40 +1084,31 @@ x = __ENCODING__ end; end - def test_heredoc_interpolation - var = 1 - - v1 = <<~HEREDOC - something - #{"/#{var}"} - HEREDOC - - v2 = <<~HEREDOC - something - #{_other = "/#{var}"} - HEREDOC + def test_heredoc_interpolation + var = 1 - v3 = <<~HEREDOC - something - #{("/#{var}")} - HEREDOC + v1 = <<~HEREDOC + something + #{"/#{var}"} + HEREDOC - assert_equal "something\n/1\n", v1 - assert_equal "something\n/1\n", v2 - assert_equal "something\n/1\n", v3 - assert_equal v1, v2 - assert_equal v2, v3 - assert_equal v1, v3 - end + v2 = <<~HEREDOC + something + #{_other = "/#{var}"} + HEREDOC - def test_heredoc_unterminated_interpolation - code = <<~'HEREDOC' - <<A+1 - #{ - HEREDOC + v3 = <<~HEREDOC + something + #{("/#{var}")} + HEREDOC - assert_syntax_error(code, /can't find string "A"/) - end + assert_equal "something\n/1\n", v1 + assert_equal "something\n/1\n", v2 + assert_equal "something\n/1\n", v3 + assert_equal v1, v2 + assert_equal v2, v3 + assert_equal v1, v3 + end def test_unexpected_token_error assert_syntax_error('"x"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', /unexpected/) @@ -1154,8 +1118,6 @@ x = __ENCODING__ assert_syntax_error('0000xyz', /^ \^~~\Z/) assert_syntax_error('1.2i1.1', /^ \^~~\Z/) assert_syntax_error('1.2.3', /^ \^~\Z/) - assert_syntax_error('1.', /unexpected end-of-input/) - assert_syntax_error('1e', /expecting end-of-input/) end def test_truncated_source_line @@ -1397,57 +1359,6 @@ x = __ENCODING__ end; end - def test_if_after_class - assert_valid_syntax('module if true; Object end::Kernel; end') - assert_valid_syntax('module while true; break Object end::Kernel; end') - assert_valid_syntax('class if true; Object end::Kernel; end') - assert_valid_syntax('class while true; break Object end::Kernel; end') - end - - def test_escaped_space - assert_syntax_error('x = \ 42', /escaped space/) - end - - def test_label - expected = {:foo => 1} - - code = '{"foo": 1}' - assert_valid_syntax(code) - assert_equal(expected, eval(code)) - - code = '{foo: 1}' - assert_valid_syntax(code) - assert_equal(expected, eval(code)) - - class << (obj = Object.new) - attr_reader :arg - def set(arg) - @arg = arg - end - end - - assert_valid_syntax(code = "#{<<~"do;"}\n#{<<~'end;'}") - do; - obj.set foo: - 1 - end; - assert_equal(expected, eval(code)) - assert_equal(expected, obj.arg) - - assert_valid_syntax(code = "#{<<~"do;"}\n#{<<~'end;'}") - do; - obj.set "foo": - 1 - end; - assert_equal(expected, eval(code)) - assert_equal(expected, obj.arg) - end - - def test_ungettable_gvar - assert_syntax_error('$01234', /not valid to get/) - assert_syntax_error('"#$01234"', /not valid to get/) - end - =begin def test_past_scope_variable assert_warning(/past scope/) {catch {|tag| eval("BEGIN{throw tag}; tap {a = 1}; a")}} diff --git a/test/ruby/test_pattern_matching.rb b/test/ruby/test_pattern_matching.rb index b761909913..4c203fb4f9 100644 --- a/test/ruby/test_pattern_matching.rb +++ b/test/ruby/test_pattern_matching.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true require 'test/unit' +experimental, Warning[:experimental] = Warning[:experimental], false # suppress "warning: Pattern matching is experimental, and the behavior may change in future versions of Ruby!" +eval "\n#{<<~'END_of_GUARD'}", binding, __FILE__, __LINE__ class TestPatternMatching < Test::Unit::TestCase class NullFormatter def message_for(corrections) @@ -9,14 +11,14 @@ class TestPatternMatching < Test::Unit::TestCase end def setup - if defined?(DidYouMean.formatter=nil) + if defined?(DidYouMean) @original_formatter = DidYouMean.formatter DidYouMean.formatter = NullFormatter.new end end def teardown - if defined?(DidYouMean.formatter=nil) + if defined?(DidYouMean) DidYouMean.formatter = @original_formatter end end @@ -109,12 +111,16 @@ class TestPatternMatching < Test::Unit::TestCase end assert_block do + # suppress "warning: Pattern matching is experimental, and the behavior may change in future versions of Ruby!" + experimental, Warning[:experimental] = Warning[:experimental], false eval(%q{ case true in a a end }) + ensure + Warning[:experimental] = experimental end assert_block do @@ -460,8 +466,6 @@ END true end end - - assert_valid_syntax("1 in ^(1\n)") end def test_array_pattern @@ -796,10 +800,6 @@ END true end end - - assert_syntax_error(%q{ - 0 => [a, *a] - }, /duplicated variable name/) end def test_find_pattern @@ -868,10 +868,6 @@ END false end end - - assert_syntax_error(%q{ - 0 => [*a, a, b, *b] - }, /duplicated variable name/) end def test_hash_pattern @@ -1161,28 +1157,6 @@ END end end - bug18890 = assert_warning(/(?:.*:[47]: warning: unused literal ignored\n){2}/) do - eval("#{<<~';;;'}") - proc do |i| - case i - in a: - 0 # line 4 - a - in "b": - 0 # line 7 - b - else - false - end - end - ;;; - end - [{a: 42}, {b: 42}].each do |i| - assert_block('newline should be significant after pattern label') do - bug18890.call(i) - end - end - assert_syntax_error(%q{ case _ in a:, a: @@ -1576,6 +1550,22 @@ END assert_equal false, (1 in 2) end + def assert_experimental_warning(code) + w = Warning[:experimental] + + Warning[:experimental] = false + assert_warn('') {eval(code)} + + Warning[:experimental] = true + assert_warn(/is experimental/) {eval(code)} + ensure + Warning[:experimental] = w + end + + def test_experimental_warning + assert_experimental_warning("case [0]; in [*, 0, *]; end") + end + def test_bug18990 {a: 0} => a: assert_equal 0, a @@ -1715,3 +1705,5 @@ END end end end +END_of_GUARD +Warning[:experimental] = experimental diff --git a/test/ruby/test_proc.rb b/test/ruby/test_proc.rb index 4245a7b785..51872e49be 100644 --- a/test/ruby/test_proc.rb +++ b/test/ruby/test_proc.rb @@ -289,6 +289,7 @@ class TestProc < Test::Unit::TestCase assert_equal(false, l.lambda?) assert_equal(false, l.curry.lambda?, '[ruby-core:24127]') assert_equal(false, proc(&l).lambda?) + assert_equal(false, assert_deprecated_warning {lambda(&l)}.lambda?) assert_equal(false, Proc.new(&l).lambda?) l = lambda {} assert_equal(true, l.lambda?) @@ -298,21 +299,47 @@ class TestProc < Test::Unit::TestCase assert_equal(true, Proc.new(&l).lambda?) end - def helper_test_warn_lambda_with_passed_block &b + def self.helper_test_warn_lamda_with_passed_block &b lambda(&b) end - def test_lambda_warning_pass_proc - assert_raise(ArgumentError) do - b = proc{} - lambda(&b) - end + def self.def_lambda_warning name, warn + define_method(name, proc do + prev = Warning[:deprecated] + assert_warn warn do + Warning[:deprecated] = true + yield + end + ensure + Warning[:deprecated] = prev + end) end - def test_lambda_warning_pass_block - assert_raise(ArgumentError) do - helper_test_warn_lambda_with_passed_block{} - end + def_lambda_warning 'test_lambda_warning_normal', '' do + lambda{} + end + + def_lambda_warning 'test_lambda_warning_pass_lambda', '' do + b = lambda{} + lambda(&b) + end + + def_lambda_warning 'test_lambda_warning_pass_symbol_proc', '' do + lambda(&:to_s) + end + + def_lambda_warning 'test_lambda_warning_pass_proc', /deprecated/ do + b = proc{} + lambda(&b) + end + + def_lambda_warning 'test_lambda_warning_pass_block', /deprecated/ do + helper_test_warn_lamda_with_passed_block{} + end + + def_lambda_warning 'test_lambda_warning_pass_block_symbol_proc', '' do + # Symbol#to_proc returns lambda + helper_test_warn_lamda_with_passed_block(&:to_s) end def test_curry_ski_fib @@ -385,11 +412,6 @@ class TestProc < Test::Unit::TestCase assert_equal(:foo, bc.foo) end - def test_dup_subclass - c1 = Class.new(Proc) - assert_equal c1, c1.new{}.dup.class, '[Bug #17545]' - end - def test_binding b = proc {|x, y, z| proc {}.binding }.call(1, 2, 3) class << b; attr_accessor :foo; end @@ -418,11 +440,6 @@ class TestProc < Test::Unit::TestCase assert_equal(@@line_of_source_location_test, lineno, 'Bug #2427') end - def test_binding_error_unless_ruby_frame - define_singleton_method :binding_from_c!, method(:binding).to_proc >> ->(bndg) {bndg} - assert_raise(RuntimeError) { binding_from_c! } - end - def test_proc_lambda assert_raise(ArgumentError) { proc } assert_raise(ArgumentError) { assert_warn(/deprecated/) {lambda} } @@ -830,88 +847,6 @@ class TestProc < Test::Unit::TestCase assert_equal [[1, 2], Proc, :x], (pr.call(1, 2){|x| x}) end - def test_proc_args_single_kw_no_autosplat - pr = proc {|c, a: 1| [c, a] } - assert_equal [nil, 1], pr.call() - assert_equal [1, 1], pr.call(1) - assert_equal [[1], 1], pr.call([1]) - assert_equal [1, 1], pr.call(1,2) - assert_equal [[1, 2], 1], pr.call([1,2]) - - assert_equal [nil, 3], pr.call(a: 3) - assert_equal [1, 3], pr.call(1, a: 3) - assert_equal [[1], 3], pr.call([1], a: 3) - assert_equal [1, 3], pr.call(1,2, a: 3) - assert_equal [[1, 2], 3], pr.call([1,2], a: 3) - end - - def test_proc_args_single_kwsplat_no_autosplat - pr = proc {|c, **kw| [c, kw] } - assert_equal [nil, {}], pr.call() - assert_equal [1, {}], pr.call(1) - assert_equal [[1], {}], pr.call([1]) - assert_equal [1, {}], pr.call(1,2) - assert_equal [[1, 2], {}], pr.call([1,2]) - - assert_equal [nil, {a: 3}], pr.call(a: 3) - assert_equal [1, {a: 3}], pr.call(1, a: 3) - assert_equal [[1], {a: 3}], pr.call([1], a: 3) - assert_equal [1, {a: 3}], pr.call(1,2, a: 3) - assert_equal [[1, 2], {a: 3}], pr.call([1,2], a: 3) - end - - def test_proc_args_multiple_kw_autosplat - pr = proc {|c, b, a: 1| [c, b, a] } - assert_equal [1, 2, 1], pr.call([1,2]) - - pr = proc {|c=nil, b=nil, a: 1| [c, b, a] } - assert_equal [nil, nil, 1], pr.call([]) - assert_equal [1, nil, 1], pr.call([1]) - assert_equal [1, 2, 1], pr.call([1,2]) - - pr = proc {|c, b=nil, a: 1| [c, b, a] } - assert_equal [1, nil, 1], pr.call([1]) - assert_equal [1, 2, 1], pr.call([1,2]) - - pr = proc {|c=nil, b, a: 1| [c, b, a] } - assert_equal [nil, 1, 1], pr.call([1]) - assert_equal [1, 2, 1], pr.call([1,2]) - - pr = proc {|c, *b, a: 1| [c, b, a] } - assert_equal [1, [], 1], pr.call([1]) - assert_equal [1, [2], 1], pr.call([1,2]) - - pr = proc {|*c, b, a: 1| [c, b, a] } - assert_equal [[], 1, 1], pr.call([1]) - assert_equal [[1], 2, 1], pr.call([1,2]) - end - - def test_proc_args_multiple_kwsplat_autosplat - pr = proc {|c, b, **kw| [c, b, kw] } - assert_equal [1, 2, {}], pr.call([1,2]) - - pr = proc {|c=nil, b=nil, **kw| [c, b, kw] } - assert_equal [nil, nil, {}], pr.call([]) - assert_equal [1, nil, {}], pr.call([1]) - assert_equal [1, 2, {}], pr.call([1,2]) - - pr = proc {|c, b=nil, **kw| [c, b, kw] } - assert_equal [1, nil, {}], pr.call([1]) - assert_equal [1, 2, {}], pr.call([1,2]) - - pr = proc {|c=nil, b, **kw| [c, b, kw] } - assert_equal [nil, 1, {}], pr.call([1]) - assert_equal [1, 2, {}], pr.call([1,2]) - - pr = proc {|c, *b, **kw| [c, b, kw] } - assert_equal [1, [], {}], pr.call([1]) - assert_equal [1, [2], {}], pr.call([1,2]) - - pr = proc {|*c, b, **kw| [c, b, kw] } - assert_equal [[], 1, {}], pr.call([1]) - assert_equal [[1], 2, {}], pr.call([1,2]) - end - def test_proc_args_only_rest pr = proc {|*c| c } assert_equal [], pr.call() @@ -1294,54 +1229,6 @@ class TestProc < Test::Unit::TestCase assert_empty(pr.parameters.map{|_,n|n}.compact) end - def test_proc_autosplat_with_multiple_args_with_ruby2_keywords_splat_bug_19759 - def self.yielder_ab(splat) - yield([:a, :b], *splat) - end - - res = yielder_ab([[:aa, :bb], Hash.ruby2_keywords_hash({k: :k})]) do |a, b, k:| - [a, b, k] - end - assert_equal([[:a, :b], [:aa, :bb], :k], res) - - def self.yielder(splat) - yield(*splat) - end - res = yielder([ [:a, :b] ]){|a, b, **| [a, b]} - assert_equal([:a, :b], res) - - res = yielder([ [:a, :b], Hash.ruby2_keywords_hash({}) ]){|a, b, **| [a, b]} - assert_equal([[:a, :b], nil], res) - - res = yielder([ [:a, :b], Hash.ruby2_keywords_hash({c: 1}) ]){|a, b, **| [a, b]} - assert_equal([[:a, :b], nil], res) - - res = yielder([ [:a, :b], Hash.ruby2_keywords_hash({}) ]){|a, b, **nil| [a, b]} - assert_equal([[:a, :b], nil], res) - end - - def test_parameters_lambda - assert_equal([], proc {}.parameters(lambda: true)) - assert_equal([], proc {||}.parameters(lambda: true)) - assert_equal([[:req, :a]], proc {|a|}.parameters(lambda: true)) - assert_equal([[:req, :a], [:req, :b]], proc {|a, b|}.parameters(lambda: true)) - assert_equal([[:opt, :a], [:block, :b]], proc {|a=:a, &b|}.parameters(lambda: true)) - assert_equal([[:req, :a], [:opt, :b]], proc {|a, b=:b|}.parameters(lambda: true)) - assert_equal([[:rest, :a]], proc {|*a|}.parameters(lambda: true)) - assert_equal([[:req, :a], [:rest, :b], [:block, :c]], proc {|a, *b, &c|}.parameters(lambda: true)) - assert_equal([[:req, :a], [:rest, :b], [:req, :c]], proc {|a, *b, c|}.parameters(lambda: true)) - assert_equal([[:req, :a], [:rest, :b], [:req, :c], [:block, :d]], proc {|a, *b, c, &d|}.parameters(lambda: true)) - assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:block, :e]], proc {|a, b=:b, *c, d, &e|}.parameters(lambda: true)) - assert_equal([[:req], [:block, :b]], proc {|(a), &b|a}.parameters(lambda: true)) - assert_equal([[:req, :a], [:req, :b], [:opt, :c], [:opt, :d], [:rest, :e], [:req, :f], [:req, :g], [:block, :h]], proc {|a,b,c=:c,d=:d,*e,f,g,&h|}.parameters(lambda: true)) - - pr = eval("proc{|"+"(_),"*30+"|}") - assert_empty(pr.parameters(lambda: true).map{|_,n|n}.compact) - - assert_equal([[:opt, :a]], lambda {|a|}.parameters(lambda: false)) - assert_equal([[:opt, :a], [:opt, :b], [:opt, :c], [:opt, :d], [:rest, :e], [:opt, :f], [:opt, :g], [:block, :h]], lambda {|a,b,c=:c,d=:d,*e,f,g,&h|}.parameters(lambda: false)) - end - def pm0() end def pm1(a) end def pm2(a, b) end @@ -1374,7 +1261,7 @@ class TestProc < Test::Unit::TestCase assert_equal([[:req, :a], [:rest, :b], [:req, :c], [:block, :d]], method(:pmo6).to_proc.parameters) assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:block, :e]], method(:pmo7).to_proc.parameters) assert_equal([[:req], [:block, :b]], method(:pma1).to_proc.parameters) - assert_equal([[:keyrest, :**]], method(:pmk1).to_proc.parameters) + assert_equal([[:keyrest]], method(:pmk1).to_proc.parameters) assert_equal([[:keyrest, :o]], method(:pmk2).to_proc.parameters) assert_equal([[:req, :a], [:keyrest, :o]], method(:pmk3).to_proc.parameters) assert_equal([[:opt, :a], [:keyrest, :o]], method(:pmk4).to_proc.parameters) diff --git a/test/ruby/test_process.rb b/test/ruby/test_process.rb index 38a29f8332..30427aeec1 100644 --- a/test/ruby/test_process.rb +++ b/test/ruby/test_process.rb @@ -3,6 +3,7 @@ require 'test/unit' require 'tempfile' require 'timeout' +require 'io/wait' require 'rbconfig' class TestProcess < Test::Unit::TestCase @@ -168,7 +169,7 @@ class TestProcess < Test::Unit::TestCase end def test_execopts_pgroup - omit "system(:pgroup) is not supported" if windows? + skip "system(:pgroup) is not supported" if windows? assert_nothing_raised { system(*TRUECOMMAND, :pgroup=>false) } io = IO.popen([RUBY, "-e", "print Process.getpgrp"]) @@ -272,7 +273,7 @@ class TestProcess < Test::Unit::TestCase end; end - MANDATORY_ENVS = %w[RUBYLIB RJIT_SEARCH_BUILD_DIR] + MANDATORY_ENVS = %w[RUBYLIB MJIT_SEARCH_BUILD_DIR] case RbConfig::CONFIG['target_os'] when /linux/ MANDATORY_ENVS << 'LD_PRELOAD' @@ -510,7 +511,7 @@ class TestProcess < Test::Unit::TestCase UMASK = [RUBY, '-e', 'printf "%04o\n", File.umask'] def test_execopts_umask - omit "umask is not supported" if windows? + skip "umask is not supported" if windows? IO.popen([*UMASK, :umask => 0]) {|io| assert_equal("0000", io.read.chomp) } @@ -665,7 +666,6 @@ class TestProcess < Test::Unit::TestCase end unless windows? # does not support fifo def test_execopts_redirect_open_fifo_interrupt_raise - pid = nil with_tmpchdir {|d| begin File.mkfifo("fifo") @@ -683,21 +683,15 @@ class TestProcess < Test::Unit::TestCase puts "ok" end EOS - pid = io.pid assert_equal("start\n", io.gets) sleep 0.5 Process.kill(:USR1, io.pid) assert_equal("ok\n", io.read) } - assert_equal(pid, $?.pid) - assert_predicate($?, :success?) } - ensure - assert_raise(Errno::ESRCH) {Process.kill(:KILL, pid)} if pid end unless windows? # does not support fifo def test_execopts_redirect_open_fifo_interrupt_print - pid = nil with_tmpchdir {|d| begin File.mkfifo("fifo") @@ -710,7 +704,6 @@ class TestProcess < Test::Unit::TestCase puts "start" system("cat", :in => "fifo") EOS - pid = io.pid assert_equal("start\n", io.gets) sleep 0.2 # wait for the child to stop at opening "fifo" Process.kill(:USR1, io.pid) @@ -718,13 +711,7 @@ class TestProcess < Test::Unit::TestCase File.write("fifo", "ok\n") assert_equal("ok\n", io.read) } - assert_equal(pid, $?.pid) - assert_predicate($?, :success?) } - ensure - if pid - assert_raise(Errno::ESRCH) {Process.kill(:KILL, pid)} - end end unless windows? # does not support fifo def test_execopts_redirect_pipe @@ -850,7 +837,7 @@ class TestProcess < Test::Unit::TestCase STDERR=>"out", STDOUT=>[:child, STDERR]) assert_equal("errout", File.read("out")) - omit "inheritance of fd other than stdin,stdout and stderr is not supported" if windows? + skip "inheritance of fd other than stdin,stdout and stderr is not supported" if windows? Process.wait spawn(RUBY, "-e", "STDERR.print 'err'; STDOUT.print 'out'", STDOUT=>"out", STDERR=>[:child, 3], @@ -902,7 +889,7 @@ class TestProcess < Test::Unit::TestCase end def test_execopts_popen_extra_fd - omit "inheritance of fd other than stdin,stdout and stderr is not supported" if windows? + skip "inheritance of fd other than stdin,stdout and stderr is not supported" if windows? with_tmpchdir {|d| with_pipe {|r, w| IO.popen([RUBY, '-e', 'IO.new(3, "w").puts("a"); puts "b"', 3=>w]) {|io| @@ -931,7 +918,7 @@ class TestProcess < Test::Unit::TestCase end def test_fd_inheritance - omit "inheritance of fd other than stdin,stdout and stderr is not supported" if windows? + skip "inheritance of fd other than stdin,stdout and stderr is not supported" if windows? with_pipe {|r, w| system(RUBY, '-e', 'IO.new(ARGV[0].to_i, "w").puts(:ba)', w.fileno.to_s, w=>w) w.close @@ -977,7 +964,7 @@ class TestProcess < Test::Unit::TestCase end def test_execopts_close_others - omit "inheritance of fd other than stdin,stdout and stderr is not supported" if windows? + skip "inheritance of fd other than stdin,stdout and stderr is not supported" if windows? with_tmpchdir {|d| with_pipe {|r, w| system(RUBY, '-e', 'STDERR.reopen("err", "w"); IO.new(ARGV[0].to_i, "w").puts("ma")', w.fileno.to_s, :close_others=>true) @@ -1071,7 +1058,7 @@ class TestProcess < Test::Unit::TestCase } } rescue NotImplementedError - omit "IO#close_on_exec= is not supported" + skip "IO#close_on_exec= is not supported" end end unless windows? # passing non-stdio fds is not supported on Windows @@ -1438,11 +1425,6 @@ class TestProcess < Test::Unit::TestCase REPRO end - def test_argv0_frozen - assert_predicate Process.argv0, :frozen? - assert_predicate $0, :frozen? - end - def test_status with_tmpchdir do s = run_in_child("exit 1") @@ -1565,8 +1547,6 @@ class TestProcess < Test::Unit::TestCase assert_operator(diff, :<, sec, ->{"#{bug11340}: #{diff} seconds to interrupt Process.wait"}) f.puts - rescue Errno::EPIPE - omit "child process exited already in #{diff} seconds" end end @@ -1630,7 +1610,7 @@ class TestProcess < Test::Unit::TestCase else assert_kind_of(Integer, max) assert_predicate(max, :positive?) - omit "not limited to NGROUPS_MAX" if /darwin/ =~ RUBY_PLATFORM + skip "not limited to NGROUPS_MAX" if /darwin/ =~ RUBY_PLATFORM gs = Process.groups assert_operator(gs.size, :<=, max) gs[0] ||= 0 @@ -1657,7 +1637,7 @@ class TestProcess < Test::Unit::TestCase end def test_setegid - omit "root can use Process.egid on Android platform" if RUBY_PLATFORM =~ /android/ + skip "root can use Process.egid on Android platform" if RUBY_PLATFORM =~ /android/ assert_nothing_raised(TypeError) {Process.egid += 0} rescue NotImplementedError end @@ -1715,6 +1695,11 @@ class TestProcess < Test::Unit::TestCase end def test_wait_and_sigchild + if /freebsd|openbsd/ =~ RUBY_PLATFORM + # this relates #4173 + # When ruby can use 2 cores, signal and wait4 may miss the signal. + skip "this fails on FreeBSD and OpenBSD on multithreaded environment" + end signal_received = [] IO.pipe do |sig_r, sig_w| Signal.trap(:CHLD) do @@ -1733,7 +1718,7 @@ class TestProcess < Test::Unit::TestCase Process.wait pid assert_send [sig_r, :wait_readable, 5], 'self-pipe not readable' end - if defined?(RubyVM::RJIT) && RubyVM::RJIT.enabled? # checking -DRJIT_FORCE_ENABLE. It may trigger extra SIGCHLD. + if defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? # checking -DMJIT_FORCE_ENABLE. It may trigger extra SIGCHLD. assert_equal [true], signal_received.uniq, "[ruby-core:19744]" else assert_equal [true], signal_received, "[ruby-core:19744]" @@ -1748,7 +1733,7 @@ class TestProcess < Test::Unit::TestCase def test_no_curdir if /solaris/i =~ RUBY_PLATFORM - omit "Temporary omit to avoid CI failures after commit to use realpath on required files" + skip "Temporary skip to avoid CI failures after commit to use realpath on required files" end with_tmpchdir {|d| Dir.mkdir("vd") @@ -1790,7 +1775,7 @@ class TestProcess < Test::Unit::TestCase def test_aspawn_too_long_path if /solaris/i =~ RUBY_PLATFORM && !defined?(Process::RLIMIT_NPROC) - omit "Too exhaustive test on platforms without Process::RLIMIT_NPROC such as Solaris 10" + skip "Too exhaustive test on platforms without Process::RLIMIT_NPROC such as Solaris 10" end bug4315 = '[ruby-core:34833] #7904 [ruby-core:52628] #11613' assert_fail_too_long_path(%w"echo |", bug4315) @@ -1804,20 +1789,14 @@ class TestProcess < Test::Unit::TestCase exs << Errno::EINVAL if windows? exs << Errno::E2BIG if defined?(Errno::E2BIG) opts = {[STDOUT, STDERR]=>File::NULL} - if defined?(Process::RLIMIT_NPROC) - opts[:rlimit_nproc] = /openbsd/i =~ RUBY_PLATFORM ? 64 : 128 - end + opts[:rlimit_nproc] = 128 if defined?(Process::RLIMIT_NPROC) EnvUtil.suppress_warning do assert_raise(*exs, mesg) do begin loop do Process.spawn(cmds.join(sep), opts) min = [cmds.size, min].max - begin - cmds *= 100 - rescue ArgumentError - raise NoMemoryError - end + cmds *= 100 end rescue NoMemoryError size = cmds.size @@ -1838,7 +1817,7 @@ class TestProcess < Test::Unit::TestCase with_tmpchdir do assert_nothing_raised('[ruby-dev:12261]') do - EnvUtil.timeout(10) do + EnvUtil.timeout(3) do pid = spawn('yes | ls') Process.waitpid pid end @@ -1859,6 +1838,8 @@ class TestProcess < Test::Unit::TestCase end def test_daemon_noclose + pend "macOS 15 beta is not working with this test" if /darwin/ =~ RUBY_PLATFORM && /15/ =~ `sw_vers -productVersion` + data = IO.popen("-", "r+") do |f| break f.read if f Process.daemon(false, true) @@ -1897,28 +1878,6 @@ class TestProcess < Test::Unit::TestCase assert_not_equal(cpid, dpid) end - def test_daemon_detached - IO.popen("-", "r+") do |f| - if f - assert_equal(f.pid, Process.wait(f.pid)) - - dpid, ppid, dsid = 3.times.map {Integer(f.gets)} - - message = "daemon #{dpid} should be detached" - assert_not_equal($$, ppid, message) # would be 1 almost always - assert_raise(Errno::ECHILD, message) {Process.wait(dpid)} - assert_kind_of(Integer, Process.kill(0, dpid), message) - assert_equal(dpid, dsid) - - break # close f, and let the daemon resume and exit - end - Process.setsid rescue nil - Process.daemon(false, true) - puts $$, Process.ppid, Process.getsid - $stdin.gets # wait for the above assertions using signals - end - end - if File.directory?("/proc/self/task") && /netbsd[a-z]*[1-6]/ !~ RUBY_PLATFORM def test_daemon_no_threads pid, data = IO.popen("-", "r+") do |f| @@ -2001,7 +1960,7 @@ class TestProcess < Test::Unit::TestCase end def test_execopts_uid - omit "root can use uid option of Kernel#system on Android platform" if RUBY_PLATFORM =~ /android/ + skip "root can use uid option of Kernel#system on Android platform" if RUBY_PLATFORM =~ /android/ feature6975 = '[ruby-core:47414]' [30000, [Process.uid, ENV["USER"]]].each do |uid, user| @@ -2032,8 +1991,8 @@ class TestProcess < Test::Unit::TestCase end def test_execopts_gid - omit "Process.groups not implemented on Windows platform" if windows? - omit "root can use Process.groups on Android platform" if RUBY_PLATFORM =~ /android/ + skip "Process.groups not implemented on Windows platform" if windows? + skip "root can use Process.groups on Android platform" if RUBY_PLATFORM =~ /android/ feature6975 = '[ruby-core:47414]' groups = Process.groups.map do |g| @@ -2177,9 +2136,7 @@ EOS t3 = Process.clock_gettime(Process::CLOCK_REALTIME, :nanosecond) assert_operator(t1, :<=, t2) assert_operator(t2, :<=, t3) - assert_raise_with_message(Errno::EINVAL, /:foo/) do - Process.clock_gettime(:foo) - end + assert_raise(Errno::EINVAL) { Process.clock_gettime(:foo) } end def test_clock_gettime_unit @@ -2284,9 +2241,7 @@ EOS rescue Errno::EINVAL else assert_kind_of(Integer, r) - assert_raise_with_message(Errno::EINVAL, /:foo/) do - Process.clock_getres(:foo) - end + assert_raise(Errno::EINVAL) { Process.clock_getres(:foo) } end def test_clock_getres_constants @@ -2373,7 +2328,7 @@ EOS end def test_deadlock_by_signal_at_forking - assert_separately(%W(- #{RUBY}), <<-INPUT, timeout: 100) + assert_separately(%W(--disable=gems - #{RUBY}), <<-INPUT, timeout: 100) ruby = ARGV.shift GC.start # reduce garbage GC.disable # avoid triggering CoW after forks @@ -2558,7 +2513,7 @@ EOS end def test_forked_child_handles_signal - omit "fork not supported" unless Process.respond_to?(:fork) + skip "fork not supported" unless Process.respond_to?(:fork) assert_normal_exit(<<-"end;", '[ruby-core:82883] [Bug #13916]') require 'timeout' pid = fork { sleep } @@ -2612,26 +2567,6 @@ EOS end end if Process.respond_to?(:_fork) - def test__fork_pid_cache - _parent_pid = Process.pid - r, w = IO.pipe - pid = Process._fork - if pid == 0 - begin - r.close - w << "ok: #{Process.pid}" - w.close - ensure - exit! - end - else - w.close - assert_equal("ok: #{pid}", r.read) - r.close - Process.waitpid(pid) - end - end if Process.respond_to?(:_fork) - def test__fork_hook %w(fork Process.fork).each do |method| feature17795 = '[ruby-core:103400] [Feature #17795]' @@ -2705,68 +2640,58 @@ EOS end; end if Process.respond_to?(:_fork) - def test_warmup_promote_all_objects_to_oldgen - assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") - require 'objspace' - begin; - obj = Object.new - - assert_not_include(ObjectSpace.dump(obj), '"old":true') - Process.warmup - assert_include(ObjectSpace.dump(obj), '"old":true') - end; - end - - def test_warmup_run_major_gc_and_compact - assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") - begin; - # Run a GC to ensure that we are not in the middle of a GC run - GC.start - - major_gc_count = GC.stat(:major_gc_count) - compact_count = GC.stat(:compact_count) - Process.warmup - assert_equal major_gc_count + 1, GC.stat(:major_gc_count) - assert_equal compact_count + 1, GC.stat(:compact_count) - end; - end - - def test_warmup_precompute_string_coderange - assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") - require 'objspace' - begin; - obj = "a" * 12 - obj.force_encoding(Encoding::BINARY) - assert_include(ObjectSpace.dump(obj), '"coderange":"unknown"') - Process.warmup - assert_include(ObjectSpace.dump(obj), '"coderange":"7bit"') - end; - end - - def test_warmup_frees_pages - assert_separately([{"RUBY_GC_HEAP_FREE_SLOTS_MAX_RATIO" => "1.0"}, "-W0"], "#{<<~"begin;"}\n#{<<~'end;'}") - begin; - GC.start - - TIMES = 10_000 - ary = Array.new(TIMES) - TIMES.times do |i| - ary[i] = Object.new + def test_concurrent_group_and_pid_wait + # Use a pair of pipes that will make long_pid exit when this test exits, to avoid + # leaking temp processes. + long_rpipe, long_wpipe = IO.pipe + short_rpipe, short_wpipe = IO.pipe + # This process should run forever + long_pid = fork do + [short_rpipe, short_wpipe, long_wpipe].each(&:close) + long_rpipe.read + end + # This process will exit + short_pid = fork do + [long_rpipe, long_wpipe, short_wpipe].each(&:close) + short_rpipe.read + end + t1, t2, t3 = nil + EnvUtil.timeout(5) do + t1 = Thread.new do + Process.waitpid long_pid end - ary.clear - ary = nil + # Wait for us to be blocking in a call to waitpid2 + Thread.pass until t1.stop? + short_wpipe.close # Make short_pid exit - # Disable GC so we can make sure GC only runs in Process.warmup - GC.disable + # The short pid has exited, so -1 should pick that up. + assert_equal short_pid, Process.waitpid(-1) - total_pages_before = GC.stat(:heap_eden_pages) + GC.stat(:heap_allocatable_pages) + # Terminate t1 for the next phase of the test. + t1.kill + t1.join - Process.warmup + t2 = Thread.new do + Process.waitpid -1 + rescue Errno::ECHILD + nil + end + Thread.pass until t2.stop? + t3 = Thread.new do + Process.waitpid long_pid + rescue Errno::ECHILD + nil + end + Thread.pass until t3.stop? - # Number of pages freed should cause equal increase in number of allocatable pages. - assert_equal(total_pages_before, GC.stat(:heap_eden_pages) + GC.stat(:heap_allocatable_pages)) - assert_equal(0, GC.stat(:heap_tomb_pages), GC.stat) - assert_operator(GC.stat(:total_freed_pages), :>, 0) - end; - end + # it's actually nondeterministic which of t2 or t3 will receive the wait (this + # nondeterminism comes from the behaviour of the underlying system calls) + long_wpipe.close + assert_equal [long_pid], [t2, t3].map(&:value).compact + end + ensure + [t1, t2, t3].each { _1&.kill rescue nil } + [t1, t2, t3].each { _1&.join rescue nil } + [long_rpipe, long_wpipe, short_rpipe, short_wpipe].each { _1&.close rescue nil } + end if defined?(fork) end diff --git a/test/ruby/test_rand.rb b/test/ruby/test_rand.rb index a4beffd689..13b7329269 100644 --- a/test/ruby/test_rand.rb +++ b/test/ruby/test_rand.rb @@ -317,7 +317,7 @@ class TestRand < Test::Unit::TestCase assert_equal(r1, r2, bug5661) assert_fork_status(1, '[ruby-core:82100] [Bug #13753]') do - Random.rand(4) + Random::DEFAULT.rand(4) end rescue NotImplementedError end @@ -336,14 +336,6 @@ class TestRand < Test::Unit::TestCase } end - def test_seed_leading_zero_guard - guard = 1<<32 - range = 0...(1<<32) - all_assertions_foreach(nil, 0, 1, 2) do |i| - assert_not_equal(Random.new(i).rand(range), Random.new(i+guard).rand(range)) - end - end - def test_marshal bug3656 = '[ruby-core:31622]' assert_raise(TypeError, bug3656) { @@ -403,8 +395,8 @@ class TestRand < Test::Unit::TestCase assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") begin; verbose, $VERBOSE = $VERBOSE, nil - seed = Random.seed - rand1 = Random.rand + seed = Random::DEFAULT::seed + rand1 = Random::DEFAULT::rand $VERBOSE = verbose rand2 = Random.new(seed).rand assert_equal(rand1, rand2) diff --git a/test/ruby/test_random_formatter.rb b/test/ruby/test_random_formatter.rb index 2c01d99b3d..a5072099e1 100644 --- a/test/ruby/test_random_formatter.rb +++ b/test/ruby/test_random_formatter.rb @@ -83,20 +83,6 @@ module Random::Formatter end end - def test_alphanumeric_chars - [ - [[*"0".."9"], /\A\d*\z/], - [[*"a".."t"], /\A[a-t]*\z/], - ["一二三四五六七八九十".chars, /\A[一二三四五六七八九十]*\z/], - ].each do |chars, pattern| - 10.times do |n| - an = @it.alphanumeric(n, chars: chars) - assert_match(pattern, an) - assert_equal(n, an.length) - end - end - end - def assert_in_range(range, result, mesg = nil) assert(range.cover?(result), build_message(mesg, "Expected #{result} to be in #{range}")) end diff --git a/test/ruby/test_range.rb b/test/ruby/test_range.rb index 820ca9e9c2..dc591b0604 100644 --- a/test/ruby/test_range.rb +++ b/test/ruby/test_range.rb @@ -2,6 +2,7 @@ require 'test/unit' require 'delegate' require 'timeout' +require 'bigdecimal' require 'rbconfig/sizeof' class TestRange < Test::Unit::TestCase @@ -391,26 +392,6 @@ class TestRange < Test::Unit::TestCase assert_equal(4, (1.0...5.6).step(1.5).to_a.size) end - def test_step_with_succ - c = Struct.new(:i) do - def succ; self.class.new(i+1); end - def <=>(other) i <=> other.i;end - end.new(0) - - result = [] - (c..c.succ).step(2) do |d| - result << d.i - end - assert_equal([0], result) - - result = [] - (c..).step(2) do |d| - result << d.i - break if d.i >= 4 - end - assert_equal([0, 2, 4], result) - end - def test_each a = [] (0..10).each {|x| a << x } @@ -475,26 +456,6 @@ class TestRange < Test::Unit::TestCase assert_equal(["a", "b", "c"], a) end - def test_each_with_succ - c = Struct.new(:i) do - def succ; self.class.new(i+1); end - def <=>(other) i <=> other.i;end - end.new(0) - - result = [] - (c..c.succ).each do |d| - result << d.i - end - assert_equal([0, 1], result) - - result = [] - (c..).each do |d| - result << d.i - break if d.i >= 4 - end - assert_equal([0, 1, 2, 3, 4], result) - end - def test_begin_end assert_equal(0, (0..1).begin) assert_equal(1, (0..1).end) @@ -578,8 +539,6 @@ class TestRange < Test::Unit::TestCase assert_not_operator(0..10, :===, 11) assert_operator(5..nil, :===, 11) assert_not_operator(5..nil, :===, 0) - assert_operator(nil..10, :===, 0) - assert_operator(nil..nil, :===, 0) end def test_eqq_string @@ -587,7 +546,7 @@ class TestRange < Test::Unit::TestCase assert_not_operator('A'..'Z', :===, 'ana') assert_operator('A'.., :===, 'ANA') assert_operator(..'Z', :===, 'ANA') - assert_raise(TypeError) {(nil..nil) === 'ANA'} + assert_operator(nil..nil, :===, 'ANA') end def test_eqq_time @@ -640,16 +599,11 @@ class TestRange < Test::Unit::TestCase assert_include("a"..."z", "y") assert_not_include("a"..."z", "z") assert_not_include("a".."z", "cc") - assert_raise(TypeError) {("a"..).include?("c")} - assert_raise(TypeError) {("a"..).include?("5")} - + assert_include("a".., "c") + assert_not_include("a".., "5") assert_include(0...10, 5) assert_include(5..., 10) assert_not_include(5..., 0) - assert_raise(TypeError) {(.."z").include?("z")} - assert_raise(TypeError) {(..."z").include?("z")} - assert_include(..10, 10) - assert_not_include(...10, 10) end def test_cover @@ -819,9 +773,6 @@ class TestRange < Test::Unit::TestCase assert_equal 5, (1.1...6).size assert_equal 42, (1..42).each.size assert_nil ("a"..."z").size - assert_nil ("a"...).size - assert_nil (..."z").size # [Bug #18983] - assert_nil (nil...nil).size # [Bug #18983] assert_equal Float::INFINITY, (1...).size assert_equal Float::INFINITY, (1.0...).size @@ -851,6 +802,9 @@ class TestRange < Test::Unit::TestCase assert_raise(TypeError) { (Rational(-1,2)..Rational(9,4)).bsearch } + assert_raise(TypeError) { + (BigDecimal('0.5')..BigDecimal('2.25')).bsearch + } end def test_bsearch_for_fixnum diff --git a/test/ruby/test_rational.rb b/test/ruby/test_rational.rb index a51ce3dc99..fe9de64c4c 100644 --- a/test/ruby/test_rational.rb +++ b/test/ruby/test_rational.rb @@ -823,8 +823,6 @@ class Rational_Test < Test::Unit::TestCase ng[5, 1, '5/_3'] ng[5, 3, '5/3_'] ng[5, 3, '5/3x'] - - ng[5, 1, '5/-3'] end def test_parse_zero_denominator diff --git a/test/ruby/test_refinement.rb b/test/ruby/test_refinement.rb index c078f61895..19857b035c 100644 --- a/test/ruby/test_refinement.rb +++ b/test/ruby/test_refinement.rb @@ -225,7 +225,7 @@ class TestRefinement < Test::Unit::TestCase end end def test_method_should_use_refinements - omit if Test::Unit::Runner.current_repeat_count > 0 + skip if Test::Unit::Runner.current_repeat_count > 0 foo = Foo.new assert_raise(NameError) { foo.method(:z) } @@ -248,7 +248,7 @@ class TestRefinement < Test::Unit::TestCase end end def test_instance_method_should_use_refinements - omit if Test::Unit::Runner.current_repeat_count > 0 + skip if Test::Unit::Runner.current_repeat_count > 0 foo = Foo.new assert_raise(NameError) { Foo.instance_method(:z) } @@ -754,32 +754,136 @@ class TestRefinement < Test::Unit::TestCase $VERBOSE = verbose end - def test_include_into_refinement - assert_raise(TypeError) do - c = Class.new - mixin = Module.new + module IncludeIntoRefinement + class C + def bar + return "C#bar" + end - Module.new do - refine c do - include mixin + def baz + return "C#baz" + end + end + + module Mixin + def foo + return "Mixin#foo" + end + + def bar + return super << " Mixin#bar" + end + + def baz + return super << " Mixin#baz" + end + end + + module M + refine C do + TestRefinement.suppress_verbose do + include Mixin + end + + def baz + return super << " M#baz" end end end end - def test_prepend_into_refinement - assert_raise(TypeError) do - c = Class.new - mixin = Module.new + eval <<-EOF, Sandbox::BINDING + using TestRefinement::IncludeIntoRefinement::M - Module.new do - refine c do - prepend mixin + module TestRefinement::IncludeIntoRefinement::User + def self.invoke_foo_on(x) + x.foo + end + + def self.invoke_bar_on(x) + x.bar + end + + def self.invoke_baz_on(x) + x.baz + end + end + EOF + + def test_include_into_refinement + x = IncludeIntoRefinement::C.new + assert_equal("Mixin#foo", IncludeIntoRefinement::User.invoke_foo_on(x)) + assert_equal("C#bar Mixin#bar", + IncludeIntoRefinement::User.invoke_bar_on(x)) + assert_equal("C#baz Mixin#baz M#baz", + IncludeIntoRefinement::User.invoke_baz_on(x)) + end + + module PrependIntoRefinement + class C + def bar + return "C#bar" + end + + def baz + return "C#baz" + end + end + + module Mixin + def foo + return "Mixin#foo" + end + + def bar + return super << " Mixin#bar" + end + + def baz + return super << " Mixin#baz" + end + end + + module M + refine C do + TestRefinement.suppress_verbose do + prepend Mixin + end + + def baz + return super << " M#baz" end end end end + eval <<-EOF, Sandbox::BINDING + using TestRefinement::PrependIntoRefinement::M + + module TestRefinement::PrependIntoRefinement::User + def self.invoke_foo_on(x) + x.foo + end + + def self.invoke_bar_on(x) + x.bar + end + + def self.invoke_baz_on(x) + x.baz + end + end + EOF + + def test_prepend_into_refinement + x = PrependIntoRefinement::C.new + assert_equal("Mixin#foo", PrependIntoRefinement::User.invoke_foo_on(x)) + assert_equal("C#bar Mixin#bar", + PrependIntoRefinement::User.invoke_bar_on(x)) + assert_equal("C#baz M#baz Mixin#baz", + PrependIntoRefinement::User.invoke_baz_on(x)) + end + PrependAfterRefine_CODE = <<-EOC module PrependAfterRefine class C @@ -819,7 +923,7 @@ class TestRefinement < Test::Unit::TestCase def test_prepend_after_refine_wb_miss if /\A(arm|mips)/ =~ RUBY_PLATFORM - omit "too slow cpu" + skip "too slow cpu" end assert_normal_exit %Q{ GC.stress = true @@ -1206,41 +1310,6 @@ class TestRefinement < Test::Unit::TestCase INPUT end - def test_refined_protected_methods - assert_separately([], <<-"end;") - bug18806 = '[ruby-core:108705] [Bug #18806]' - class C; end - - module R - refine C do - def refined_call_foo = foo - def refined_call_foo_on(other) = other.foo - - protected - - def foo = :foo - end - end - - class C - using R - - def call_foo = foo - def call_foo_on(other) = other.foo - end - - c = C.new - assert_equal :foo, c.call_foo, bug18806 - assert_equal :foo, c.call_foo_on(c), bug18806 - assert_equal :foo, c.call_foo_on(C.new), bug18806 - - using R - assert_equal :foo, c.refined_call_foo, bug18806 - assert_equal :foo, c.refined_call_foo_on(c), bug18806 - assert_equal :foo, c.refined_call_foo_on(C.new), bug18806 - end; - end - def test_refine_basic_object assert_separately([], <<-"end;") bug10106 = '[ruby-core:64166] [Bug #10106]' @@ -1722,8 +1791,6 @@ class TestRefinement < Test::Unit::TestCase refine Object do def in_ref_a end - - RefA.const_set(:REF, self) end end @@ -1731,8 +1798,6 @@ class TestRefinement < Test::Unit::TestCase refine Object do def in_ref_b end - - RefB.const_set(:REF, self) end end @@ -1742,28 +1807,23 @@ class TestRefinement < Test::Unit::TestCase refine Object do def in_ref_c end - - RefC.const_set(:REF, self) end end module Foo using RefB USED_MODS = Module.used_modules - USED_REFS = Module.used_refinements end module Bar using RefC USED_MODS = Module.used_modules - USED_REFS = Module.used_refinements end module Combined using RefA using RefB USED_MODS = Module.used_modules - USED_REFS = Module.used_refinements end end @@ -1775,47 +1835,6 @@ class TestRefinement < Test::Unit::TestCase assert_equal [ref::RefB, ref::RefA], ref::Combined::USED_MODS end - def test_used_refinements - ref = VisibleRefinements - assert_equal [], Module.used_refinements - assert_equal [ref::RefB::REF], ref::Foo::USED_REFS - assert_equal [ref::RefC::REF], ref::Bar::USED_REFS - assert_equal [ref::RefB::REF, ref::RefA::REF], ref::Combined::USED_REFS - end - - def test_refinements - int_refinement = nil - str_refinement = nil - m = Module.new { - refine Integer do - int_refinement = self - end - - refine String do - str_refinement = self - end - } - assert_equal([int_refinement, str_refinement], m.refinements) - end - - def test_target - refinements = Module.new { - refine Integer do - end - - refine String do - end - }.refinements - assert_equal(Integer, refinements[0].target) - assert_warn(/Refinement#refined_class is deprecated and will be removed in Ruby 3.4; use Refinement#target instead/) do - assert_equal(Integer, refinements[0].refined_class) - end - assert_equal(String, refinements[1].target) - assert_warn(/Refinement#refined_class is deprecated and will be removed in Ruby 3.4; use Refinement#target instead/) do - assert_equal(String, refinements[1].refined_class) - end - end - def test_warn_setconst_in_refinmenet bug10103 = '[ruby-core:64143] [Bug #10103]' warnings = [ @@ -1960,10 +1979,10 @@ class TestRefinement < Test::Unit::TestCase m = Module.new do r = refine(String) {def test;:ok end} end - assert_raise_with_message(TypeError, /refinement/, bug) do + assert_raise_with_message(ArgumentError, /refinement/, bug) do m.module_eval {include r} end - assert_raise_with_message(TypeError, /refinement/, bug) do + assert_raise_with_message(ArgumentError, /refinement/, bug) do m.module_eval {prepend r} end end @@ -2607,6 +2626,18 @@ class TestRefinement < Test::Unit::TestCase end end + module D + refine A do + TestRefinement.suppress_verbose do + include B + end + + def foo + "refined" + end + end + end + module UsingC using C @@ -2614,10 +2645,19 @@ class TestRefinement < Test::Unit::TestCase A.new.bar end end + + module UsingD + using D + + def self.call_bar + A.new.bar + end + end end def test_import_methods assert_equal("refined:bar", TestImport::UsingC.call_bar) + assert_equal("original:bar", TestImport::UsingD.call_bar) assert_raise(ArgumentError) do Module.new do @@ -2632,24 +2672,6 @@ class TestRefinement < Test::Unit::TestCase assert_equal([], Refinement.used_modules) end - def test_inlinecache - assert_separately([], <<-"end;") - module R - refine String do - def to_s = :R - end - end - - 2.times{|i| - s = ''.to_s - assert_equal '', s if i == 0 - assert_equal :R, s if i == 1 - using R if i == 0 - assert_equal :R, ''.to_s - } - end; - end - private def eval_using(mod, s) diff --git a/test/ruby/test_regexp.rb b/test/ruby/test_regexp.rb index 0a72caba45..16a6ed921f 100644 --- a/test/ruby/test_regexp.rb +++ b/test/ruby/test_regexp.rb @@ -40,6 +40,19 @@ class TestRegexp < Test::Unit::TestCase assert_equal("a".gsub(/a\Z/, ""), "") end + def test_yoshidam_net_20041111_1 + s = "[\xC2\xA0-\xC3\xBE]" + r = assert_deprecated_warning(/ignored/) {Regexp.new(s, nil, "u")} + assert_match(r, "\xC3\xBE") + end + + def test_yoshidam_net_20041111_2 + assert_raise(RegexpError) do + s = "[\xFF-\xFF]".force_encoding("utf-8") + assert_warning(/ignored/) {Regexp.new(s, nil, "u")} + end + end + def test_ruby_dev_31309 assert_equal('Ruby', 'Ruby'.sub(/[^a-z]/i, '-')) end @@ -78,122 +91,6 @@ class TestRegexp < Test::Unit::TestCase assert_warn('', '[ruby-core:82328] [Bug #13798]') {re.to_s} end - def test_extended_comment_invalid_escape_bug_18294 - assert_separately([], <<-RUBY) - re = / C:\\\\[a-z]{5} # e.g. C:\\users /x - assert_match(re, 'C:\\users') - assert_not_match(re, 'C:\\user') - - re = / - foo # \\M-ca - bar - /x - assert_match(re, 'foobar') - assert_not_match(re, 'foobaz') - - re = / - f[#o]o # \\M-ca - bar - /x - assert_match(re, 'foobar') - assert_not_match(re, 'foobaz') - - re = / - f[[:alnum:]#]o # \\M-ca - bar - /x - assert_match(re, 'foobar') - assert_not_match(re, 'foobaz') - - re = / - f(?# \\M-ca)oo # \\M-ca - bar - /x - assert_match(re, 'foobar') - assert_not_match(re, 'foobaz') - - re = /f(?# \\M-ca)oobar/ - assert_match(re, 'foobar') - assert_not_match(re, 'foobaz') - - re = /[-(?# fca)]oobar/ - assert_match(re, 'foobar') - assert_not_match(re, 'foobaz') - - re = /f(?# ca\0\\M-ca)oobar/ - assert_match(re, 'foobar') - assert_not_match(re, 'foobaz') - RUBY - - assert_raise(SyntaxError) {eval "/\\users/x"} - assert_raise(SyntaxError) {eval "/[\\users]/x"} - assert_raise(SyntaxError) {eval "/(?<\\users)/x"} - assert_raise(SyntaxError) {eval "/# \\users/"} - end - - def test_nonextended_section_of_extended_regexp_bug_19379 - assert_separately([], <<-'RUBY') - re = /(?-x:#)/x - assert_match(re, '#') - assert_not_match(re, '-') - - re = /(?xi:# - y)/ - assert_match(re, 'Y') - assert_not_match(re, '-') - - re = /(?mix:# - y)/ - assert_match(re, 'Y') - assert_not_match(re, '-') - - re = /(?x-im:# - y)/i - assert_match(re, 'y') - assert_not_match(re, 'Y') - - re = /(?-imx:(?xim:# - y))/x - assert_match(re, 'y') - assert_not_match(re, '-') - - re = /(?x)# - y/ - assert_match(re, 'y') - assert_not_match(re, 'Y') - - re = /(?mx-i)# - y/i - assert_match(re, 'y') - assert_not_match(re, 'Y') - - re = /(?-imx:(?xim:# - (?-x)y#))/x - assert_match(re, 'Y#') - assert_not_match(re, '-#') - - re = /(?imx:# - (?-xim:#(?im)#(?x)# - )# - (?x)# - y)/ - assert_match(re, '###Y') - assert_not_match(re, '###-') - - re = %r{#c-\w+/comment/[\w-]+} - re = %r{https?://[^/]+#{re}}x - assert_match(re, 'http://foo#c-x/comment/bar') - assert_not_match(re, 'http://foo#cx/comment/bar') - RUBY - end - - def test_utf8_comment_in_usascii_extended_regexp_bug_19455 - assert_separately([], <<-RUBY) - assert_equal(Encoding::UTF_8, /(?#\u1000)/x.encoding) - assert_equal(Encoding::UTF_8, /#\u1000/x.encoding) - RUBY - end - def test_union assert_equal :ok, begin Regexp.union( @@ -311,9 +208,6 @@ class TestRegexp < Test::Unit::TestCase assert_equal({'a' => '1', 'b' => '2', 'c' => '3'}, /^(?<a>.)(?<b>.)(?<c>.)?/.match('123').named_captures) assert_equal({'a' => '1', 'b' => '2', 'c' => ''}, /^(?<a>.)(?<b>.)(?<c>.?)/.match('12').named_captures) - assert_equal({a: '1', b: '2', c: ''}, /^(?<a>.)(?<b>.)(?<c>.?)/.match('12').named_captures(symbolize_names: true)) - assert_equal({'a' => '1', 'b' => '2', 'c' => ''}, /^(?<a>.)(?<b>.)(?<c>.?)/.match('12').named_captures(symbolize_names: false)) - assert_equal({'a' => 'x'}, /(?<a>x)|(?<a>y)/.match('x').named_captures) assert_equal({'a' => 'y'}, /(?<a>x)|(?<a>y)/.match('y').named_captures) @@ -530,27 +424,6 @@ class TestRegexp < Test::Unit::TestCase assert_equal([2, 3], m.offset(3)) end - def test_match_byteoffset_begin_end - m = /(?<x>b..)/.match("foobarbaz") - assert_equal([3, 6], m.byteoffset("x")) - assert_equal(3, m.begin("x")) - assert_equal(6, m.end("x")) - assert_raise(IndexError) { m.byteoffset("y") } - assert_raise(IndexError) { m.byteoffset(2) } - assert_raise(IndexError) { m.begin(2) } - assert_raise(IndexError) { m.end(2) } - - m = /(?<x>q..)?/.match("foobarbaz") - assert_equal([nil, nil], m.byteoffset("x")) - assert_equal(nil, m.begin("x")) - assert_equal(nil, m.end("x")) - - m = /\A\u3042(.)(.)?(.)\z/.match("\u3042\u3043\u3044") - assert_equal([3, 6], m.byteoffset(1)) - assert_equal([nil, nil], m.byteoffset(2)) - assert_equal([6, 9], m.byteoffset(3)) - end - def test_match_to_s m = /(?<x>b..)/.match("foobarbaz") assert_equal("bar", m.to_s) @@ -661,61 +534,17 @@ class TestRegexp < Test::Unit::TestCase assert_equal('#<MatchData "foobarbaz" 1:"foo" 2:"bar" 3:"baz" 4:nil>', m.inspect) end - def test_match_data_deconstruct - m = /foo.+/.match("foobarbaz") - assert_equal([], m.deconstruct) - - m = /(foo).+(baz)/.match("foobarbaz") - assert_equal(["foo", "baz"], m.deconstruct) - - m = /(...)(...)(...)(...)?/.match("foobarbaz") - assert_equal(["foo", "bar", "baz", nil], m.deconstruct) - end - - def test_match_data_deconstruct_keys - m = /foo.+/.match("foobarbaz") - assert_equal({}, m.deconstruct_keys([:a])) - - m = /(?<a>foo).+(?<b>baz)/.match("foobarbaz") - assert_equal({a: "foo", b: "baz"}, m.deconstruct_keys(nil)) - assert_equal({a: "foo", b: "baz"}, m.deconstruct_keys([:a, :b])) - assert_equal({b: "baz"}, m.deconstruct_keys([:b])) - assert_equal({}, m.deconstruct_keys([:c, :a])) - assert_equal({a: "foo"}, m.deconstruct_keys([:a, :c])) - assert_equal({}, m.deconstruct_keys([:a, :b, :c])) - - assert_raise(TypeError) { - m.deconstruct_keys(0) - } - - assert_raise(TypeError) { - m.deconstruct_keys(["a", "b"]) - } - end - def test_initialize assert_raise(ArgumentError) { Regexp.new } assert_equal(/foo/, assert_warning(/ignored/) {Regexp.new(/foo/, Regexp::IGNORECASE)}) - assert_equal(/foo/, assert_no_warning(/ignored/) {Regexp.new(/foo/)}) - assert_equal(/foo/, assert_no_warning(/ignored/) {Regexp.new(/foo/, timeout: nil)}) - - arg_encoding_none = //n.options # ARG_ENCODING_NONE is implementation defined value - assert_deprecated_warning('') do - assert_equal(Encoding.find("US-ASCII"), Regexp.new("b..", Regexp::NOENCODING).encoding) - assert_equal("bar", "foobarbaz"[Regexp.new("b..", Regexp::NOENCODING)]) - assert_equal(//, Regexp.new("")) - assert_equal(//, Regexp.new("", timeout: 1)) - assert_equal(//n, Regexp.new("", Regexp::NOENCODING)) - assert_equal(//n, Regexp.new("", Regexp::NOENCODING, timeout: 1)) + assert_equal(Encoding.find("US-ASCII"), Regexp.new("b..", nil, "n").encoding) + assert_equal("bar", "foobarbaz"[Regexp.new("b..", nil, "n")]) + assert_equal(//n, Regexp.new("", nil, "n")) - assert_equal(arg_encoding_none, Regexp.new("", Regexp::NOENCODING).options) - - assert_nil(Regexp.new("").timeout) - assert_equal(1.0, Regexp.new("", timeout: 1.0).timeout) - assert_nil(Regexp.compile("").timeout) - assert_equal(1.0, Regexp.compile("", timeout: 1.0).timeout) - end + arg_encoding_none = 32 # ARG_ENCODING_NONE is implementation defined value + assert_equal(arg_encoding_none, Regexp.new("", nil, "n").options) + assert_equal(arg_encoding_none, Regexp.new("", nil, "N").options) assert_raise(RegexpError) { Regexp.new(")(") } assert_raise(RegexpError) { Regexp.new('[\\40000000000') } @@ -723,29 +552,6 @@ class TestRegexp < Test::Unit::TestCase assert_raise(RegexpError) { Regexp.new("((?<v>))\\g<0>") } end - def test_initialize_bool_warning - assert_warning(/expected true or false as ignorecase/) do - Regexp.new("foo", :i) - end - end - - def test_initialize_option - assert_equal(//i, Regexp.new("", "i")) - assert_equal(//m, Regexp.new("", "m")) - assert_equal(//x, Regexp.new("", "x")) - assert_equal(//imx, Regexp.new("", "imx")) - assert_equal(//, Regexp.new("", "")) - assert_equal(//imx, Regexp.new("", "mimix")) - - assert_raise(ArgumentError) { Regexp.new("", "e") } - assert_raise(ArgumentError) { Regexp.new("", "n") } - assert_raise(ArgumentError) { Regexp.new("", "s") } - assert_raise(ArgumentError) { Regexp.new("", "u") } - assert_raise(ArgumentError) { Regexp.new("", "o") } - assert_raise(ArgumentError) { Regexp.new("", "j") } - assert_raise(ArgumentError) { Regexp.new("", "xmen") } - end - def test_match_control_meta_escape assert_equal(0, /\c\xFF/ =~ "\c\xFF") assert_equal(0, /\c\M-\xFF/ =~ "\c\M-\xFF") @@ -1379,11 +1185,6 @@ class TestRegexp < Test::Unit::TestCase assert_no_match(/^\p{age=12.0}$/u, "\u32FF") assert_match(/^\p{age=12.1}$/u, "\u32FF") - assert_no_match(/^\p{age=13.0}$/u, "\u{10570}") - assert_match(/^\p{age=14.0}$/u, "\u{10570}") - assert_match(/^\p{age=14.0}$/u, "\u9FFF") - assert_match(/^\p{age=14.0}$/u, "\u{2A6DF}") - assert_match(/^\p{age=14.0}$/u, "\u{2B738}") end MatchData_A = eval("class MatchData_\u{3042} < MatchData; self; end") @@ -1588,9 +1389,6 @@ class TestRegexp < Test::Unit::TestCase assert_equal(0, /(?~(a)c)/ =~ "abb") assert_nil($1) - - assert_equal(0, /(?~(a))/ =~ "") - assert_nil($1) end def test_backref_overrun @@ -1599,12 +1397,6 @@ class TestRegexp < Test::Unit::TestCase end end - def test_bug18631 - assert_kind_of MatchData, /(?<x>a)(?<x>aa)\k<x>/.match("aaaaa") - assert_kind_of MatchData, /(?<x>a)(?<x>aa)\k<x>/.match("aaaa") - assert_kind_of MatchData, /(?<x>a)(?<x>aa)\k<x>/.match("aaaab") - end - def test_invalid_group assert_separately([], "#{<<-"begin;"}\n#{<<-'end;'}") begin; @@ -1614,6 +1406,12 @@ class TestRegexp < Test::Unit::TestCase end; end + def test_bug18631 + assert_kind_of MatchData, /(?<x>a)(?<x>aa)\k<x>/.match("aaaaa") + assert_kind_of MatchData, /(?<x>a)(?<x>aa)\k<x>/.match("aaaa") + assert_kind_of MatchData, /(?<x>a)(?<x>aa)\k<x>/.match("aaaab") + end + # This assertion is for porting x2() tests in testpy.py of Onigmo. def assert_match_at(re, str, positions, msg = nil) re = Regexp.new(re) unless re.is_a?(Regexp) @@ -1643,184 +1441,4 @@ class TestRegexp < Test::Unit::TestCase } assert_empty(errs, msg) end - - def test_s_timeout - assert_separately([], "#{<<-"begin;"}\n#{<<-'end;'}") - timeout = #{ EnvUtil.apply_timeout_scale(0.2).inspect } - begin; - Regexp.timeout = timeout - assert_in_delta(timeout, Regexp.timeout, timeout * 2 * Float::EPSILON) - - t = Time.now - assert_raise_with_message(Regexp::TimeoutError, "regexp match timeout") do - # A typical ReDoS case - /^(a*)*\1$/ =~ "a" * 1000000 + "x" - end - t = Time.now - t - - assert_in_delta(timeout, t, timeout / 2) - end; - end - - def test_s_timeout_corner_cases - assert_separately([], "#{<<-"begin;"}\n#{<<-'end;'}") - begin; - assert_nil(Regexp.timeout) - - # This is just an implementation detail that users should not depend on: - # If Regexp.timeout is set to a value greater than the value that can be - # represented in the internal representation of timeout, it uses the - # maximum value that can be represented. - Regexp.timeout = Float::INFINITY - assert_equal(((1<<64)-1) / 1000000000.0, Regexp.timeout) - - Regexp.timeout = 1e300 - assert_equal(((1<<64)-1) / 1000000000.0, Regexp.timeout) - - assert_raise(ArgumentError) { Regexp.timeout = 0 } - assert_raise(ArgumentError) { Regexp.timeout = -1 } - - Regexp.timeout = nil - assert_nil(Regexp.timeout) - end; - end - - def per_instance_redos_test(global_timeout, per_instance_timeout, expected_timeout) - assert_separately([], "#{<<-"begin;"}\n#{<<-'end;'}") - global_timeout = #{ EnvUtil.apply_timeout_scale(global_timeout).inspect } - per_instance_timeout = #{ (per_instance_timeout ? EnvUtil.apply_timeout_scale(per_instance_timeout) : nil).inspect } - expected_timeout = #{ EnvUtil.apply_timeout_scale(expected_timeout).inspect } - begin; - Regexp.timeout = global_timeout - - re = Regexp.new("^(a*)\\1b?a*$", timeout: per_instance_timeout) - if per_instance_timeout - assert_in_delta(per_instance_timeout, re.timeout, per_instance_timeout * 2 * Float::EPSILON) - else - assert_nil(re.timeout) - end - - t = Time.now - assert_raise_with_message(Regexp::TimeoutError, "regexp match timeout") do - re =~ "a" * 1000000 + "x" - end - t = Time.now - t - - assert_in_delta(expected_timeout, t, expected_timeout * 3 / 4) - end; - end - - def test_timeout_shorter_than_global - per_instance_redos_test(10, 0.2, 0.2) - end - - def test_timeout_longer_than_global - per_instance_redos_test(0.01, 0.5, 0.5) - end - - def test_timeout_nil - per_instance_redos_test(0.5, nil, 0.5) - end - - def test_timeout_corner_cases - assert_separately([], "#{<<-"begin;"}\n#{<<-'end;'}") - begin; - assert_nil(//.timeout) - - # This is just an implementation detail that users should not depend on: - # If Regexp.timeout is set to a value greater than the value that can be - # represented in the internal representation of timeout, it uses the - # maximum value that can be represented. - assert_equal(((1<<64)-1) / 1000000000.0, Regexp.new("foo", timeout: Float::INFINITY).timeout) - - assert_equal(((1<<64)-1) / 1000000000.0, Regexp.new("foo", timeout: 1e300).timeout) - - assert_raise(ArgumentError) { Regexp.new("foo", timeout: 0) } - assert_raise(ArgumentError) { Regexp.new("foo", timeout: -1) } - end; - end - - def test_match_cache_exponential - assert_separately([], "#{<<-"begin;"}\n#{<<-'end;'}") - timeout = #{ EnvUtil.apply_timeout_scale(10).inspect } - begin; - Regexp.timeout = timeout - - assert_nil(/^(a*)*$/ =~ "a" * 1000000 + "x") - end; - end - - def test_match_cache_square - assert_separately([], "#{<<-"begin;"}\n#{<<-'end;'}") - timeout = #{ EnvUtil.apply_timeout_scale(10).inspect } - begin; - Regexp.timeout = timeout - - assert_nil(/^a*b?a*$/ =~ "a" * 1000000 + "x") - end; - end - - def test_match_cache_atomic - assert_separately([], "#{<<-"begin;"}\n#{<<-'end;'}") - timeout = #{ EnvUtil.apply_timeout_scale(10).inspect } - begin; - Regexp.timeout = timeout - - assert_nil(/^(?>a?a?)(a|a)*$/ =~ "a" * 1000000 + "x") - end; - end - - def test_cache_opcodes_initialize - str = 'test1-test2-test3-test4-test_5' - re = '^([0-9a-zA-Z\-/]*){1,256}$' - 100.times do - assert !Regexp.new(re).match?(str) - end - end - - def test_bug_19273 # [Bug #19273] - pattern = /(?:(?:-?b)|(?:-?(?:1_?(?:0_?)*)?0))(?::(?:(?:-?b)|(?:-?(?:1_?(?:0_?)*)?0))){0,3}/ - assert_equal("10:0:0".match(pattern)[0], "10:0:0") - end - - def test_bug_19467 - assert_separately([], "#{<<-"begin;"}\n#{<<-'end;'}") - timeout = #{ EnvUtil.apply_timeout_scale(10).inspect } - begin; - Regexp.timeout = timeout - - assert_nil(/\A.*a.*z\z/ =~ "a" * 1000000 + "y") - end; - end - - def test_bug_19476 # [Bug #19476] - assert_equal("123456789".match(/(?:x?\dx?){2,10}/)[0], "123456789") - assert_equal("123456789".match(/(?:x?\dx?){2,}/)[0], "123456789") - end - - def test_bug_19537 - str = 'aac' - re = '^([ab]{1,3})(a?)*$' - 100.times do - assert !Regexp.new(re).match?(str) - end - end - - def test_linear_time_p - assert_send [Regexp, :linear_time?, /a/] - assert_send [Regexp, :linear_time?, 'a'] - assert_send [Regexp, :linear_time?, 'a', Regexp::IGNORECASE] - assert_not_send [Regexp, :linear_time?, /(a)\1/] - assert_not_send [Regexp, :linear_time?, "(a)\\1"] - - assert_raise(TypeError) {Regexp.linear_time?(nil)} - assert_raise(TypeError) {Regexp.linear_time?(Regexp.allocate)} - end - - def test_linear_performance - pre = ->(n) {[Regexp.new("a?" * n + "a" * n), "a" * n]} - assert_linear_performance([10, 29], pre: pre) do |re, s| - re =~ s - end - end end diff --git a/test/ruby/test_require.rb b/test/ruby/test_require.rb index cadab4f851..a71fe0932e 100644 --- a/test/ruby/test_require.rb +++ b/test/ruby/test_require.rb @@ -6,11 +6,27 @@ require 'tmpdir' class TestRequire < Test::Unit::TestCase def test_load_error_path - filename = "should_not_exist" - error = assert_raise(LoadError) do - require filename - end - assert_equal filename, error.path + Tempfile.create(["should_not_exist", ".rb"]) {|t| + filename = t.path + t.close + File.unlink(filename) + + error = assert_raise(LoadError) do + require filename + end + assert_equal filename, error.path + + # with --disable=gems + assert_separately(["-", filename], "#{<<~"begin;"}\n#{<<~'end;'}") + begin; + filename = ARGV[0] + path = Struct.new(:to_path).new(filename) + error = assert_raise(LoadError) do + require path + end + assert_equal filename, error.path + end; + } end def test_require_invalid_shared_object @@ -94,7 +110,7 @@ class TestRequire < Test::Unit::TestCase begin require_path = File.join(tmp, dir, 'foo.rb').encode(encoding) rescue - omit "cannot convert path encoding to #{encoding}" + skip "cannot convert path encoding to #{encoding}" end Dir.mkdir(File.dirname(require_path)) open(require_path, "wb") {|f| f.puts '$:.push __FILE__'} @@ -176,7 +192,7 @@ class TestRequire < Test::Unit::TestCase t.close path = File.expand_path(t.path).sub(/\A(\w):/, '//127.0.0.1/\1$') - omit "local drive #$1: is not shared" unless File.exist?(path) + skip "local drive #$1: is not shared" unless File.exist?(path) args = ['--disable-gems', "-I#{File.dirname(path)}"] assert_in_out_err(args, "#{<<~"END;"}", [path], []) begin @@ -193,7 +209,7 @@ class TestRequire < Test::Unit::TestCase File.write(req, "p :ok\n") assert_file.exist?(req) req[/.rb$/i] = "" - assert_in_out_err([], <<-INPUT, %w(:ok), []) + assert_in_out_err(['--disable-gems'], <<-INPUT, %w(:ok), []) require "#{req}" require "#{req}" INPUT @@ -211,7 +227,6 @@ class TestRequire < Test::Unit::TestCase assert_not_nil(bt = e.backtrace, "no backtrace") assert_not_empty(bt.find_all {|b| b.start_with? __FILE__}, proc {bt.inspect}) end - ensure $LOADED_FEATURES.replace loaded_features end @@ -462,7 +477,7 @@ class TestRequire < Test::Unit::TestCase result = IO.popen([EnvUtil.rubybin, "b/tst.rb"], &:read) assert_equal("a/lib.rb\n", result, "[ruby-dev:40040]") rescue NotImplementedError, Errno::EACCES - omit "File.symlink is not implemented" + skip "File.symlink is not implemented" end } } @@ -488,7 +503,7 @@ class TestRequire < Test::Unit::TestCase result = IO.popen([EnvUtil.rubybin, "c.rb"], &:read) assert_equal("1", result, "bug17885 [ruby-core:104010]") rescue NotImplementedError, Errno::EACCES - omit "File.symlink is not implemented" + skip "File.symlink is not implemented" end } } @@ -681,7 +696,7 @@ class TestRequire < Test::Unit::TestCase Dir.mktmpdir {|tmp| Dir.chdir(tmp) { open("foo.rb", "w") {} - assert_in_out_err([{"RUBYOPT"=>nil}], "#{<<~"begin;"}\n#{<<~"end;"}", %w(:ok), [], bug7158) + assert_in_out_err([{"RUBYOPT"=>nil}, '--disable-gems'], "#{<<~"begin;"}\n#{<<~"end;"}", %w(:ok), [], bug7158) begin; $:.replace([IO::NULL]) a = Object.new @@ -709,7 +724,7 @@ class TestRequire < Test::Unit::TestCase Dir.mktmpdir {|tmp| Dir.chdir(tmp) { open("foo.rb", "w") {} - assert_in_out_err([{"RUBYOPT"=>nil}], "#{<<~"begin;"}\n#{<<~"end;"}", %w(:ok), [], bug7158) + assert_in_out_err([{"RUBYOPT"=>nil}, '--disable-gems'], "#{<<~"begin;"}\n#{<<~"end;"}", %w(:ok), [], bug7158) begin; $:.replace([IO::NULL]) a = Object.new @@ -739,7 +754,7 @@ class TestRequire < Test::Unit::TestCase open("foo.rb", "w") {} Dir.mkdir("a") open(File.join("a", "bar.rb"), "w") {} - assert_in_out_err([], "#{<<~"begin;"}\n#{<<~"end;"}", %w(:ok), [], bug7383) + assert_in_out_err(['--disable-gems'], "#{<<~"begin;"}\n#{<<~"end;"}", %w(:ok), [], bug7383) begin; $:.replace([IO::NULL]) $:.#{add} "#{tmp}" @@ -823,8 +838,6 @@ class TestRequire < Test::Unit::TestCase end if File.respond_to?(:mkfifo) def test_loading_fifo_threading_success - omit "[Bug #18613]" if /freebsd/=~ RUBY_PLATFORM - Tempfile.create(%w'fifo .rb') {|f| f.close File.unlink(f.path) @@ -851,7 +864,7 @@ class TestRequire < Test::Unit::TestCase end if File.respond_to?(:mkfifo) def test_loading_fifo_fd_leak - omit if RUBY_PLATFORM =~ /android/ # https://rubyci.org/logs/rubyci.s3.amazonaws.com/android29-x86_64/ruby-master/log/20200419T124100Z.fail.html.gz + skip if RUBY_PLATFORM =~ /android/ # https://rubyci.org/logs/rubyci.s3.amazonaws.com/android29-x86_64/ruby-master/log/20200419T124100Z.fail.html.gz Tempfile.create(%w'fifo .rb') {|f| f.close @@ -912,7 +925,7 @@ class TestRequire < Test::Unit::TestCase begin File.symlink "real", File.join(tmp, "symlink") rescue NotImplementedError, Errno::EACCES - omit "File.symlink is not implemented" + skip "File.symlink is not implemented" end File.write(File.join(tmp, "real/test_symlink_load_path.rb"), "print __FILE__") result = IO.popen([EnvUtil.rubybin, "-I#{tmp}/symlink", "-e", "require 'test_symlink_load_path.rb'"], &:read) @@ -960,19 +973,4 @@ class TestRequire < Test::Unit::TestCase assert_nil($LOAD_PATH.resolve_feature_path("superkalifragilisticoespialidoso")) end end - - def test_require_with_public_method_missing - # [Bug #19793] - assert_separately(["-W0", "-rtempfile"], __FILE__, __LINE__, <<~RUBY) - GC.stress = true - - class Object - public :method_missing - end - - Tempfile.create(["empty", ".rb"]) do |file| - require file.path - end - RUBY - end end diff --git a/test/ruby/test_require_lib.rb b/test/ruby/test_require_lib.rb index a88279727e..6b2846c8fd 100644 --- a/test/ruby/test_require_lib.rb +++ b/test/ruby/test_require_lib.rb @@ -1,26 +1,25 @@ -# frozen_string_literal: true +# frozen_string_literal: false require 'test/unit' class TestRequireLib < Test::Unit::TestCase - libdir = __dir__ + '/../../lib' + TEST_RATIO = ENV["TEST_REQUIRE_THREAD_RATIO"]&.tap {|s|break s.to_f} || 0.05 # testing all files needs too long time... - # .rb files at lib - scripts = Dir.glob('*.rb', base: libdir).map {|f| f.chomp('.rb')} - - # .rb files in subdirectories of lib without same name script - dirs = Dir.glob('*/', base: libdir).map {|d| d.chomp('/')} - dirs -= scripts - scripts.concat(Dir.glob(dirs.map {|d| d + '/*.rb'}, base: libdir).map {|f| f.chomp('.rb')}) - - # skip some problems - scripts -= %w[bundler bundled_gems rubygems mkmf] - - scripts.each do |lib| + Dir.glob(File.expand_path('../../lib/**/*.rb', __dir__)).each do |lib| + # skip some problems + next if %r!/lib/(?:bundler|rubygems)\b! =~ lib + next if %r!/lib/(?:debug|mkmf)\.rb\z! =~ lib + next if %r!/lib/irb/ext/tracer\.rb\z! =~ lib + # skip many files that almost use no threads + next if TEST_RATIO < rand(0.0..1.0) define_method "test_thread_size:#{lib}" do - assert_separately(['-W0'], "#{<<~"begin;"}\n#{<<~"end;"}") + assert_separately(['--disable-gems', '-W0'], "#{<<~"begin;"}\n#{<<~"end;"}") begin; n = Thread.list.size - require #{lib.dump} + begin + require #{lib.dump} + rescue Exception + skip $! + end assert_equal n, Thread.list.size end; end diff --git a/test/ruby/test_rubyoptions.rb b/test/ruby/test_rubyoptions.rb index 20fa15604d..aae2522fc6 100644 --- a/test/ruby/test_rubyoptions.rb +++ b/test/ruby/test_rubyoptions.rb @@ -7,14 +7,13 @@ require 'tempfile' require_relative '../lib/jit_support' class TestRubyOptions < Test::Unit::TestCase - def self.rjit_enabled? = defined?(RubyVM::RJIT) && RubyVM::RJIT.enabled? def self.yjit_enabled? = defined?(RubyVM::YJIT.enabled?) && RubyVM::YJIT.enabled? NO_JIT_DESCRIPTION = - if rjit_enabled? - RUBY_DESCRIPTION.sub(/\+RJIT /, '') - elsif yjit_enabled? - RUBY_DESCRIPTION.sub(/\+YJIT( (dev|dev_nodebug|stats))? /, '') + if defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? # checking -DMJIT_FORCE_ENABLE + RUBY_DESCRIPTION.sub(/\+MJIT /, '') + elsif yjit_enabled? # checking -DYJIT_FORCE_ENABLE + RUBY_DESCRIPTION.sub(/\+YJIT /, '') else RUBY_DESCRIPTION end @@ -74,7 +73,7 @@ class TestRubyOptions < Test::Unit::TestCase def test_backtrace_limit assert_in_out_err(%w(--backtrace-limit), "", [], /missing argument for --backtrace-limit/) assert_in_out_err(%w(--backtrace-limit= 1), "", [], /missing argument for --backtrace-limit/) - assert_in_out_err(%w(--backtrace-limit=-2), "", [], /wrong limit for backtrace length/) + assert_in_out_err(%w(--backtrace-limit=-1), "", [], /wrong limit for backtrace length/) code = 'def f(n);n > 0 ? f(n-1) : raise;end;f(5)' assert_in_out_err(%w(--backtrace-limit=1), code, [], [/.*unhandled exception\n/, /^\tfrom .*\n/, @@ -84,18 +83,6 @@ class TestRubyOptions < Test::Unit::TestCase /^\t \.{3} \d+ levels\.{3}\n/]) assert_kind_of(Integer, Thread::Backtrace.limit) assert_in_out_err(%w(--backtrace-limit=1), "p Thread::Backtrace.limit", ['1'], []) - assert_in_out_err(%w(--backtrace-limit 1), "p Thread::Backtrace.limit", ['1'], []) - env = {"RUBYOPT" => "--backtrace-limit=5"} - assert_in_out_err([env], "p Thread::Backtrace.limit", ['5'], []) - assert_in_out_err([env, "--backtrace-limit=1"], "p Thread::Backtrace.limit", ['1'], []) - assert_in_out_err([env, "--backtrace-limit=-1"], "p Thread::Backtrace.limit", ['-1'], []) - assert_in_out_err([env, "--backtrace-limit=3", "--backtrace-limit=1"], - "p Thread::Backtrace.limit", ['1'], []) - assert_in_out_err([{"RUBYOPT" => "--backtrace-limit=5 --backtrace-limit=3"}], - "p Thread::Backtrace.limit", ['3'], []) - long_max = RbConfig::LIMITS["LONG_MAX"] - assert_in_out_err(%W(--backtrace-limit=#{long_max}), "p Thread::Backtrace.limit", - ["#{long_max}"], []) end def test_warning @@ -111,36 +98,29 @@ class TestRubyOptions < Test::Unit::TestCase assert_in_out_err(%w(-W:no-deprecated -e) + ['p Warning[:deprecated]'], "", %w(false), []) assert_in_out_err(%w(-W:experimental -e) + ['p Warning[:experimental]'], "", %w(true), []) assert_in_out_err(%w(-W:no-experimental -e) + ['p Warning[:experimental]'], "", %w(false), []) - assert_in_out_err(%w(-W -e) + ['p Warning[:performance]'], "", %w(false), []) - assert_in_out_err(%w(-W:performance -e) + ['p Warning[:performance]'], "", %w(true), []) assert_in_out_err(%w(-W:qux), "", [], /unknown warning category: `qux'/) assert_in_out_err(%w(-w -e) + ['p Warning[:deprecated]'], "", %w(true), []) assert_in_out_err(%w(-W -e) + ['p Warning[:deprecated]'], "", %w(true), []) assert_in_out_err(%w(-We) + ['p Warning[:deprecated]'], "", %w(true), []) assert_in_out_err(%w(-e) + ['p Warning[:deprecated]'], "", %w(false), []) - assert_in_out_err(%w(-w -e) + ['p Warning[:performance]'], "", %w(false), []) - assert_in_out_err(%w(-W -e) + ['p Warning[:performance]'], "", %w(false), []) - code = 'puts "#{$VERBOSE}:#{Warning[:deprecated]}:#{Warning[:experimental]}:#{Warning[:performance]}"' + code = 'puts "#{$VERBOSE}:#{Warning[:deprecated]}:#{Warning[:experimental]}"' Tempfile.create(["test_ruby_test_rubyoption", ".rb"]) do |t| t.puts code t.close - assert_in_out_err(["-r#{t.path}", '-e', code], "", %w(false:false:true:false false:false:true:false), []) - assert_in_out_err(["-r#{t.path}", '-w', '-e', code], "", %w(true:true:true:false true:true:true:false), []) - assert_in_out_err(["-r#{t.path}", '-W:deprecated', '-e', code], "", %w(false:true:true:false false:true:true:false), []) - assert_in_out_err(["-r#{t.path}", '-W:no-experimental', '-e', code], "", %w(false:false:false:false false:false:false:false), []) - assert_in_out_err(["-r#{t.path}", '-W:performance', '-e', code], "", %w(false:false:true:true false:false:true:true), []) + assert_in_out_err(["-r#{t.path}", '-e', code], "", %w(false:false:true false:false:true), []) + assert_in_out_err(["-r#{t.path}", '-w', '-e', code], "", %w(true:true:true true:true:true), []) + assert_in_out_err(["-r#{t.path}", '-W:deprecated', '-e', code], "", %w(false:true:true false:true:true), []) + assert_in_out_err(["-r#{t.path}", '-W:no-experimental', '-e', code], "", %w(false:false:false false:false:false), []) end ensure ENV['RUBYOPT'] = save_rubyopt end def test_debug - assert_in_out_err(["-de", "p $DEBUG"], "", %w(true), []) + assert_in_out_err(["--disable-gems", "-de", "p $DEBUG"], "", %w(true), []) - assert_in_out_err(["--debug", "-e", "p $DEBUG"], + assert_in_out_err(["--disable-gems", "--debug", "-e", "p $DEBUG"], "", %w(true), []) - - assert_in_out_err(["--debug-", "-e", "p $DEBUG"], "", %w(), /invalid option --debug-/) end q = Regexp.method(:quote) @@ -154,21 +134,21 @@ class TestRubyOptions < Test::Unit::TestCase end private_constant :VERSION_PATTERN - VERSION_PATTERN_WITH_RJIT = + VERSION_PATTERN_WITH_JIT = case RUBY_ENGINE when 'ruby' - /^ruby #{q[RUBY_VERSION]}(?:[p ]|dev|rc).*? \+RJIT \[#{q[RUBY_PLATFORM]}\]$/ + /^ruby #{q[RUBY_VERSION]}(?:[p ]|dev|rc).*? \+MJIT \[#{q[RUBY_PLATFORM]}\]$/ else VERSION_PATTERN end - private_constant :VERSION_PATTERN_WITH_RJIT + private_constant :VERSION_PATTERN_WITH_JIT def test_verbose assert_in_out_err([{'RUBY_YJIT_ENABLE' => nil}, "-vve", ""]) do |r, e| assert_match(VERSION_PATTERN, r[0]) - if self.class.rjit_enabled? && !JITSupport.rjit_force_enabled? + if defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? && !mjit_force_enabled? # checking -DMJIT_FORCE_ENABLE assert_equal(NO_JIT_DESCRIPTION, r[0]) - elsif self.class.yjit_enabled? && !JITSupport.yjit_force_enabled? + elsif self.class.yjit_enabled? && !yjit_force_enabled? # checking -DYJIT_FORCE_ENABLE assert_equal(NO_JIT_DESCRIPTION, r[0]) else assert_equal(RUBY_DESCRIPTION, r[0]) @@ -189,15 +169,10 @@ class TestRubyOptions < Test::Unit::TestCase end def test_enable - if JITSupport.yjit_supported? + if JITSupport.supported? assert_in_out_err(%w(--enable all -e) + [""], "", [], []) assert_in_out_err(%w(--enable-all -e) + [""], "", [], []) assert_in_out_err(%w(--enable=all -e) + [""], "", [], []) - elsif JITSupport.rjit_supported? - # Avoid failing tests by RJIT warnings - assert_in_out_err(%w(--enable all --disable rjit -e) + [""], "", [], []) - assert_in_out_err(%w(--enable-all --disable-rjit -e) + [""], "", [], []) - assert_in_out_err(%w(--enable=all --disable=rjit -e) + [""], "", [], []) end assert_in_out_err(%w(--enable foobarbazqux -e) + [""], "", [], /unknown argument for --enable: `foobarbazqux'/) @@ -211,9 +186,9 @@ class TestRubyOptions < Test::Unit::TestCase assert_in_out_err(%w(--disable foobarbazqux -e) + [""], "", [], /unknown argument for --disable: `foobarbazqux'/) assert_in_out_err(%w(--disable), "", [], /missing argument for --disable/) - assert_in_out_err(%w(-e) + ['p defined? Gem'], "", ["nil"], []) + assert_in_out_err(%w(--disable-gems -e) + ['p defined? Gem'], "", ["nil"], []) assert_in_out_err(%w(--disable-did_you_mean -e) + ['p defined? DidYouMean'], "", ["nil"], []) - assert_in_out_err(%w(-e) + ['p defined? DidYouMean'], "", ["nil"], []) + assert_in_out_err(%w(--disable-gems -e) + ['p defined? DidYouMean'], "", ["nil"], []) end def test_kanji @@ -234,29 +209,31 @@ class TestRubyOptions < Test::Unit::TestCase end def test_version - env = { 'RUBY_YJIT_ENABLE' => nil } # unset in children + env = {'RUBY_YJIT_ENABLE' => nil} # unset in children assert_in_out_err([env, '--version']) do |r, e| assert_match(VERSION_PATTERN, r[0]) if ENV['RUBY_YJIT_ENABLE'] == '1' assert_equal(NO_JIT_DESCRIPTION, r[0]) - elsif self.class.rjit_enabled? || self.class.yjit_enabled? # checking -D(M|Y)JIT_FORCE_ENABLE + elsif defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? || self.class.yjit_enabled? # checking -D(M|Y)JIT_FORCE_ENABLE assert_equal(EnvUtil.invoke_ruby(['-e', 'print RUBY_DESCRIPTION'], '', true).first, r[0]) else assert_equal(RUBY_DESCRIPTION, r[0]) end assert_equal([], e) end - end - def test_rjit_disabled_version - return unless JITSupport.rjit_supported? - return if JITSupport.yjit_force_enabled? + return if RbConfig::CONFIG["MJIT_SUPPORT"] == 'no' + return if yjit_force_enabled? - env = { 'RUBY_YJIT_ENABLE' => nil } # unset in children [ - %w(--version --rjit --disable=rjit), - %w(--version --enable=rjit --disable=rjit), - %w(--version --enable-rjit --disable-rjit), + %w(--version --mjit --disable=mjit), + %w(--version --enable=mjit --disable=mjit), + %w(--version --enable-mjit --disable-mjit), + *([ + %w(--version --jit --disable=jit), + %w(--version --enable=jit --disable=jit), + %w(--version --enable-jit --disable-jit), + ] unless RUBY_PLATFORM.start_with?('x86_64-') && RUBY_PLATFORM !~ /mswin|mingw|msys/), ].each do |args| assert_in_out_err([env] + args) do |r, e| assert_match(VERSION_PATTERN, r[0]) @@ -264,26 +241,27 @@ class TestRubyOptions < Test::Unit::TestCase assert_equal([], e) end end - end - def test_rjit_version - return unless JITSupport.rjit_supported? - return if JITSupport.yjit_force_enabled? - - env = { 'RUBY_YJIT_ENABLE' => nil } # unset in children - [ - %w(--version --rjit), - %w(--version --enable=rjit), - %w(--version --enable-rjit), - ].each do |args| - assert_in_out_err([env] + args) do |r, e| - assert_match(VERSION_PATTERN_WITH_RJIT, r[0]) - if JITSupport.rjit_force_enabled? - assert_equal(RUBY_DESCRIPTION, r[0]) - else - assert_equal(EnvUtil.invoke_ruby([env, '--rjit', '-e', 'print RUBY_DESCRIPTION'], '', true).first, r[0]) + if JITSupport.supported? + [ + %w(--version --mjit), + %w(--version --enable=mjit), + %w(--version --enable-mjit), + *([ + %w(--version --jit), + %w(--version --enable=jit), + %w(--version --enable-jit), + ] unless RUBY_PLATFORM.start_with?('x86_64-') && RUBY_PLATFORM !~ /mswin|mingw|msys/), + ].each do |args| + assert_in_out_err([env] + args) do |r, e| + assert_match(VERSION_PATTERN_WITH_JIT, r[0]) + if defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? # checking -DMJIT_FORCE_ENABLE + assert_equal(RUBY_DESCRIPTION, r[0]) + else + assert_equal(EnvUtil.invoke_ruby([env, '--mjit', '-e', 'print RUBY_DESCRIPTION'], '', true).first, r[0]) + end + assert_equal([], e) end - assert_equal([], e) end end end @@ -377,9 +355,9 @@ class TestRubyOptions < Test::Unit::TestCase assert_in_out_err(%W(-\r -e) + [""], "", [], []) - assert_in_out_err(%W(-\rx), "", [], /invalid option -[\r\n] \(-h will show valid options\) \(RuntimeError\)/) + assert_in_out_err(%W(-\rx), "", [], /invalid option -\\r \(-h will show valid options\) \(RuntimeError\)/) - assert_in_out_err(%W(-\x01), "", [], /invalid option -\x01 \(-h will show valid options\) \(RuntimeError\)/) + assert_in_out_err(%W(-\x01), "", [], /invalid option -\\x01 \(-h will show valid options\) \(RuntimeError\)/) assert_in_out_err(%w(-Z), "", [], /invalid option -Z \(-h will show valid options\) \(RuntimeError\)/) end @@ -696,7 +674,7 @@ class TestRubyOptions < Test::Unit::TestCase end def test_set_program_name - omit "platform dependent feature" unless defined?(PSCMD) and PSCMD + skip "platform dependent feature" unless defined?(PSCMD) and PSCMD with_tmpchdir do write_file("test-script", "$0 = 'hello world'; /test-script/ =~ Process.argv0 or $0 = 'Process.argv0 changed!'; sleep 60") @@ -719,7 +697,7 @@ class TestRubyOptions < Test::Unit::TestCase end def test_setproctitle - omit "platform dependent feature" unless defined?(PSCMD) and PSCMD + skip "platform dependent feature" unless defined?(PSCMD) and PSCMD assert_separately([], "#{<<-"{#"}\n#{<<-'};'}") {# @@ -760,7 +738,7 @@ class TestRubyOptions < Test::Unit::TestCase -e:(?:1:)?\s\[BUG\]\sSegmentation\sfault.*\n )x, %r( - #{ Regexp.quote((TestRubyOptions.rjit_enabled? && !JITSupport.rjit_force_enabled?) ? NO_JIT_DESCRIPTION : RUBY_DESCRIPTION) }\n\n + #{ Regexp.quote(NO_JIT_DESCRIPTION) }\n\n )x, %r( (?:--\s(?:.+\n)*\n)? @@ -777,9 +755,6 @@ class TestRubyOptions < Test::Unit::TestCase )? )x, %r( - (?:--\sThreading(?:.+\n)*\n)? - )x, - %r( (?:--\sMachine(?:.+\n)*\n)? )x, %r( @@ -798,10 +773,7 @@ class TestRubyOptions < Test::Unit::TestCase end def assert_segv(args, message=nil) - # We want YJIT to be enabled in the subprocess if it's enabled for us - # so that the Ruby description matches. - args.unshift("--yjit") if self.class.yjit_enabled? - args.unshift({'RUBY_ON_BUG' => nil}) + skip if ENV['RUBY_ON_BUG'] test_stdin = "" opt = SEGVTest::ExecOptions.dup @@ -886,7 +858,7 @@ class TestRubyOptions < Test::Unit::TestCase Process.wait pid } rescue RuntimeError - omit $! + skip $! end } assert_equal("", result, '[ruby-dev:37798]') @@ -936,7 +908,7 @@ class TestRubyOptions < Test::Unit::TestCase name = c.chr(Encoding::UTF_8) expected = name.encode("locale") rescue nil } - omit "can't make locale name" + skip "can't make locale name" end name << ".rb" expected << ".rb" @@ -1022,7 +994,8 @@ class TestRubyOptions < Test::Unit::TestCase stderr = [] Tempfile.create(%w"bug10435- .rb") do |script| dir, base = File.split(script.path) - File.write(script, "abort ':run'\n") + script.puts "abort ':run'" + script.close opts = ['-C', dir, '-r', "./#{base}", *opt] _, e = assert_in_out_err([*opts, '-ep'], "", //) stderr.concat(e) if e @@ -1046,8 +1019,6 @@ class TestRubyOptions < Test::Unit::TestCase def test_dump_parsetree_with_rflag assert_norun_with_rflag('--dump=parsetree') assert_norun_with_rflag('--dump=parsetree', '-e', '#frozen-string-literal: true') - assert_norun_with_rflag('--dump=parsetree+error_tolerant') - assert_norun_with_rflag('--dump=parse+error_tolerant') end def test_dump_insns_with_rflag @@ -1145,7 +1116,25 @@ class TestRubyOptions < Test::Unit::TestCase end def test_null_script - omit "#{IO::NULL} is not a character device" unless File.chardev?(IO::NULL) + skip "#{IO::NULL} is not a character device" unless File.chardev?(IO::NULL) assert_in_out_err([IO::NULL], success: true) end + + def test_jit_debug + # mswin uses prebuilt precompiled header. Thus it does not show a pch compilation log to check "-O0 -O1". + if JITSupport.supported? && !RUBY_PLATFORM.match?(/mswin/) + env = { 'MJIT_SEARCH_BUILD_DIR' => 'true' } + assert_in_out_err([env, "--disable-yjit", "--mjit-debug=-O0 -O1", "--mjit-verbose=2", "" ], "", [], /-O0 -O1/) + end + end + + private + + def mjit_force_enabled? + "#{RbConfig::CONFIG['CFLAGS']} #{RbConfig::CONFIG['CPPFLAGS']}".match?(/(\A|\s)-D ?MJIT_FORCE_ENABLE\b/) + end + + def yjit_force_enabled? + "#{RbConfig::CONFIG['CFLAGS']} #{RbConfig::CONFIG['CPPFLAGS']}".match?(/(\A|\s)-D ?YJIT_FORCE_ENABLE\b/) + end end diff --git a/test/ruby/test_rubyvm.rb b/test/ruby/test_rubyvm.rb index d729aa5af8..7d4588a165 100644 --- a/test/ruby/test_rubyvm.rb +++ b/test/ruby/test_rubyvm.rb @@ -4,9 +4,11 @@ require 'test/unit' class TestRubyVM < Test::Unit::TestCase def test_stat assert_kind_of Hash, RubyVM.stat + assert_kind_of Integer, RubyVM.stat[:global_constant_state] RubyVM.stat(stat = {}) assert_not_empty stat + assert_equal stat[:global_constant_state], RubyVM.stat(:global_constant_state) end def test_stat_unknown @@ -32,8 +34,6 @@ class TestRubyVM < Test::Unit::TestCase end def test_keep_script_lines - pend if ENV['RUBY_ISEQ_DUMP_DEBUG'] # TODO - prev_conf = RubyVM.keep_script_lines # keep diff --git a/test/ruby/test_rubyvm_jit.rb b/test/ruby/test_rubyvm_jit.rb new file mode 100644 index 0000000000..a3558d791c --- /dev/null +++ b/test/ruby/test_rubyvm_jit.rb @@ -0,0 +1,91 @@ +# frozen_string_literal: true +require 'test/unit' +require_relative '../lib/jit_support' + +return if RbConfig::CONFIG["MJIT_SUPPORT"] == 'no' + +class TestRubyVMJIT < Test::Unit::TestCase + include JITSupport + + def setup + unless JITSupport.supported? + skip 'JIT seems not supported on this platform' + end + end + + def test_pause + out, err = eval_with_jit(<<~'EOS', verbose: 1, min_calls: 1, wait: false) + i = 0 + while i < 5 + eval("def mjit#{i}; end; mjit#{i}") + i += 1 + end + print RubyVM::MJIT.pause + print RubyVM::MJIT.pause + while i < 10 + eval("def mjit#{i}; end; mjit#{i}") + i += 1 + end + print RubyVM::MJIT.pause # no JIT here + EOS + assert_equal('truefalsefalse', out) + assert_equal( + 5, err.scan(/#{JITSupport::JIT_SUCCESS_PREFIX}/).size, + "unexpected stdout:\n```\n#{out}```\n\nstderr:\n```\n#{err}```", + ) + end + + def test_pause_waits_until_compaction + out, err = eval_with_jit(<<~'EOS', verbose: 1, min_calls: 1, wait: false) + def a() end; a + def b() end; b + RubyVM::MJIT.pause + EOS + assert_equal( + 2, err.scan(/#{JITSupport::JIT_SUCCESS_PREFIX}/).size, + "unexpected stdout:\n```\n#{out}```\n\nstderr:\n```\n#{err}```", + ) + assert_equal( + 1, err.scan(/#{JITSupport::JIT_COMPACTION_PREFIX}/).size, + "unexpected stdout:\n```\n#{out}```\n\nstderr:\n```\n#{err}```", + ) unless RUBY_PLATFORM.match?(/mswin|mingw/) # compaction is not supported on Windows yet + end + + def test_pause_does_not_hang_on_full_units + out, _ = eval_with_jit(<<~'EOS', verbose: 1, min_calls: 1, max_cache: 10, wait: false) + i = 0 + while i < 11 + eval("def mjit#{i}; end; mjit#{i}") + i += 1 + end + print RubyVM::MJIT.pause + EOS + assert_equal('true', out) + end + + def test_pause_wait_false + out, err = eval_with_jit(<<~'EOS', verbose: 1, min_calls: 1, wait: false) + i = 0 + while i < 10 + eval("def mjit#{i}; end; mjit#{i}") + i += 1 + end + print RubyVM::MJIT.pause(wait: false) + print RubyVM::MJIT.pause(wait: false) + EOS + assert_equal('truefalse', out) + assert_equal(true, err.scan(/#{JITSupport::JIT_SUCCESS_PREFIX}/).size < 10) + end + + def test_resume + out, err = eval_with_jit(<<~'EOS', verbose: 1, min_calls: 1, wait: false) + print RubyVM::MJIT.resume + print RubyVM::MJIT.pause + print RubyVM::MJIT.resume + print RubyVM::MJIT.resume + print RubyVM::MJIT.pause + EOS + assert_equal('falsetruetruefalsetrue', out) + assert_equal(0, err.scan(/#{JITSupport::JIT_SUCCESS_PREFIX}/).size) + end +end diff --git a/test/ruby/test_settracefunc.rb b/test/ruby/test_settracefunc.rb index 76891e3c97..73d8aee6a2 100644 --- a/test/ruby/test_settracefunc.rb +++ b/test/ruby/test_settracefunc.rb @@ -50,26 +50,6 @@ class TestSetTraceFunc < Test::Unit::TestCase assert_equal([], events) end - def test_c_return_no_binding - binding = :none - TracePoint.new(:c_return){|tp| - binding = tp.binding - }.enable{ - 1.object_id - } - assert_nil(binding) - end - - def test_c_call_no_binding - binding = :none - TracePoint.new(:c_call){|tp| - binding = tp.binding - }.enable{ - 1.object_id - } - assert_nil(binding) - end - def test_c_call_removed_method # [Bug #19305] klass = Class.new do @@ -151,10 +131,6 @@ class TestSetTraceFunc < Test::Unit::TestCase events.shift) assert_equal(["line", 4, __method__, self.class], events.shift) - assert_equal(["c-call", 4, :const_added, Module], - events.shift) - assert_equal(["c-return", 4, :const_added, Module], - events.shift) assert_equal(["c-call", 4, :inherited, Class], events.shift) assert_equal(["c-return", 4, :inherited, Class], @@ -392,8 +368,6 @@ class TestSetTraceFunc < Test::Unit::TestCase [["c-return", 2, :add_trace_func, Thread], ["line", 3, __method__, self.class], - ["c-call", 3, :const_added, Module], - ["c-return", 3, :const_added, Module], ["c-call", 3, :inherited, Class], ["c-return", 3, :inherited, Class], ["class", 3, nil, nil], @@ -502,9 +476,9 @@ class TestSetTraceFunc < Test::Unit::TestCase begin eval <<-EOF.gsub(/^.*?: /, ""), nil, 'xyzzy' 1: trace = TracePoint.trace(*trace_events){|tp| next if !target_thread? - 2: events << [tp.event, tp.lineno, tp.path, _defined_class.(tp), tp.method_id, tp.self, tp.binding&.eval("_local_var"), _get_data.(tp)] if tp.path == 'xyzzy' + 2: events << [tp.event, tp.lineno, tp.path, _defined_class.(tp), tp.method_id, tp.self, tp.binding.eval("_local_var"), _get_data.(tp)] if tp.path == 'xyzzy' 3: } - 4: [1].each{|;_local_var| _local_var = :inner + 4: 1.times{|;_local_var| _local_var = :inner 5: tap{} 6: } 7: class XYZZY @@ -531,29 +505,27 @@ class TestSetTraceFunc < Test::Unit::TestCase answer_events = [ # [:line, 4, 'xyzzy', self.class, method, self, :outer, :nothing], - [:c_call, 4, 'xyzzy', Array, :each, [1], nil, :nothing], + [:c_call, 4, 'xyzzy', Integer, :times, 1, :outer, :nothing], [:line, 4, 'xyzzy', self.class, method, self, nil, :nothing], [:line, 5, 'xyzzy', self.class, method, self, :inner, :nothing], - [:c_return, 4, "xyzzy", Array, :each, [1], nil, [1]], + [:c_return, 4, "xyzzy", Integer, :times, 1, :outer, 1], [:line, 7, 'xyzzy', self.class, method, self, :outer, :nothing], - [:c_call, 7, "xyzzy", Module, :const_added, TestSetTraceFunc, nil, :nothing], - [:c_return, 7, "xyzzy", Module, :const_added, TestSetTraceFunc, nil, nil], - [:c_call, 7, "xyzzy", Class, :inherited, Object, nil, :nothing], - [:c_return, 7, "xyzzy", Class, :inherited, Object, nil, nil], + [:c_call, 7, "xyzzy", Class, :inherited, Object, :outer, :nothing], + [:c_return, 7, "xyzzy", Class, :inherited, Object, :outer, nil], [:class, 7, "xyzzy", nil, nil, xyzzy.class, nil, :nothing], [:line, 8, "xyzzy", nil, nil, xyzzy.class, nil, :nothing], [:line, 9, "xyzzy", nil, nil, xyzzy.class, :XYZZY_outer, :nothing], - [:c_call, 9, "xyzzy", Module, :method_added, xyzzy.class, nil, :nothing], - [:c_return, 9, "xyzzy", Module, :method_added, xyzzy.class, nil, nil], + [:c_call, 9, "xyzzy", Module, :method_added, xyzzy.class, :XYZZY_outer, :nothing], + [:c_return, 9, "xyzzy", Module, :method_added, xyzzy.class, :XYZZY_outer, nil], [:line, 13, "xyzzy", nil, nil, xyzzy.class, :XYZZY_outer, :nothing], - [:c_call, 13, "xyzzy", Module, :method_added, xyzzy.class, nil, :nothing], - [:c_return,13, "xyzzy", Module, :method_added, xyzzy.class, nil, nil], + [:c_call, 13, "xyzzy", Module, :method_added, xyzzy.class, :XYZZY_outer, :nothing], + [:c_return,13, "xyzzy", Module, :method_added, xyzzy.class, :XYZZY_outer, nil], [:end, 17, "xyzzy", nil, nil, xyzzy.class, :XYZZY_outer, :nothing], [:line, 18, "xyzzy", TestSetTraceFunc, method, self, :outer, :nothing], - [:c_call, 18, "xyzzy", Class, :new, xyzzy.class, nil, :nothing], - [:c_call, 18, "xyzzy", BasicObject, :initialize, xyzzy, nil, :nothing], - [:c_return,18, "xyzzy", BasicObject, :initialize, xyzzy, nil, nil], - [:c_return,18, "xyzzy", Class, :new, xyzzy.class, nil, xyzzy], + [:c_call, 18, "xyzzy", Class, :new, xyzzy.class, :outer, :nothing], + [:c_call, 18, "xyzzy", BasicObject, :initialize, xyzzy, :outer, :nothing], + [:c_return,18, "xyzzy", BasicObject, :initialize, xyzzy, :outer, nil], + [:c_return,18, "xyzzy", Class, :new, xyzzy.class, :outer, xyzzy], [:line, 19, "xyzzy", TestSetTraceFunc, method, self, :outer, :nothing], [:call, 9, "xyzzy", xyzzy.class, :foo, xyzzy, nil, :nothing], [:line, 10, "xyzzy", xyzzy.class, :foo, xyzzy, nil, :nothing], @@ -564,17 +536,17 @@ class TestSetTraceFunc < Test::Unit::TestCase [:return, 16, "xyzzy", xyzzy.class, :bar, xyzzy, :XYZZY_bar, xyzzy], [:return, 12, "xyzzy", xyzzy.class, :foo, xyzzy, :XYZZY_foo, xyzzy], [:line, 20, "xyzzy", TestSetTraceFunc, method, self, :outer, :nothing], - [:c_call, 20, "xyzzy", Kernel, :raise, self, nil, :nothing], - [:c_call, 20, "xyzzy", Exception, :exception, RuntimeError, nil, :nothing], - [:c_call, 20, "xyzzy", Exception, :initialize, raised_exc, nil, :nothing], - [:c_return,20, "xyzzy", Exception, :initialize, raised_exc, nil, raised_exc], - [:c_return,20, "xyzzy", Exception, :exception, RuntimeError, nil, raised_exc], - [:c_return,20, "xyzzy", Kernel, :raise, self, nil, nil], - [:c_call, 20, "xyzzy", Exception, :backtrace, raised_exc, nil, :nothing], - [:c_return,20, "xyzzy", Exception, :backtrace, raised_exc, nil, nil], + [:c_call, 20, "xyzzy", Kernel, :raise, self, :outer, :nothing], + [:c_call, 20, "xyzzy", Exception, :exception, RuntimeError, :outer, :nothing], + [:c_call, 20, "xyzzy", Exception, :initialize, raised_exc, :outer, :nothing], + [:c_return,20, "xyzzy", Exception, :initialize, raised_exc, :outer, raised_exc], + [:c_return,20, "xyzzy", Exception, :exception, RuntimeError, :outer, raised_exc], + [:c_return,20, "xyzzy", Kernel, :raise, self, :outer, nil], + [:c_call, 20, "xyzzy", Exception, :backtrace, raised_exc, :outer, :nothing], + [:c_return,20, "xyzzy", Exception, :backtrace, raised_exc, :outer, nil], [:raise, 20, "xyzzy", TestSetTraceFunc, :trace_by_tracepoint, self, :outer, raised_exc], - [:c_call, 20, "xyzzy", Module, :===, RuntimeError, nil, :nothing], - [:c_return,20, "xyzzy", Module, :===, RuntimeError, nil, true], + [:c_call, 20, "xyzzy", Module, :===, RuntimeError,:outer, :nothing], + [:c_return,20, "xyzzy", Module, :===, RuntimeError,:outer, true], [:line, 21, "xyzzy", TestSetTraceFunc, method, self, :outer, :nothing], ] @@ -637,9 +609,9 @@ CODE eval <<-EOF.gsub(/^.*?: /, ""), nil, 'xyzzy' 1: set_trace_func(lambda{|event, file, line, id, binding, klass| - 2: events << [event, line, file, klass, id, binding&.eval('self'), binding&.eval("_local_var")] if file == 'xyzzy' + 2: events << [event, line, file, klass, id, binding.eval('self'), binding.eval("_local_var")] if file == 'xyzzy' 3: }) - 4: [1].map{|;_local_var| _local_var = :inner + 4: 1.times{|;_local_var| _local_var = :inner 5: tap{} 6: } 7: class XYZZY @@ -662,31 +634,29 @@ CODE answer_events = [ # - [:c_return, 1, "xyzzy", TracePoint, :trace, TracePoint, nil, nil], + [:c_return, 1, "xyzzy", TracePoint, :trace, TracePoint, :outer, trace], [:line, 4, 'xyzzy', self.class, method, self, :outer, :nothing], - [:c_call, 4, 'xyzzy', Integer, :times, 1, nil, nil], + [:c_call, 4, 'xyzzy', Integer, :times, 1, :outer, :nothing], [:line, 4, 'xyzzy', self.class, method, self, nil, :nothing], [:line, 5, 'xyzzy', self.class, method, self, :inner, :nothing], - [:c_return, 4, "xyzzy", Integer, :times, 1, nil, nil], + [:c_return, 4, "xyzzy", Integer, :times, 1, :outer, 1], [:line, 7, 'xyzzy', self.class, method, self, :outer, :nothing], - [:c_call, 7, "xyzzy", Class, :inherited, Object, nil, nil], - [:c_return, 7, "xyzzy", Class, :inherited, Object, nil, nil], - [:c_call, 7, "xyzzy", Class, :const_added, Object, nil, nil], - [:c_return, 7, "xyzzy", Class, :const_added, Object, nil, nil], + [:c_call, 7, "xyzzy", Class, :inherited, Object, :outer, :nothing], + [:c_return, 7, "xyzzy", Class, :inherited, Object, :outer, nil], [:class, 7, "xyzzy", nil, nil, xyzzy.class, nil, :nothing], [:line, 8, "xyzzy", nil, nil, xyzzy.class, nil, :nothing], [:line, 9, "xyzzy", nil, nil, xyzzy.class, :XYZZY_outer, :nothing], - [:c_call, 9, "xyzzy", Module, :method_added, xyzzy.class, nil, nil], - [:c_return, 9, "xyzzy", Module, :method_added, xyzzy.class, nil, nil], + [:c_call, 9, "xyzzy", Module, :method_added, xyzzy.class, :XYZZY_outer, :nothing], + [:c_return, 9, "xyzzy", Module, :method_added, xyzzy.class, :XYZZY_outer, nil], [:line, 13, "xyzzy", nil, nil, xyzzy.class, :XYZZY_outer, :nothing], - [:c_call, 13, "xyzzy", Module, :method_added, xyzzy.class, nil, nil], - [:c_return,13, "xyzzy", Module, :method_added, xyzzy.class, nil, nil], + [:c_call, 13, "xyzzy", Module, :method_added, xyzzy.class, :XYZZY_outer, :nothing], + [:c_return,13, "xyzzy", Module, :method_added, xyzzy.class, :XYZZY_outer, nil], [:end, 17, "xyzzy", nil, nil, xyzzy.class, :XYZZY_outer, :nothing], [:line, 18, "xyzzy", TestSetTraceFunc, method, self, :outer, :nothing], - [:c_call, 18, "xyzzy", Class, :new, xyzzy.class, nil, nil], - [:c_call, 18, "xyzzy", BasicObject, :initialize, xyzzy, nil, nil], - [:c_return,18, "xyzzy", BasicObject, :initialize, xyzzy, nil, nil], - [:c_return,18, "xyzzy", Class, :new, xyzzy.class, nil, nil], + [:c_call, 18, "xyzzy", Class, :new, xyzzy.class, :outer, :nothing], + [:c_call, 18, "xyzzy", BasicObject, :initialize, xyzzy, :outer, :nothing], + [:c_return,18, "xyzzy", BasicObject, :initialize, xyzzy, :outer, nil], + [:c_return,18, "xyzzy", Class, :new, xyzzy.class, :outer, xyzzy], [:line, 19, "xyzzy", TestSetTraceFunc, method, self, :outer, :nothing], [:call, 9, "xyzzy", xyzzy.class, :foo, xyzzy, nil, :nothing], [:line, 10, "xyzzy", xyzzy.class, :foo, xyzzy, nil, :nothing], @@ -697,29 +667,23 @@ CODE [:return, 16, "xyzzy", xyzzy.class, :bar, xyzzy, :XYZZY_bar, xyzzy], [:return, 12, "xyzzy", xyzzy.class, :foo, xyzzy, :XYZZY_foo, xyzzy], [:line, 20, "xyzzy", TestSetTraceFunc, method, self, :outer, :nothing], - [:c_call, 20, "xyzzy", Kernel, :raise, self, nil, nil], - [:c_call, 20, "xyzzy", Exception, :exception, RuntimeError, nil, nil], - [:c_call, 20, "xyzzy", Exception, :initialize, raised_exc, nil, nil], - [:c_return,20, "xyzzy", Exception, :initialize, raised_exc, nil, nil], - [:c_return,20, "xyzzy", Exception, :exception, RuntimeError, nil, nil], - [:c_return,20, "xyzzy", Kernel, :raise, self, nil, nil], - [:c_call, 20, "xyzzy", Exception, :backtrace, raised_exc, nil, nil], - [:c_return,20, "xyzzy", Exception, :backtrace, raised_exc, nil, nil], + [:c_call, 20, "xyzzy", Kernel, :raise, self, :outer, :nothing], + [:c_call, 20, "xyzzy", Exception, :exception, RuntimeError, :outer, :nothing], + [:c_call, 20, "xyzzy", Exception, :initialize, raised_exc, :outer, :nothing], + [:c_return,20, "xyzzy", Exception, :initialize, raised_exc, :outer, raised_exc], + [:c_return,20, "xyzzy", Exception, :exception, RuntimeError, :outer, raised_exc], + [:c_return,20, "xyzzy", Kernel, :raise, self, :outer, nil], + [:c_call, 20, "xyzzy", Exception, :backtrace, raised_exc, :outer, :nothing], + [:c_return,20, "xyzzy", Exception, :backtrace, raised_exc, :outer, nil], [:raise, 20, "xyzzy", TestSetTraceFunc, :trace_by_tracepoint, self, :outer, raised_exc], - [:c_call, 20, "xyzzy", Module, :===, RuntimeError, nil, nil], - [:c_return,20, "xyzzy", Module, :===, RuntimeError, nil, nil], + [:c_call, 20, "xyzzy", Module, :===, RuntimeError,:outer, :nothing], + [:c_return,20, "xyzzy", Module, :===, RuntimeError,:outer, true], [:line, 21, "xyzzy", TestSetTraceFunc, method, self, :outer, :nothing], - [:c_call, 21, "xyzzy", TracePoint, :disable, trace, nil, nil], + [:c_call, 21, "xyzzy", TracePoint, :disable, trace, :outer, :nothing], ] return events, answer_events end - def test_set_trace_func_curry_argument_error - b = lambda {|x, y, z| (x||0) + (y||0) + (z||0) }.curry[1, 2] - set_trace_func(proc {}) - assert_raise(ArgumentError) {b[3, 4]} - end - def test_set_trace_func actual_events, expected_events = trace_by_set_trace_func expected_events.zip(actual_events){|e, a| @@ -776,30 +740,25 @@ CODE def test_tracepoint_enable ary = [] args = nil - begin - trace = TracePoint.new(:call){|tp| - next if !target_thread? - ary << tp.method_id - } - foo - trace.enable(target_thread: nil){|*a| - args = a - foo - } + trace = TracePoint.new(:call){|tp| + next if !target_thread? + ary << tp.method_id + } + foo + trace.enable{|*a| + args = a foo - assert_equal([:foo], ary) - assert_equal([], args) - ensure - trace&.disable - end + } + foo + assert_equal([:foo], ary) + assert_equal([], args) trace = TracePoint.new{} begin assert_equal(false, trace.enable) assert_equal(true, trace.enable) - trace.enable(target_thread: nil){} - trace.disable - assert_equal(false, trace.enable) + trace.enable{} + assert_equal(true, trace.enable) ensure trace.disable end @@ -994,7 +953,7 @@ CODE /return/ =~ tp.event ? tp.return_value : nil ] }.enable{ - [1].map{ + 1.times{ 3 } method_for_test_tracepoint_block{ @@ -1004,10 +963,10 @@ CODE # pp events # expected_events = [[:b_call, :test_tracepoint_block, TestSetTraceFunc, TestSetTraceFunc, nil], - [:c_call, :map, Array, Array, nil], + [:c_call, :times, Integer, Integer, nil], [:b_call, :test_tracepoint_block, TestSetTraceFunc, TestSetTraceFunc, nil], [:b_return, :test_tracepoint_block, TestSetTraceFunc, TestSetTraceFunc, 3], - [:c_return, :map, Array, Array, [3]], + [:c_return, :times, Integer, Integer, 1], [:call, :method_for_test_tracepoint_block, TestSetTraceFunc, TestSetTraceFunc, nil], [:b_call, :test_tracepoint_block, TestSetTraceFunc, TestSetTraceFunc, nil], [:b_return, :test_tracepoint_block, TestSetTraceFunc, TestSetTraceFunc, 4], @@ -1031,7 +990,7 @@ CODE tp.defined_class, #=> nil, tp.self.class # tp.self return creating/ending thread ] - }.enable(target_thread: nil){ + }.enable{ created_thread = Thread.new{thread_self = self} created_thread.join } @@ -1310,7 +1269,7 @@ CODE next if !target_thread? events << tp.event }.enable{ - [1].map{ + 1.times{ 3 } method_for_test_tracepoint_block{ @@ -1332,7 +1291,7 @@ CODE next if !target_thread? events << tp.event }.enable{ - [1].map{ + 1.times{ 3 } method_for_test_tracepoint_block{ @@ -1691,7 +1650,7 @@ CODE Bug10724.new } - assert_equal([:call, :call, :return, :return], evs) + assert_equal([:call, :return], evs) end require 'fiber' @@ -2168,9 +2127,9 @@ CODE } # it is dirty hack. usually we shouldn't use such technique Thread.pass until t.status == 'sleep' - # When RJIT thread exists, t.status becomes 'sleep' even if it does not reach m2t_q.pop. + # When MJIT thread exists, t.status becomes 'sleep' even if it does not reach m2t_q.pop. # This sleep forces it to reach m2t_q.pop for --jit-wait. - sleep 1 if defined?(RubyVM::RJIT) && RubyVM::RJIT.enabled? + sleep 1 if defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? t.add_trace_func proc{|ev, file, line, *args| if file == __FILE__ @@ -2183,16 +2142,17 @@ CODE m2t_q.push 1 t.join - assert_equal ["line", base_line + 32], events[0] - assert_equal ["line", base_line + 33], events[1] - assert_equal ["call", base_line + -6], events[2] - assert_equal ["return", base_line + -4], events[3] - assert_equal ["line", base_line + 34], events[4] - assert_equal ["line", base_line + 35], events[5] - assert_equal ["c-call", base_line + 35], events[6] # Thread.current - assert_equal ["c-return", base_line + 35], events[7] # Thread.current - assert_equal ["c-call", base_line + 35], events[8] # Thread#set_trace_func - assert_equal nil, events[9] + assert_equal ["c-return", base_line + 31], events[0] + assert_equal ["line", base_line + 32], events[1] + assert_equal ["line", base_line + 33], events[2] + assert_equal ["call", base_line + -6], events[3] + assert_equal ["return", base_line + -4], events[4] + assert_equal ["line", base_line + 34], events[5] + assert_equal ["line", base_line + 35], events[6] + assert_equal ["c-call", base_line + 35], events[7] # Thread.current + assert_equal ["c-return", base_line + 35], events[8] # Thread.current + assert_equal ["c-call", base_line + 35], events[9] # Thread#set_trace_func + assert_equal nil, events[10] end def test_lineno_in_optimized_insn @@ -2292,7 +2252,7 @@ CODE # global TP and targeted TP ex = assert_raise(ArgumentError) do tp = TracePoint.new(:line){} - tp.enable(target_thread: nil){ + tp.enable{ tp.enable(target: code2){} } end @@ -2406,28 +2366,6 @@ CODE assert_equal [:tp1, 1, 2, :tp2, 3], events end - def test_multiple_tracepoints_same_bmethod - events = [] - tp1 = TracePoint.new(:return) do |tp| - events << :tp1 - end - tp2 = TracePoint.new(:return) do |tp| - events << :tp2 - end - - obj = Object.new - obj.define_singleton_method(:foo) {} - bmethod = obj.method(:foo) - - tp1.enable(target: bmethod) do - tp2.enable(target: bmethod) do - obj.foo - end - end - - assert_equal([:tp2, :tp1], events, '[Bug #18031]') - end - def test_script_compiled events = [] tp = TracePoint.new(:script_compiled){|tp| @@ -2456,7 +2394,7 @@ CODE } assert_equal [], events, 'script_compiled event should not be invoked on compile error' - omit "TODO: test for requires" + skip "TODO: test for requires" events.clear tp.enable{ @@ -2625,20 +2563,6 @@ CODE end bar EOS - - assert_normal_exit(<<-EOS, 'Bug #18730') - def bar - 42 - end - tp_line = TracePoint.new(:line) do |tp0| - tp_multi1 = TracePoint.new(:return, :b_return, :line) do |tp| - tp0.disable - end - tp_multi1.enable - end - tp_line.enable(target: method(:bar)) - bar - EOS end def test_stat_exists @@ -2698,102 +2622,4 @@ CODE TracePoint.allow_reentry{} end end - - def test_raising_from_b_return_tp_tracing_bmethod - assert_normal_exit(<<~RUBY, '[Bug #18060]', timeout: 3) - class Foo - define_singleton_method(:foo) { return } # a bmethod - end - - TracePoint.trace(:b_return) do |tp| - raise - end - - Foo.foo - RUBY - - # Same thing but with a target - assert_normal_exit(<<~RUBY, '[Bug #18060]', timeout: 3) - class Foo - define_singleton_method(:foo) { return } # a bmethod - end - - TracePoint.new(:b_return) do |tp| - raise - end.enable(target: Foo.method(:foo)) - - Foo.foo - RUBY - end - - def helper_cant_rescue - begin - raise SyntaxError - rescue - cant_rescue - end - end - - def test_tp_rescue - lines = [] - TracePoint.new(:line){|tp| - next unless target_thread? - lines << tp.lineno - }.enable{ - begin - helper_cant_rescue - rescue SyntaxError - end - } - _call_line = lines.shift - _raise_line = lines.shift - assert_equal [], lines - end - - def helper_can_rescue - begin - raise __LINE__.to_s - rescue SyntaxError - :ng - rescue - :ok - end - end - - def helper_can_rescue_empty_body - begin - raise __LINE__.to_s - rescue SyntaxError - :ng - rescue - end - end - - def test_tp_rescue_event - lines = [] - TracePoint.new(:rescue){|tp| - next unless target_thread? - lines << [tp.lineno, tp.raised_exception] - }.enable{ - helper_can_rescue - } - - line, err, = lines.pop - assert_equal [], lines - assert err.kind_of?(RuntimeError) - assert_equal err.message.to_i + 4, line - - lines = [] - TracePoint.new(:rescue){|tp| - next unless target_thread? - lines << [tp.lineno, tp.raised_exception] - }.enable{ - helper_can_rescue_empty_body - } - - line, err, = lines.pop - assert_equal [], lines - assert err.kind_of?(RuntimeError) - assert_equal err.message.to_i + 3, line - end end diff --git a/test/ruby/test_shapes.rb b/test/ruby/test_shapes.rb deleted file mode 100644 index ebc94a12d2..0000000000 --- a/test/ruby/test_shapes.rb +++ /dev/null @@ -1,495 +0,0 @@ -# frozen_string_literal: false -require 'test/unit' -require 'objspace' -require 'json' - -# These test the functionality of object shapes -class TestShapes < Test::Unit::TestCase - class IVOrder - def expected_ivs - %w{ @a @b @c @d @e @f @g @h @i @j @k } - end - - def set_ivs - expected_ivs.each { instance_variable_set(_1, 1) } - self - end - end - - class ShapeOrder - def initialize - @b = :b # 5 => 6 - end - - def set_b - @b = :b # 5 => 6 - end - - def set_c - @c = :c # 5 => 7 - end - end - - class OrderedAlloc - def add_ivars - 10.times do |i| - instance_variable_set("@foo" + i.to_s, 0) - end - end - end - - class Example - def initialize - @a = 1 - end - end - - class RemoveAndAdd - def add_foo - @foo = 1 - end - - def remove_foo - remove_instance_variable(:@foo) - end - - def add_bar - @bar = 1 - end - end - - class TooComplex - attr_reader :hopefully_unique_name, :b - - def initialize - @hopefully_unique_name = "a" - @b = "b" - end - - # Make enough lazily defined accessors to allow us to force - # polymorphism - class_eval (RubyVM::Shape::SHAPE_MAX_VARIATIONS + 1).times.map { - "def a#{_1}_m; @a#{_1} ||= #{_1}; end" - }.join(" ; ") - - class_eval "attr_accessor " + (RubyVM::Shape::SHAPE_MAX_VARIATIONS + 1).times.map { - ":a#{_1}" - }.join(", ") - - def iv_not_defined; @not_defined; end - - def write_iv_method - self.a3 = 12345 - end - - def write_iv - @a3 = 12345 - end - end - - # RubyVM::Shape.of returns new instances of shape objects for - # each call. This helper method allows us to define equality for - # shapes - def assert_shape_equal(shape1, shape2) - assert_equal(shape1.id, shape2.id) - assert_equal(shape1.parent_id, shape2.parent_id) - assert_equal(shape1.depth, shape2.depth) - assert_equal(shape1.type, shape2.type) - end - - def refute_shape_equal(shape1, shape2) - refute_equal(shape1.id, shape2.id) - end - - def test_iv_order_correct_on_complex_objects - (RubyVM::Shape::SHAPE_MAX_VARIATIONS + 1).times { - IVOrder.new.instance_variable_set("@a#{_1}", 1) - } - - obj = IVOrder.new - iv_list = obj.set_ivs.instance_variables - assert_equal obj.expected_ivs, iv_list.map(&:to_s) - end - - def test_too_complex - ensure_complex - - tc = TooComplex.new - tc.send("a#{RubyVM::Shape::SHAPE_MAX_VARIATIONS}_m") - assert_predicate RubyVM::Shape.of(tc), :too_complex? - end - - def test_ordered_alloc_is_not_complex - 5.times { OrderedAlloc.new.add_ivars } - obj = JSON.parse(ObjectSpace.dump(OrderedAlloc)) - assert_operator obj["variation_count"], :<, RubyVM::Shape::SHAPE_MAX_VARIATIONS - end - - def test_too_many_ivs_on_obj - obj = Object.new - - (RubyVM::Shape::SHAPE_MAX_NUM_IVS + 1).times do - obj.instance_variable_set(:"@a#{_1}", 1) - end - - assert_predicate RubyVM::Shape.of(obj), :too_complex? - end - - def test_too_many_ivs_on_class - obj = Class.new - - (RubyVM::Shape::SHAPE_MAX_NUM_IVS + 1).times do - obj.instance_variable_set(:"@a#{_1}", 1) - end - - assert_false RubyVM::Shape.of(obj).too_complex? - end - - def test_removing_when_too_many_ivs_on_class - obj = Class.new - - (RubyVM::Shape::SHAPE_MAX_NUM_IVS + 2).times do - obj.instance_variable_set(:"@a#{_1}", 1) - end - (RubyVM::Shape::SHAPE_MAX_NUM_IVS + 2).times do - obj.remove_instance_variable(:"@a#{_1}") - end - - assert_empty obj.instance_variables - end - - def test_removing_when_too_many_ivs_on_module - obj = Module.new - - (RubyVM::Shape::SHAPE_MAX_NUM_IVS + 2).times do - obj.instance_variable_set(:"@a#{_1}", 1) - end - (RubyVM::Shape::SHAPE_MAX_NUM_IVS + 2).times do - obj.remove_instance_variable(:"@a#{_1}") - end - - assert_empty obj.instance_variables - end - - def test_too_complex_ractor - assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") - begin; - $VERBOSE = nil - class TooComplex - attr_reader :very_unique - end - - RubyVM::Shape::SHAPE_MAX_VARIATIONS.times do - TooComplex.new.instance_variable_set(:"@unique_#{_1}", Object.new) - end - - tc = TooComplex.new - tc.instance_variable_set(:"@very_unique", 3) - - assert_predicate RubyVM::Shape.of(tc), :too_complex? - assert_equal 3, tc.very_unique - assert_equal 3, Ractor.new(tc) { |x| Ractor.yield(x.very_unique) }.take - assert_equal tc.instance_variables.sort, Ractor.new(tc) { |x| Ractor.yield(x.instance_variables) }.take.sort - end; - end - - def test_too_complex_ractor_shareable - assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") - begin; - $VERBOSE = nil - class TooComplex - attr_reader :very_unique - end - - RubyVM::Shape::SHAPE_MAX_VARIATIONS.times do - TooComplex.new.instance_variable_set(:"@unique_#{_1}", Object.new) - end - - tc = TooComplex.new - tc.instance_variable_set(:"@very_unique", 3) - - assert_predicate RubyVM::Shape.of(tc), :too_complex? - assert_equal 3, tc.very_unique - assert_equal 3, Ractor.make_shareable(tc).very_unique - end; - end - - def test_read_iv_after_complex - ensure_complex - - tc = TooComplex.new - tc.send("a#{RubyVM::Shape::SHAPE_MAX_VARIATIONS}_m") - assert_predicate RubyVM::Shape.of(tc), :too_complex? - assert_equal 3, tc.a3_m - end - - def test_read_method_after_complex - ensure_complex - - tc = TooComplex.new - tc.send("a#{RubyVM::Shape::SHAPE_MAX_VARIATIONS}_m") - assert_predicate RubyVM::Shape.of(tc), :too_complex? - assert_equal 3, tc.a3_m - assert_equal 3, tc.a3 - end - - def test_write_method_after_complex - ensure_complex - - tc = TooComplex.new - tc.send("a#{RubyVM::Shape::SHAPE_MAX_VARIATIONS}_m") - assert_predicate RubyVM::Shape.of(tc), :too_complex? - tc.write_iv_method - tc.write_iv_method - assert_equal 12345, tc.a3_m - assert_equal 12345, tc.a3 - end - - def test_write_iv_after_complex - ensure_complex - - tc = TooComplex.new - tc.send("a#{RubyVM::Shape::SHAPE_MAX_VARIATIONS}_m") - assert_predicate RubyVM::Shape.of(tc), :too_complex? - tc.write_iv - tc.write_iv - assert_equal 12345, tc.a3_m - assert_equal 12345, tc.a3 - end - - def test_iv_read_via_method_after_complex - ensure_complex - - tc = TooComplex.new - tc.send("a#{RubyVM::Shape::SHAPE_MAX_VARIATIONS}_m") - assert_predicate RubyVM::Shape.of(tc), :too_complex? - assert_equal 3, tc.a3_m - assert_equal 3, tc.instance_variable_get(:@a3) - end - - def test_delete_iv_after_complex - ensure_complex - - tc = TooComplex.new - tc.send("a#{RubyVM::Shape::SHAPE_MAX_VARIATIONS}_m") - assert_predicate RubyVM::Shape.of(tc), :too_complex? - - assert_equal 3, tc.a3_m # make sure IV is initialized - assert tc.instance_variable_defined?(:@a3) - tc.remove_instance_variable(:@a3) - assert_nil tc.a3 - end - - def test_delete_undefined_after_complex - ensure_complex - - tc = TooComplex.new - tc.send("a#{RubyVM::Shape::SHAPE_MAX_VARIATIONS}_m") - assert_predicate RubyVM::Shape.of(tc), :too_complex? - - refute tc.instance_variable_defined?(:@a3) - assert_raise(NameError) do - tc.remove_instance_variable(:@a3) - end - assert_nil tc.a3 - end - - def test_freeze_after_complex - ensure_complex - - tc = TooComplex.new - tc.send("a#{RubyVM::Shape::SHAPE_MAX_VARIATIONS}_m") - assert_predicate RubyVM::Shape.of(tc), :too_complex? - tc.freeze - assert_raise(FrozenError) { tc.a3_m } - end - - def test_read_undefined_iv_after_complex - ensure_complex - - tc = TooComplex.new - tc.send("a#{RubyVM::Shape::SHAPE_MAX_VARIATIONS}_m") - assert_predicate RubyVM::Shape.of(tc), :too_complex? - assert_equal nil, tc.iv_not_defined - end - - def test_shape_order - bar = ShapeOrder.new # 0 => 1 - bar.set_c # 1 => 2 - bar.set_b # 2 => 2 - - foo = ShapeOrder.new # 0 => 1 - shape_id = RubyVM::Shape.of(foo).id - foo.set_b # should not transition - assert_equal shape_id, RubyVM::Shape.of(foo).id - end - - def test_iv_index - example = RemoveAndAdd.new - initial_shape = RubyVM::Shape.of(example) - assert_equal 0, initial_shape.next_iv_index - - example.add_foo # makes a transition - add_foo_shape = RubyVM::Shape.of(example) - assert_equal([:@foo], example.instance_variables) - assert_equal(initial_shape.id, add_foo_shape.parent.id) - assert_equal(1, add_foo_shape.next_iv_index) - - example.remove_foo # makes a transition - remove_foo_shape = RubyVM::Shape.of(example) - assert_equal([], example.instance_variables) - assert_shape_equal(initial_shape, remove_foo_shape) - - example.add_bar # makes a transition - bar_shape = RubyVM::Shape.of(example) - assert_equal([:@bar], example.instance_variables) - assert_equal(initial_shape.id, bar_shape.parent_id) - assert_equal(1, bar_shape.next_iv_index) - end - - def test_remove_then_add_again - example = RemoveAndAdd.new - _initial_shape = RubyVM::Shape.of(example) - - example.add_foo # makes a transition - add_foo_shape = RubyVM::Shape.of(example) - example.remove_foo # makes a transition - example.add_foo # makes a transition - assert_shape_equal(add_foo_shape, RubyVM::Shape.of(example)) - end - - class TestObject; end - - def test_new_obj_has_t_object_shape - assert_shape_equal(RubyVM::Shape.root_shape, RubyVM::Shape.of(TestObject.new).parent) - end - - def test_str_has_root_shape - assert_shape_equal(RubyVM::Shape.root_shape, RubyVM::Shape.of("")) - end - - def test_array_has_root_shape - assert_shape_equal(RubyVM::Shape.root_shape, RubyVM::Shape.of([])) - end - - def test_hash_has_correct_pool_shape - omit "SHAPE_IN_BASIC_FLAGS == 0" unless RbConfig::SIZEOF["uint64_t"] <= RbConfig::SIZEOF["void*"] - - # All hashes are now allocated their own ar_table, so start in a - # larger pool, and have already transitioned once. - assert_shape_equal(RubyVM::Shape.root_shape, RubyVM::Shape.of({}).parent) - end - - def test_true_has_special_const_shape_id - assert_equal(RubyVM::Shape::SPECIAL_CONST_SHAPE_ID, RubyVM::Shape.of(true).id) - end - - def test_nil_has_special_const_shape_id - assert_equal(RubyVM::Shape::SPECIAL_CONST_SHAPE_ID, RubyVM::Shape.of(nil).id) - end - - def test_basic_shape_transition - omit "Failing with RJIT for some reason" if defined?(RubyVM::RJIT) && RubyVM::RJIT.enabled? - obj = Example.new - shape = RubyVM::Shape.of(obj) - refute_equal(RubyVM::Shape.root_shape, shape) - assert_equal :@a, shape.edge_name - assert_equal RubyVM::Shape::SHAPE_IVAR, shape.type - - shape = shape.parent - assert_equal RubyVM::Shape::SHAPE_T_OBJECT, shape.type - - shape = shape.parent - assert_equal(RubyVM::Shape.root_shape.id, shape.id) - assert_equal(obj.instance_variable_get(:@a), 1) - end - - def test_different_objects_make_same_transition - obj = [] - obj2 = "" - obj.instance_variable_set(:@a, 1) - obj2.instance_variable_set(:@a, 1) - assert_shape_equal(RubyVM::Shape.of(obj), RubyVM::Shape.of(obj2)) - end - - def test_duplicating_objects - obj = Example.new - obj2 = obj.dup - assert_shape_equal(RubyVM::Shape.of(obj), RubyVM::Shape.of(obj2)) - end - - def test_freezing_and_duplicating_object - obj = Object.new.freeze - obj2 = obj.dup - refute_predicate(obj2, :frozen?) - # dup'd objects shouldn't be frozen, and the shape should be the - # parent shape of the copied object - assert_equal(RubyVM::Shape.of(obj).parent.id, RubyVM::Shape.of(obj2).id) - end - - def test_freezing_and_duplicating_object_with_ivars - obj = Example.new.freeze - obj2 = obj.dup - refute_predicate(obj2, :frozen?) - refute_shape_equal(RubyVM::Shape.of(obj), RubyVM::Shape.of(obj2)) - assert_equal(obj2.instance_variable_get(:@a), 1) - end - - def test_freezing_and_duplicating_string_with_ivars - str = "str" - str.instance_variable_set(:@a, 1) - str.freeze - str2 = str.dup - refute_predicate(str2, :frozen?) - refute_equal(RubyVM::Shape.of(str).id, RubyVM::Shape.of(str2).id) - assert_equal(str2.instance_variable_get(:@a), 1) - end - - def test_freezing_and_cloning_objects - obj = Object.new.freeze - obj2 = obj.clone(freeze: true) - assert_predicate(obj2, :frozen?) - assert_shape_equal(RubyVM::Shape.of(obj), RubyVM::Shape.of(obj2)) - end - - def test_freezing_and_cloning_object_with_ivars - obj = Example.new.freeze - obj2 = obj.clone(freeze: true) - assert_predicate(obj2, :frozen?) - assert_shape_equal(RubyVM::Shape.of(obj), RubyVM::Shape.of(obj2)) - assert_equal(obj2.instance_variable_get(:@a), 1) - end - - def test_freezing_and_cloning_string - str = "str".freeze - str2 = str.clone(freeze: true) - assert_predicate(str2, :frozen?) - assert_shape_equal(RubyVM::Shape.of(str), RubyVM::Shape.of(str2)) - end - - def test_freezing_and_cloning_string_with_ivars - str = "str" - str.instance_variable_set(:@a, 1) - str.freeze - str2 = str.clone(freeze: true) - assert_predicate(str2, :frozen?) - assert_shape_equal(RubyVM::Shape.of(str), RubyVM::Shape.of(str2)) - assert_equal(str2.instance_variable_get(:@a), 1) - end - - def test_out_of_bounds_shape - assert_raise ArgumentError do - RubyVM::Shape.find_by_id(RubyVM.stat[:next_shape_id]) - end - assert_raise ArgumentError do - RubyVM::Shape.find_by_id(-1) - end - end - - def ensure_complex - RubyVM::Shape::SHAPE_MAX_VARIATIONS.times do - tc = TooComplex.new - tc.send("a#{_1}_m") - end - end -end if defined?(RubyVM::Shape) diff --git a/test/ruby/test_signal.rb b/test/ruby/test_signal.rb index 7877a35129..a62537d59d 100644 --- a/test/ruby/test_signal.rb +++ b/test/ruby/test_signal.rb @@ -291,8 +291,7 @@ class TestSignal < Test::Unit::TestCase if trap = Signal.list['TRAP'] bug9820 = '[ruby-dev:48592] [Bug #9820]' - no_core = "Process.setrlimit(Process::RLIMIT_CORE, 0); " if defined?(Process.setrlimit) && defined?(Process::RLIMIT_CORE) - status = assert_in_out_err(['-e', "#{no_core}Process.kill(:TRAP, $$)"]) + status = assert_in_out_err(['-e', 'Process.kill(:TRAP, $$)']) assert_predicate(status, :signaled?, bug9820) assert_equal(trap, status.termsig, bug9820) end @@ -323,6 +322,49 @@ class TestSignal < Test::Unit::TestCase end; end + def test_sigchld_ignore + skip 'no SIGCHLD' unless Signal.list['CHLD'] + old = trap(:CHLD, 'IGNORE') + cmd = [ EnvUtil.rubybin, '--disable=gems', '-e' ] + assert(system(*cmd, 'exit!(0)'), 'no ECHILD') + IO.pipe do |r, w| + pid = spawn(*cmd, "STDIN.read", in: r) + nb = Process.wait(pid, Process::WNOHANG) + th = Thread.new(Thread.current) do |parent| + Thread.pass until parent.stop? # wait for parent to Process.wait + w.close + end + assert_raise(Errno::ECHILD) { Process.wait(pid) } + th.join + assert_nil nb + end + + IO.pipe do |r, w| + pids = 3.times.map { spawn(*cmd, 'exit!', out: w) } + w.close + zombies = pids.dup + assert_nil r.read(1), 'children dead' + + Timeout.timeout(10) do + zombies.delete_if do |pid| + begin + Process.kill(0, pid) + false + rescue Errno::ESRCH + true + end + end while zombies[0] + end + assert_predicate zombies, :empty?, 'zombies leftover' + + pids.each do |pid| + assert_raise(Errno::ECHILD) { Process.waitpid(pid) } + end + end + ensure + trap(:CHLD, old) if Signal.list['CHLD'] + end + def test_sigwait_fd_unused t = EnvUtil.apply_timeout_scale(0.1) assert_separately([], <<-End) diff --git a/test/ruby/test_sprintf.rb b/test/ruby/test_sprintf.rb index c453ecd350..f2e73eb58d 100644 --- a/test/ruby/test_sprintf.rb +++ b/test/ruby/test_sprintf.rb @@ -362,16 +362,11 @@ class TestSprintf < Test::Unit::TestCase def test_char assert_equal("a", sprintf("%c", 97)) assert_equal("a", sprintf("%c", ?a)) - assert_equal("a", sprintf("%c", "a")) - assert_equal("a", sprintf("%c", sprintf("%c%c", ?a, ?a))) + assert_raise(ArgumentError) { sprintf("%c", sprintf("%c%c", ?a, ?a)) } assert_equal(" " * (BSIZ - 1) + "a", sprintf(" " * (BSIZ - 1) + "%c", ?a)) assert_equal(" " * (BSIZ - 1) + "a", sprintf(" " * (BSIZ - 1) + "%-1c", ?a)) assert_equal(" " * BSIZ + "a", sprintf("%#{ BSIZ + 1 }c", ?a)) assert_equal("a" + " " * BSIZ, sprintf("%-#{ BSIZ + 1 }c", ?a)) - assert_raise(ArgumentError) { sprintf("%c", -1) } - s = sprintf("%c".encode(Encoding::US_ASCII), 0x80) - assert_equal("\x80".b, s) - assert_predicate(s, :valid_encoding?) end def test_string @@ -512,16 +507,6 @@ class TestSprintf < Test::Unit::TestCase end end - def test_coderange - format_str = "wrong constant name %s" - interpolated_str = "\u3042" - assert_predicate format_str, :ascii_only? - refute_predicate interpolated_str, :ascii_only? - - str = format_str % interpolated_str - refute_predicate str, :ascii_only? - end - def test_named_default h = Hash.new('world') assert_equal("hello world", "hello %{location}" % h) diff --git a/test/ruby/test_stack.rb b/test/ruby/test_stack.rb index 8a78848322..763aeb6bc2 100644 --- a/test/ruby/test_stack.rb +++ b/test/ruby/test_stack.rb @@ -18,6 +18,7 @@ class TestStack < Test::Unit::TestCase env = {} env['RUBY_FIBER_VM_STACK_SIZE'] = vm_stack_size.to_s if vm_stack_size env['RUBY_FIBER_MACHINE_STACK_SIZE'] = machine_stack_size.to_s if machine_stack_size + env['ASAN_OPTIONS'] = ENV['ASAN_OPTIONS'] if ENV['ASAN_OPTIONS'] stdout, stderr, status = EnvUtil.invoke_ruby([env, '-e', script], '', true, true, timeout: 30) assert(!status.signaled?, FailDesc[status, nil, stderr]) diff --git a/test/ruby/test_string.rb b/test/ruby/test_string.rb index 22bec09855..6c00aa15f9 100644 --- a/test/ruby/test_string.rb +++ b/test/ruby/test_string.rb @@ -83,7 +83,7 @@ class TestString < Test::Unit::TestCase end def test_initialize_shared - S(str = "mystring" * 10).__send__(:initialize, capacity: str.bytesize) + String.new(str = "mystring" * 10).__send__(:initialize, capacity: str.bytesize) assert_equal("mystring", str[0, 8]) end @@ -97,10 +97,8 @@ class TestString < Test::Unit::TestCase end def test_initialize_memory_leak - return unless @cls == String - assert_no_memory_leak([], <<-PREP, <<-CODE, rss: true) -code = proc {('x'*100_000).__send__(:initialize, '')} +code = proc {('x'*100000).__send__(:initialize, '')} 1_000.times(&code) PREP 100_000.times(&code) @@ -109,10 +107,8 @@ CODE # Bug #18154 def test_initialize_nofree_memory_leak - return unless @cls == String - assert_no_memory_leak([], <<-PREP, <<-CODE, rss: true) -code = proc {0.to_s.__send__(:initialize, capacity: 100_000)} +code = proc {0.to_s.__send__(:initialize, capacity: 10000)} 1_000.times(&code) PREP 100_000.times(&code) @@ -244,23 +240,23 @@ CODE assert_equal(-1, S("ABCDEF") <=> S("abcdef")) - assert_nil(S("foo") <=> Object.new) + assert_nil("foo" <=> Object.new) o = Object.new def o.to_str; "bar"; end - assert_equal(1, S("foo") <=> o) + assert_equal(1, "foo" <=> o) class << o;remove_method :to_str;end def o.<=>(x); nil; end - assert_nil(S("foo") <=> o) + assert_nil("foo" <=> o) class << o;remove_method :<=>;end def o.<=>(x); 1; end - assert_equal(-1, S("foo") <=> o) + assert_equal(-1, "foo" <=> o) class << o;remove_method :<=>;end def o.<=>(x); 2**100; end - assert_equal(-1, S("foo") <=> o) + assert_equal(-1, "foo" <=> o) end def test_EQUAL # '==' @@ -274,10 +270,10 @@ CODE o = Object.new def o.to_str; end def o.==(x); false; end - assert_equal(false, S("foo") == o) + assert_equal(false, "foo" == o) class << o;remove_method :==;end def o.==(x); true; end - assert_equal(true, S("foo") == o) + assert_equal(true, "foo" == o) end def test_LSHIFT # '<<' @@ -652,36 +648,15 @@ CODE result << 0x0300 expected = S("\u0300".encode(Encoding::UTF_16LE)) assert_equal(expected, result, bug7090) - assert_raise(TypeError) { S('foo') << :foo } - assert_raise(FrozenError) { S('foo').freeze.concat('bar') } + assert_raise(TypeError) { 'foo' << :foo } + assert_raise(FrozenError) { 'foo'.freeze.concat('bar') } end def test_concat_literals - s=S("." * 50) + s="." * 50 assert_equal(Encoding::UTF_8, "#{s}x".encoding) end - def test_string_interpolations_across_size_pools_get_embedded - omit if GC::INTERNAL_CONSTANTS[:SIZE_POOL_COUNT] == 1 - - require 'objspace' - base_slot_size = GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE] - small_obj_size = (base_slot_size / 2) - large_obj_size = base_slot_size * 2 - - a = "a" * small_obj_size - b = "a" * large_obj_size - - res = "#{a}, #{b}" - dump_res = ObjectSpace.dump(res) - dump_orig = ObjectSpace.dump(a) - new_slot_size = Integer(dump_res.match(/"slot_size":(\d+)/)[1]) - orig_slot_size = Integer(dump_orig.match(/"slot_size":(\d+)/)[1]) - - assert_match(/"embedded":true/, dump_res) - assert_operator(new_slot_size, :>, orig_slot_size) - end - def test_count a = S("hello world") assert_equal(5, a.count(S("lo"))) @@ -689,18 +664,18 @@ CODE assert_equal(4, a.count(S("hello"), S("^l"))) assert_equal(4, a.count(S("ej-m"))) assert_equal(0, S("y").count(S("a\\-z"))) - assert_equal(5, S("abc\u{3042 3044 3046}").count("^a")) - assert_equal(1, S("abc\u{3042 3044 3046}").count("\u3042")) - assert_equal(5, S("abc\u{3042 3044 3046}").count("^\u3042")) - assert_equal(2, S("abc\u{3042 3044 3046}").count("a-z", "^a")) - assert_equal(0, S("abc\u{3042 3044 3046}").count("a", "\u3042")) - assert_equal(0, S("abc\u{3042 3044 3046}").count("\u3042", "a")) - assert_equal(0, S("abc\u{3042 3044 3046}").count("\u3042", "\u3044")) - assert_equal(4, S("abc\u{3042 3044 3046}").count("^a", "^\u3044")) - assert_equal(4, S("abc\u{3042 3044 3046}").count("^\u3044", "^a")) - assert_equal(4, S("abc\u{3042 3044 3046}").count("^\u3042", "^\u3044")) + assert_equal(5, "abc\u{3042 3044 3046}".count("^a")) + assert_equal(1, "abc\u{3042 3044 3046}".count("\u3042")) + assert_equal(5, "abc\u{3042 3044 3046}".count("^\u3042")) + assert_equal(2, "abc\u{3042 3044 3046}".count("a-z", "^a")) + assert_equal(0, "abc\u{3042 3044 3046}".count("a", "\u3042")) + assert_equal(0, "abc\u{3042 3044 3046}".count("\u3042", "a")) + assert_equal(0, "abc\u{3042 3044 3046}".count("\u3042", "\u3044")) + assert_equal(4, "abc\u{3042 3044 3046}".count("^a", "^\u3044")) + assert_equal(4, "abc\u{3042 3044 3046}".count("^\u3044", "^a")) + assert_equal(4, "abc\u{3042 3044 3046}".count("^\u3042", "^\u3044")) - assert_raise(ArgumentError) { S("foo").count } + assert_raise(ArgumentError) { "foo".count } end def crypt_supports_des_crypt? @@ -742,17 +717,17 @@ CODE assert_equal(S("hell"), S("hello").delete(S("aeiou"), S("^e"))) assert_equal(S("ho"), S("hello").delete(S("ej-m"))) - assert_equal(S("a").hash, S("a\u0101").delete("\u0101").hash, '[ruby-talk:329267]') - assert_equal(true, S("a\u0101").delete("\u0101").ascii_only?) - assert_equal(true, S("a\u3041").delete("\u3041").ascii_only?) - assert_equal(false, S("a\u3041\u3042").delete("\u3041").ascii_only?) + assert_equal("a".hash, "a\u0101".delete("\u0101").hash, '[ruby-talk:329267]') + assert_equal(true, "a\u0101".delete("\u0101").ascii_only?) + assert_equal(true, "a\u3041".delete("\u3041").ascii_only?) + assert_equal(false, "a\u3041\u3042".delete("\u3041").ascii_only?) - assert_equal("a", S("abc\u{3042 3044 3046}").delete("^a")) - assert_equal("bc\u{3042 3044 3046}", S("abc\u{3042 3044 3046}").delete("a")) - assert_equal("\u3042", S("abc\u{3042 3044 3046}").delete("^\u3042")) + assert_equal("a", "abc\u{3042 3044 3046}".delete("^a")) + assert_equal("bc\u{3042 3044 3046}", "abc\u{3042 3044 3046}".delete("a")) + assert_equal("\u3042", "abc\u{3042 3044 3046}".delete("^\u3042")) bug6160 = '[ruby-dev:45374]' - assert_equal("", S('\\').delete('\\'), bug6160) + assert_equal("", '\\'.delete('\\'), bug6160) end def test_delete! @@ -857,10 +832,10 @@ CODE assert_equal(Encoding::UTF_8, S('"\\u3042"').encode(Encoding::EUC_JP).undump.encoding) assert_equal("abc".encode(Encoding::UTF_16LE), - S('"a\x00b\x00c\x00".force_encoding("UTF-16LE")').undump) + '"a\x00b\x00c\x00".force_encoding("UTF-16LE")'.undump) - assert_equal('\#', S('"\\\\#"').undump) - assert_equal('\#{', S('"\\\\\#{"').undump) + assert_equal('\#', '"\\\\#"'.undump) + assert_equal('\#{', '"\\\\\#{"'.undump) assert_raise(RuntimeError) { S('\u3042').undump } assert_raise(RuntimeError) { S('"\x82\xA0\u3042"'.force_encoding("SJIS")).undump } @@ -892,7 +867,7 @@ CODE assert_raise(RuntimeError) { S('"\\"').undump } assert_raise(RuntimeError) { S(%("\0")).undump } assert_raise_with_message(RuntimeError, /invalid/) { - S('"\\u{007F}".xxxxxx').undump + '"\\u{007F}".xxxxxx'.undump } end @@ -908,18 +883,6 @@ CODE end end - class StringWithIVSet < String - def set_iv - @foo = 1 - end - end - - def test_ivar_set_after_frozen_dup - str = StringWithIVSet.new.freeze - str.dup.set_iv - assert_raise(FrozenError) { str.set_iv } - end - def test_each verbose, $VERBOSE = $VERBOSE, nil @@ -1084,9 +1047,9 @@ CODE g = g.encode(enc) assert_equal g.chars, g.grapheme_clusters end - assert_equal ["a", "b", "c"], S("abc").b.grapheme_clusters + assert_equal ["a", "b", "c"], "abc".b.grapheme_clusters - s = S("ABC").b + s = "ABC".b res = [] assert_same s, s.grapheme_clusters {|x| res << x } assert_equal(3, res.size) @@ -1132,7 +1095,7 @@ CODE $/ = save s = nil - S("foo\nbar").each_line(nil) {|s2| s = s2 } + "foo\nbar".each_line(nil) {|s2| s = s2 } assert_equal("foo\nbar", s) assert_equal "hello\n", S("hello\nworld").each_line.next @@ -1140,7 +1103,7 @@ CODE bug7646 = "[ruby-dev:46827]" assert_nothing_raised(bug7646) do - S("\n\u0100").each_line("\n") {} + "\n\u0100".each_line("\n") {} end ensure $/ = save @@ -1154,19 +1117,14 @@ CODE assert_equal(S("world"), res[1]) res = [] - S("hello\n\n\nworld\n").each_line(S(''), chomp: true) {|x| res << x} - assert_equal(S("hello"), res[0]) - assert_equal(S("world\n"), res[1]) - - res = [] - S("hello\r\n\r\nworld\r\n").each_line(S(''), chomp: true) {|x| res << x} - assert_equal(S("hello"), res[0]) - assert_equal(S("world\r\n"), res[1]) + S("hello\n\n\nworld").each_line(S(''), chomp: true) {|x| res << x} + assert_equal(S("hello\n"), res[0]) + assert_equal(S("world"), res[1]) res = [] - S("hello\r\n\n\nworld").each_line(S(''), chomp: true) {|x| res << x} - assert_equal(S("hello"), res[0]) - assert_equal(S("world"), res[1]) + S("hello\r\n\r\nworld").each_line(S(''), chomp: true) {|x| res << x} + assert_equal(S("hello\r\n"), res[0]) + assert_equal(S("world"), res[1]) res = [] S("hello!world").each_line(S('!'), chomp: true) {|x| res << x} @@ -1179,7 +1137,7 @@ CODE assert_equal(S("a"), res[0]) s = nil - S("foo\nbar").each_line(nil, chomp: true) {|s2| s = s2 } + "foo\nbar".each_line(nil, chomp: true) {|s2| s = s2 } assert_equal("foo\nbar", s) assert_equal "hello", S("hello\nworld").each_line(chomp: true).next @@ -1244,9 +1202,9 @@ CODE S("hello").gsub(/(hell)(.)/) { |s| $1.upcase + S('-') + $2 }) assert_equal(S("<>h<>e<>l<>l<>o<>"), S("hello").gsub(S(''), S('<\0>'))) - assert_equal("z", S("abc").gsub(/./, "a" => "z"), "moved from btest/knownbug") + assert_equal("z", "abc".gsub(/./, "a" => "z"), "moved from btest/knownbug") - assert_raise(ArgumentError) { S("foo").gsub } + assert_raise(ArgumentError) { "foo".gsub } end def test_gsub_encoding @@ -1293,23 +1251,23 @@ CODE end def test_sub_hash - assert_equal('azc', S('abc').sub(/b/, "b" => "z")) - assert_equal('ac', S('abc').sub(/b/, {})) - assert_equal('a1c', S('abc').sub(/b/, "b" => 1)) - assert_equal('aBc', S('abc').sub(/b/, Hash.new {|h, k| k.upcase })) - assert_equal('a[\&]c', S('abc').sub(/b/, "b" => '[\&]')) - assert_equal('aBcabc', S('abcabc').sub(/b/, Hash.new {|h, k| h[k] = k.upcase })) - assert_equal('aBcdef', S('abcdef').sub(/de|b/, "b" => "B", "de" => "DE")) + assert_equal('azc', 'abc'.sub(/b/, "b" => "z")) + assert_equal('ac', 'abc'.sub(/b/, {})) + assert_equal('a1c', 'abc'.sub(/b/, "b" => 1)) + assert_equal('aBc', 'abc'.sub(/b/, Hash.new {|h, k| k.upcase })) + assert_equal('a[\&]c', 'abc'.sub(/b/, "b" => '[\&]')) + assert_equal('aBcabc', 'abcabc'.sub(/b/, Hash.new {|h, k| h[k] = k.upcase })) + assert_equal('aBcdef', 'abcdef'.sub(/de|b/, "b" => "B", "de" => "DE")) end def test_gsub_hash - assert_equal('azc', S('abc').gsub(/b/, "b" => "z")) - assert_equal('ac', S('abc').gsub(/b/, {})) - assert_equal('a1c', S('abc').gsub(/b/, "b" => 1)) - assert_equal('aBc', S('abc').gsub(/b/, Hash.new {|h, k| k.upcase })) - assert_equal('a[\&]c', S('abc').gsub(/b/, "b" => '[\&]')) - assert_equal('aBcaBc', S('abcabc').gsub(/b/, Hash.new {|h, k| h[k] = k.upcase })) - assert_equal('aBcDEf', S('abcdef').gsub(/de|b/, "b" => "B", "de" => "DE")) + assert_equal('azc', 'abc'.gsub(/b/, "b" => "z")) + assert_equal('ac', 'abc'.gsub(/b/, {})) + assert_equal('a1c', 'abc'.gsub(/b/, "b" => 1)) + assert_equal('aBc', 'abc'.gsub(/b/, Hash.new {|h, k| k.upcase })) + assert_equal('a[\&]c', 'abc'.gsub(/b/, "b" => '[\&]')) + assert_equal('aBcaBc', 'abcabc'.gsub(/b/, Hash.new {|h, k| h[k] = k.upcase })) + assert_equal('aBcDEf', 'abcdef'.gsub(/de|b/, "b" => "B", "de" => "DE")) end def test_hash @@ -1339,54 +1297,45 @@ CODE end def test_index - assert_index(0, S("hello"), ?h) - assert_index(1, S("hello"), S("ell")) - assert_index(2, S("hello"), /ll./) + assert_equal(0, S("hello").index(?h)) + assert_equal(1, S("hello").index(S("ell"))) + assert_equal(2, S("hello").index(/ll./)) - assert_index(3, S("hello"), ?l, 3) - assert_index(3, S("hello"), S("l"), 3) - assert_index(3, S("hello"), /l./, 3) + assert_equal(3, S("hello").index(?l, 3)) + assert_equal(3, S("hello").index(S("l"), 3)) + assert_equal(3, S("hello").index(/l./, 3)) - assert_index(nil, S("hello"), ?z, 3) - assert_index(nil, S("hello"), S("z"), 3) - assert_index(nil, S("hello"), /z./, 3) + assert_nil(S("hello").index(?z, 3)) + assert_nil(S("hello").index(S("z"), 3)) + assert_nil(S("hello").index(/z./, 3)) - assert_index(nil, S("hello"), ?z) - assert_index(nil, S("hello"), S("z")) - assert_index(nil, S("hello"), /z./) + assert_nil(S("hello").index(?z)) + assert_nil(S("hello").index(S("z"))) + assert_nil(S("hello").index(/z./)) - assert_index(0, S(""), S("")) - assert_index(0, S(""), //) - assert_index(nil, S(""), S("hello")) - assert_index(nil, S(""), /hello/) - assert_index(0, S("hello"), S("")) - assert_index(0, S("hello"), //) + assert_equal(0, S("").index(S(""))) + assert_equal(0, S("").index(//)) + assert_nil(S("").index(S("hello"))) + assert_nil(S("").index(/hello/)) + assert_equal(0, S("hello").index(S(""))) + assert_equal(0, S("hello").index(//)) s = S("long") * 1000 << "x" - assert_index(nil, s, S("y")) - assert_index(4 * 1000, s, S("x")) + assert_nil(s.index(S("y"))) + assert_equal(4 * 1000, s.index(S("x"))) s << "yx" - assert_index(4 * 1000, s, S("x")) - assert_index(4 * 1000, s, S("xyx")) + assert_equal(4 * 1000, s.index(S("x"))) + assert_equal(4 * 1000, s.index(S("xyx"))) o = Object.new def o.to_str; "bar"; end - assert_index(3, S("foobarbarbaz"), o) - assert_raise(TypeError) { S("foo").index(Object.new) } - - assert_index(nil, S("foo"), //, -100) - assert_index(nil, S("foo"), //, 4) - - assert_index(2, S("abcdbce"), /b\Kc/) + assert_equal(3, "foobarbarbaz".index(o)) + assert_raise(TypeError) { "foo".index(Object.new) } - assert_index(0, S("こんにちは"), ?こ) - assert_index(1, S("こんにちは"), S("んにち")) - assert_index(2, S("こんにちは"), /にち./) + assert_nil("foo".index(//, -100)) + assert_nil($~) - assert_index(0, S("にんにちは"), ?に, 0) - assert_index(2, S("にんにちは"), ?に, 1) - assert_index(2, S("にんにちは"), ?に, 2) - assert_index(nil, S("にんにちは"), ?に, 3) + assert_equal(2, S("abcdbce").index(/b\Kc/)) end def test_insert @@ -1493,16 +1442,16 @@ CODE b = a.replace(S("xyz")) assert_equal(S("xyz"), b) - s = S("foo") * 100 + s = "foo" * 100 s2 = ("bar" * 100).dup s.replace(s2) assert_equal(s2, s) - s2 = [S("foo")].pack("p") + s2 = ["foo"].pack("p") s.replace(s2) assert_equal(s2, s) - fs = S("").freeze + fs = "".freeze assert_raise(FrozenError) { fs.replace("a") } assert_raise(FrozenError) { fs.replace(fs) } assert_raise(ArgumentError) { fs.replace() } @@ -1533,57 +1482,34 @@ CODE end def test_rindex - assert_rindex(3, S("hello"), ?l) - assert_rindex(6, S("ell, hello"), S("ell")) - assert_rindex(7, S("ell, hello"), /ll./) + assert_equal(3, S("hello").rindex(?l)) + assert_equal(6, S("ell, hello").rindex(S("ell"))) + assert_equal(7, S("ell, hello").rindex(/ll./)) - assert_rindex(3, S("hello,lo"), ?l, 3) - assert_rindex(3, S("hello,lo"), S("l"), 3) - assert_rindex(3, S("hello,lo"), /l./, 3) + assert_equal(3, S("hello,lo").rindex(?l, 3)) + assert_equal(3, S("hello,lo").rindex(S("l"), 3)) + assert_equal(3, S("hello,lo").rindex(/l./, 3)) - assert_rindex(nil, S("hello"), ?z, 3) - assert_rindex(nil, S("hello"), S("z"), 3) - assert_rindex(nil, S("hello"), /z./, 3) + assert_nil(S("hello").rindex(?z, 3)) + assert_nil(S("hello").rindex(S("z"), 3)) + assert_nil(S("hello").rindex(/z./, 3)) - assert_rindex(nil, S("hello"), ?z) - assert_rindex(nil, S("hello"), S("z")) - assert_rindex(nil, S("hello"), /z./) - - assert_rindex(5, S("hello"), S("")) - assert_rindex(5, S("hello"), S(""), 5) - assert_rindex(4, S("hello"), S(""), 4) - assert_rindex(0, S("hello"), S(""), 0) + assert_nil(S("hello").rindex(?z)) + assert_nil(S("hello").rindex(S("z"))) + assert_nil(S("hello").rindex(/z./)) o = Object.new def o.to_str; "bar"; end - assert_rindex(6, S("foobarbarbaz"), o) - assert_raise(TypeError) { S("foo").rindex(Object.new) } - - assert_rindex(nil, S("foo"), //, -100) + assert_equal(6, "foobarbarbaz".rindex(o)) + assert_raise(TypeError) { "foo".rindex(Object.new) } - m = assert_rindex(3, S("foo"), //) - assert_equal([3, 3], m.offset(0)) - assert_rindex(3, S("foo"), //, 4) - - assert_rindex(5, S("abcdbce"), /b\Kc/) - - assert_rindex(2, S("こんにちは"), ?に) - assert_rindex(6, S("にちは、こんにちは"), S("にちは")) - assert_rindex(6, S("にちは、こんにちは"), /にち./) + assert_nil("foo".rindex(//, -100)) + assert_nil($~) - assert_rindex(6, S("にちは、こんにちは"), S("にちは"), 7) - assert_rindex(6, S("にちは、こんにちは"), S("にちは"), -2) - assert_rindex(6, S("にちは、こんにちは"), S("にちは"), 6) - assert_rindex(6, S("にちは、こんにちは"), S("にちは"), -3) - assert_rindex(0, S("にちは、こんにちは"), S("にちは"), 5) - assert_rindex(0, S("にちは、こんにちは"), S("にちは"), -4) - assert_rindex(0, S("にちは、こんにちは"), S("にちは"), 1) - assert_rindex(0, S("にちは、こんにちは"), S("にちは"), 0) + assert_equal(3, "foo".rindex(//)) + assert_equal([3, 3], $~.offset(0)) - assert_rindex(0, S("こんにちは"), S("こんにちは")) - assert_rindex(nil, S("こんにち"), S("こんにちは")) - assert_rindex(nil, S("こ"), S("こんにちは")) - assert_rindex(nil, S(""), S("こんにちは")) + assert_equal(5, S("abcdbce").rindex(/b\Kc/)) end def test_rjust @@ -1622,15 +1548,6 @@ CODE assert_equal(%w[1 2 3], S("a1 a2 a3").scan(/a\K./)) end - def test_scan_segv - bug19159 = '[Bug #19159]' - assert_nothing_raised(Exception, bug19159) do - ObjectSpace.each_object(MatchData).to_a - "".scan(//) - ObjectSpace.each_object(MatchData).to_a.inspect - end - end - def test_size assert_equal(0, S("").size) assert_equal(4, S("1234").size) @@ -1772,8 +1689,7 @@ CODE assert_equal(S("Bar"), a.slice!(S("Bar"))) assert_equal(S("Foo"), a) - a = S("foo") - assert_raise(ArgumentError) { a.slice! } + assert_raise(ArgumentError) { "foo".slice! } end def test_split @@ -1798,7 +1714,7 @@ CODE assert_equal([S("a"), S(""), S("b"), S("c")], S("a||b|c|").split(S('|'))) assert_equal([S("a"), S(""), S("b"), S("c"), S("")], S("a||b|c|").split(S('|'), -1)) - assert_equal([], S("").split(//, 1)) + assert_equal([], "".split(//, 1)) ensure EnvUtil.suppress_warning {$; = fs} end @@ -1837,18 +1753,16 @@ CODE result = []; S("a||b|c|").split(S('|'), -1) {|s| result << s} assert_equal([S("a"), S(""), S("b"), S("c"), S("")], result) - result = []; S("").split(//, 1) {|s| result << s} + result = []; "".split(//, 1) {|s| result << s} assert_equal([], result) - result = []; S("aaa,bbb,ccc,ddd").split(/,/) {|s| result << s.gsub(/./, "A")} + result = []; "aaa,bbb,ccc,ddd".split(/,/) {|s| result << s.gsub(/./, "A")} assert_equal(["AAA"]*4, result) ensure EnvUtil.suppress_warning {$; = fs} end def test_fs - return unless @cls == String - assert_raise_with_message(TypeError, /\$;/) { $; = [] } @@ -1938,18 +1852,13 @@ CODE assert_send([S("hello"), :start_with?, S("hel")]) assert_not_send([S("hello"), :start_with?, S("el")]) assert_send([S("hello"), :start_with?, S("el"), S("he")]) - assert_send([S("\xFF\xFE"), :start_with?, S("\xFF")]) - assert_send([S("hello\xBE"), :start_with?, S("hello")]) - assert_not_send([S("\u{c4}"), :start_with?, S("\xC3")]) bug5536 = '[ruby-core:40623]' assert_raise(TypeError, bug5536) {S("str").start_with? :not_convertible_to_string} - end - def test_start_with_regexp - assert_equal(true, S("hello").start_with?(/hel/)) + assert_equal(true, "hello".start_with?(/hel/)) assert_equal("hel", $&) - assert_equal(false, S("hello").start_with?(/el/)) + assert_equal(false, "hello".start_with?(/el/)) assert_nil($&) end @@ -1959,9 +1868,9 @@ CODE assert_equal(S("x"), S("\x00x\x00").strip) assert_equal("0b0 ".force_encoding("UTF-16BE"), - S("\x00 0b0 ").force_encoding("UTF-16BE").strip) + "\x00 0b0 ".force_encoding("UTF-16BE").strip) assert_equal("0\x000b0 ".force_encoding("UTF-16BE"), - S("0\x000b0 ").force_encoding("UTF-16BE").strip) + "0\x000b0 ".force_encoding("UTF-16BE").strip) end def test_strip! @@ -2026,17 +1935,17 @@ CODE o = Object.new def o.to_str; "bar"; end - assert_equal("fooBARbaz", S("foobarbaz").sub(o, "BAR")) + assert_equal("fooBARbaz", "foobarbaz".sub(o, "BAR")) - assert_raise(TypeError) { S("foo").sub(Object.new, "") } + assert_raise(TypeError) { "foo".sub(Object.new, "") } - assert_raise(ArgumentError) { S("foo").sub } + assert_raise(ArgumentError) { "foo".sub } assert_raise(IndexError) { "foo"[/(?:(o$)|(x))/, 2] = 'bar' } o = Object.new def o.to_s; self; end - assert_match(/^foo#<Object:0x.*>baz$/, S("foobarbaz").sub("bar") { o }) + assert_match(/^foo#<Object:0x.*>baz$/, "foobarbaz".sub("bar") { o }) assert_equal(S("Abc"), S("abc").sub("a", "A")) m = nil @@ -2045,7 +1954,7 @@ CODE assert_equal(/a/, m.regexp) bug = '[ruby-core:78686] [Bug #13042] other than regexp has no name references' assert_raise_with_message(IndexError, /oops/, bug) { - S('hello').gsub('hello', '\k<oops>') + 'hello'.gsub('hello', '\k<oops>') } end @@ -2092,18 +2001,18 @@ CODE assert_equal(S("AAAAA000"), S("ZZZZ999").succ) assert_equal(S("*+"), S("**").succ) - assert_equal("abce", S("abcd").succ) - assert_equal("THX1139", S("THX1138").succ) - assert_equal("<\<koalb>>", S("<\<koala>>").succ) - assert_equal("2000aaa", S("1999zzz").succ) - assert_equal("AAAA0000", S("ZZZ9999").succ) - assert_equal("**+", S("***").succ) + assert_equal("abce", "abcd".succ) + assert_equal("THX1139", "THX1138".succ) + assert_equal("<\<koalb>>", "<\<koala>>".succ) + assert_equal("2000aaa", "1999zzz".succ) + assert_equal("AAAA0000", "ZZZ9999".succ) + assert_equal("**+", "***".succ) - assert_equal("!", S(" ").succ) - assert_equal("", S("").succ) + assert_equal("!", " ".succ) + assert_equal("", "".succ) bug = '[ruby-core:83062] [Bug #13952]' - s = S("\xff").b + s = "\xff".b assert_not_predicate(s, :ascii_only?) assert_predicate(s.succ, :ascii_only?, bug) end @@ -2155,8 +2064,8 @@ CODE assert_equal(S(""), a.succ!) assert_equal(S(""), a) - assert_equal("aaaaaaaaaaaa", S("zzzzzzzzzzz").succ!) - assert_equal("aaaaaaaaaaaaaaaaaaaaaaaa", S("zzzzzzzzzzzzzzzzzzzzzzz").succ!) + assert_equal("aaaaaaaaaaaa", "zzzzzzzzzzz".succ!) + assert_equal("aaaaaaaaaaaaaaaaaaaaaaaa", "zzzzzzzzzzzzzzzzzzzzzzz".succ!) end def test_sum @@ -2178,8 +2087,8 @@ CODE end def test_sum_2 - assert_equal(0, S("").sum) - assert_equal(294, S("abc").sum) + assert_equal(0, "".sum) + assert_equal(294, "abc".sum) check_sum("abc") check_sum("\x80") -3.upto(70) {|bits| @@ -2226,39 +2135,39 @@ CODE def test_to_i assert_equal(1480, S("1480ft/sec").to_i) assert_equal(0, S("speed of sound in water @20C = 1480ft/sec)").to_i) - assert_equal(0, S(" 0").to_i) - assert_equal(0, S("+0").to_i) - assert_equal(0, S("-0").to_i) - assert_equal(0, S("--0").to_i) - assert_equal(16, S("0x10").to_i(0)) - assert_equal(16, S("0X10").to_i(0)) - assert_equal(2, S("0b10").to_i(0)) - assert_equal(2, S("0B10").to_i(0)) - assert_equal(8, S("0o10").to_i(0)) - assert_equal(8, S("0O10").to_i(0)) - assert_equal(10, S("0d10").to_i(0)) - assert_equal(10, S("0D10").to_i(0)) - assert_equal(8, S("010").to_i(0)) - assert_raise(ArgumentError) { S("010").to_i(-10) } + assert_equal(0, " 0".to_i) + assert_equal(0, "+0".to_i) + assert_equal(0, "-0".to_i) + assert_equal(0, "--0".to_i) + assert_equal(16, "0x10".to_i(0)) + assert_equal(16, "0X10".to_i(0)) + assert_equal(2, "0b10".to_i(0)) + assert_equal(2, "0B10".to_i(0)) + assert_equal(8, "0o10".to_i(0)) + assert_equal(8, "0O10".to_i(0)) + assert_equal(10, "0d10".to_i(0)) + assert_equal(10, "0D10".to_i(0)) + assert_equal(8, "010".to_i(0)) + assert_raise(ArgumentError) { "010".to_i(-10) } 2.upto(36) {|radix| - assert_equal(radix, S("10").to_i(radix)) - assert_equal(radix**2, S("100").to_i(radix)) + assert_equal(radix, "10".to_i(radix)) + assert_equal(radix**2, "100".to_i(radix)) } - assert_raise(ArgumentError) { S("0").to_i(1) } - assert_raise(ArgumentError) { S("0").to_i(37) } - assert_equal(0, S("z").to_i(10)) - assert_equal(12, S("1_2").to_i(10)) - assert_equal(0x40000000, S("1073741824").to_i(10)) - assert_equal(0x4000000000000000, S("4611686018427387904").to_i(10)) - assert_equal(1, S("1__2").to_i(10)) - assert_equal(1, S("1_z").to_i(10)) + assert_raise(ArgumentError) { "0".to_i(1) } + assert_raise(ArgumentError) { "0".to_i(37) } + assert_equal(0, "z".to_i(10)) + assert_equal(12, "1_2".to_i(10)) + assert_equal(0x40000000, "1073741824".to_i(10)) + assert_equal(0x4000000000000000, "4611686018427387904".to_i(10)) + assert_equal(1, "1__2".to_i(10)) + assert_equal(1, "1_z".to_i(10)) bug6192 = '[ruby-core:43566]' - assert_raise(Encoding::CompatibilityError, bug6192) {S("0".encode("utf-16be")).to_i} - assert_raise(Encoding::CompatibilityError, bug6192) {S("0".encode("utf-16le")).to_i} - assert_raise(Encoding::CompatibilityError, bug6192) {S("0".encode("utf-32be")).to_i} - assert_raise(Encoding::CompatibilityError, bug6192) {S("0".encode("utf-32le")).to_i} - assert_raise(Encoding::CompatibilityError, bug6192) {S("0".encode("iso-2022-jp")).to_i} + assert_raise(Encoding::CompatibilityError, bug6192) {"0".encode("utf-16be").to_i} + assert_raise(Encoding::CompatibilityError, bug6192) {"0".encode("utf-16le").to_i} + assert_raise(Encoding::CompatibilityError, bug6192) {"0".encode("utf-32be").to_i} + assert_raise(Encoding::CompatibilityError, bug6192) {"0".encode("utf-32le").to_i} + assert_raise(Encoding::CompatibilityError, bug6192) {"0".encode("iso-2022-jp").to_i} end def test_to_s @@ -2290,13 +2199,13 @@ CODE assert_equal(S("*e**o"), S("hello").tr(S("^aeiou"), S("*"))) assert_equal(S("hal"), S("ibm").tr(S("b-z"), S("a-z"))) - a = S("abc".force_encoding(Encoding::US_ASCII)) + a = "abc".force_encoding(Encoding::US_ASCII) assert_equal(Encoding::US_ASCII, a.tr(S("z"), S("\u0101")).encoding, '[ruby-core:22326]') - assert_equal("a".hash, S("a").tr("a", "\u0101").tr("\u0101", "a").hash, '[ruby-core:22328]') - assert_equal(true, S("\u0101").tr("\u0101", "a").ascii_only?) - assert_equal(true, S("\u3041").tr("\u3041", "a").ascii_only?) - assert_equal(false, S("\u3041\u3042").tr("\u3041", "a").ascii_only?) + assert_equal("a".hash, "a".tr("a", "\u0101").tr("\u0101", "a").hash, '[ruby-core:22328]') + assert_equal(true, "\u0101".tr("\u0101", "a").ascii_only?) + assert_equal(true, "\u3041".tr("\u3041", "a").ascii_only?) + assert_equal(false, "\u3041\u3042".tr("\u3041", "a").ascii_only?) bug6156 = '[ruby-core:43335]' bug13950 = '[ruby-core:83056] [Bug #13950]' @@ -2306,8 +2215,6 @@ CODE assert_not_predicate(str, :ascii_only?) assert_not_predicate(star, :ascii_only?) assert_not_predicate(result, :ascii_only?, bug13950) - - assert_equal(S("XYC"), S("ABC").tr("A-AB", "XY")) end def test_tr! @@ -2329,20 +2236,16 @@ CODE assert_nil(a.tr!(S("B-Z"), S("A-Z"))) assert_equal(S("ibm"), a) - a = S("abc".force_encoding(Encoding::US_ASCII)) + a = "abc".force_encoding(Encoding::US_ASCII) assert_nil(a.tr!(S("z"), S("\u0101")), '[ruby-core:22326]') assert_equal(Encoding::US_ASCII, a.encoding, '[ruby-core:22326]') - - assert_equal(S("XYC"), S("ABC").tr!("A-AB", "XY")) end def test_tr_s assert_equal(S("hypo"), S("hello").tr_s(S("el"), S("yp"))) assert_equal(S("h*o"), S("hello").tr_s(S("el"), S("*"))) - assert_equal("a".hash, S("\u0101\u0101").tr_s("\u0101", "a").hash) - assert_equal(true, S("\u3041\u3041").tr("\u3041", "a").ascii_only?) - - assert_equal(S("XYC"), S("ABC").tr_s("A-AB", "XY")) + assert_equal("a".hash, "\u0101\u0101".tr_s("\u0101", "a").hash) + assert_equal(true, "\u3041\u3041".tr("\u3041", "a").ascii_only?) end def test_tr_s! @@ -2355,8 +2258,6 @@ CODE a = S("hello") assert_equal(S("h*o"), a.tr_s!(S("el"), S("*"))) assert_equal(S("h*o"), a) - - assert_equal(S("XYC"), S("ABC").tr_s!("A-AB", "XY")) end def test_unpack @@ -2444,7 +2345,6 @@ CODE assert_equal(S("HELLO"), S("HELLO").upcase) assert_equal(S("ABC HELLO 123"), S("abc HELLO 123").upcase) assert_equal(S("H\0""ELLO"), S("H\0""ello").upcase) - assert_equal(S("\u{10574}"), S("\u{1059B}").upcase) end def test_upcase! @@ -2518,8 +2418,6 @@ CODE class S2 < String end def test_str_new4 - return unless @cls == String - s = (0..54).to_a.join # length = 100 s2 = S2.new(s[10,90]) s3 = s2[10,80] @@ -2528,7 +2426,7 @@ CODE end def test_rb_str_new4 - s = S("a" * 100) + s = "a" * 100 s2 = s[10,90] assert_equal("a" * 90, s2) s3 = s2[10,80] @@ -2546,11 +2444,11 @@ CODE end def test_rb_str_to_str - assert_equal("ab", S("a") + StringLike.new("b")) + assert_equal("ab", "a" + StringLike.new("b")) end def test_rb_str_shared_replace - s = S("a" * 100) + s = "a" * 100 s.succ! assert_equal("a" * 99 + "b", s) s = "" @@ -2574,12 +2472,12 @@ CODE def test_times2 s1 = '' 100.times {|n| - s2 = S("a") * n + s2 = "a" * n assert_equal(s1, s2) s1 << 'a' } - assert_raise(ArgumentError) { S("foo") * (-1) } + assert_raise(ArgumentError) { "foo" * (-1) } end def test_respond_to @@ -2587,41 +2485,41 @@ CODE def o.respond_to?(arg) [:to_str].include?(arg) ? nil : super end def o.to_str() "" end def o.==(other) "" == other end - assert_equal(false, S("") == o) + assert_equal(false, "" == o) end def test_match_method - assert_equal("bar", S("foobarbaz").match(/bar/).to_s) + assert_equal("bar", "foobarbaz".match(/bar/).to_s) o = Regexp.new('foo') def o.match(x, y, z); x + y + z; end - assert_equal("foobarbaz", S("foo").match(o, "bar", "baz")) + assert_equal("foobarbaz", "foo".match(o, "bar", "baz")) x = nil - S("foo").match(o, "bar", "baz") {|y| x = y } + "foo".match(o, "bar", "baz") {|y| x = y } assert_equal("foobarbaz", x) - assert_raise(ArgumentError) { S("foo").match } + assert_raise(ArgumentError) { "foo".match } end def test_match_p_regexp /backref/ =~ 'backref' # must match here, but not in a separate method, e.g., assert_send, # to check if $~ is affected or not. - assert_equal(true, S("").match?(//)) + assert_equal(true, "".match?(//)) assert_equal(true, :abc.match?(/.../)) - assert_equal(true, S('abc').match?(/b/)) - assert_equal(true, S('abc').match?(/b/, 1)) - assert_equal(true, S('abc').match?(/../, 1)) - assert_equal(true, S('abc').match?(/../, -2)) - assert_equal(false, S('abc').match?(/../, -4)) - assert_equal(false, S('abc').match?(/../, 4)) - assert_equal(true, S("\u3042xx").match?(/../, 1)) - assert_equal(false, S("\u3042x").match?(/../, 1)) - assert_equal(true, S('').match?(/\z/)) - assert_equal(true, S('abc').match?(/\z/)) - assert_equal(true, S('Ruby').match?(/R.../)) - assert_equal(false, S('Ruby').match?(/R.../, 1)) - assert_equal(false, S('Ruby').match?(/P.../)) + assert_equal(true, 'abc'.match?(/b/)) + assert_equal(true, 'abc'.match?(/b/, 1)) + assert_equal(true, 'abc'.match?(/../, 1)) + assert_equal(true, 'abc'.match?(/../, -2)) + assert_equal(false, 'abc'.match?(/../, -4)) + assert_equal(false, 'abc'.match?(/../, 4)) + assert_equal(true, "\u3042xx".match?(/../, 1)) + assert_equal(false, "\u3042x".match?(/../, 1)) + assert_equal(true, ''.match?(/\z/)) + assert_equal(true, 'abc'.match?(/\z/)) + assert_equal(true, 'Ruby'.match?(/R.../)) + assert_equal(false, 'Ruby'.match?(/R.../, 1)) + assert_equal(false, 'Ruby'.match?(/P.../)) assert_equal('backref', $&) end @@ -2629,21 +2527,21 @@ CODE /backref/ =~ 'backref' # must match here, but not in a separate method, e.g., assert_send, # to check if $~ is affected or not. - assert_equal(true, S("").match?('')) + assert_equal(true, "".match?('')) assert_equal(true, :abc.match?('...')) - assert_equal(true, S('abc').match?('b')) - assert_equal(true, S('abc').match?('b', 1)) - assert_equal(true, S('abc').match?('..', 1)) - assert_equal(true, S('abc').match?('..', -2)) - assert_equal(false, S('abc').match?('..', -4)) - assert_equal(false, S('abc').match?('..', 4)) - assert_equal(true, S("\u3042xx").match?('..', 1)) - assert_equal(false, S("\u3042x").match?('..', 1)) - assert_equal(true, S('').match?('\z')) - assert_equal(true, S('abc').match?('\z')) - assert_equal(true, S('Ruby').match?('R...')) - assert_equal(false, S('Ruby').match?('R...', 1)) - assert_equal(false, S('Ruby').match?('P...')) + assert_equal(true, 'abc'.match?('b')) + assert_equal(true, 'abc'.match?('b', 1)) + assert_equal(true, 'abc'.match?('..', 1)) + assert_equal(true, 'abc'.match?('..', -2)) + assert_equal(false, 'abc'.match?('..', -4)) + assert_equal(false, 'abc'.match?('..', 4)) + assert_equal(true, "\u3042xx".match?('..', 1)) + assert_equal(false, "\u3042x".match?('..', 1)) + assert_equal(true, ''.match?('\z')) + assert_equal(true, 'abc'.match?('\z')) + assert_equal(true, 'Ruby'.match?('R...')) + assert_equal(false, 'Ruby'.match?('R...', 1)) + assert_equal(false, 'Ruby'.match?('P...')) assert_equal('backref', $&) end @@ -2663,23 +2561,18 @@ CODE def test_inspect_nul bug8290 = '[ruby-core:54458]' - s = S("\0") + "12" + s = "\0" + "12" assert_equal '"\u000012"', s.inspect, bug8290 - s = S("\0".b) + "12" + s = "\0".b + "12" assert_equal '"\x0012"', s.inspect, bug8290 end - def test_inspect_next_line - bug16842 = '[ruby-core:98231]' - assert_equal '"\\u0085"', 0x85.chr(Encoding::UTF_8).inspect, bug16842 - end - def test_partition - assert_equal(%w(he l lo), S("hello").partition(/l/)) - assert_equal(%w(he l lo), S("hello").partition("l")) - assert_raise(TypeError) { S("hello").partition(1) } + assert_equal(%w(he l lo), "hello".partition(/l/)) + assert_equal(%w(he l lo), "hello".partition("l")) + assert_raise(TypeError) { "hello".partition(1) } def (hyphen = Object.new).to_str; "-"; end - assert_equal(%w(foo - bar), S("foo-bar").partition(hyphen), '[ruby-core:23540]') + assert_equal(%w(foo - bar), "foo-bar".partition(hyphen), '[ruby-core:23540]') bug6206 = '[ruby-dev:45441]' Encoding.list.each do |enc| @@ -2689,24 +2582,24 @@ CODE end assert_equal(["\u30E6\u30FC\u30B6", "@", "\u30C9\u30E1.\u30A4\u30F3"], - S("\u30E6\u30FC\u30B6@\u30C9\u30E1.\u30A4\u30F3").partition(/[@.]/)) + "\u30E6\u30FC\u30B6@\u30C9\u30E1.\u30A4\u30F3".partition(/[@.]/)) bug = '[ruby-core:82911]' - hello = S("hello") + hello = "hello" hello.partition("hi").map(&:upcase!) assert_equal("hello", hello, bug) - assert_equal(["", "", "foo"], S("foo").partition(/^=*/)) + assert_equal(["", "", "foo"], "foo".partition(/^=*/)) assert_equal([S("ab"), S("c"), S("dbce")], S("abcdbce").partition(/b\Kc/)) end def test_rpartition - assert_equal(%w(hel l o), S("hello").rpartition(/l/)) - assert_equal(%w(hel l o), S("hello").rpartition("l")) - assert_raise(TypeError) { S("hello").rpartition(1) } + assert_equal(%w(hel l o), "hello".rpartition(/l/)) + assert_equal(%w(hel l o), "hello".rpartition("l")) + assert_raise(TypeError) { "hello".rpartition(1) } def (hyphen = Object.new).to_str; "-"; end - assert_equal(%w(foo - bar), S("foo-bar").rpartition(hyphen), '[ruby-core:23540]') + assert_equal(%w(foo - bar), "foo-bar".rpartition(hyphen), '[ruby-core:23540]') bug6206 = '[ruby-dev:45441]' Encoding.list.each do |enc| @@ -2717,7 +2610,7 @@ CODE bug8138 = '[ruby-dev:47183]' assert_equal(["\u30E6\u30FC\u30B6@\u30C9\u30E1", ".", "\u30A4\u30F3"], - S("\u30E6\u30FC\u30B6@\u30C9\u30E1.\u30A4\u30F3").rpartition(/[@.]/), bug8138) + "\u30E6\u30FC\u30B6@\u30C9\u30E1.\u30A4\u30F3".rpartition(/[@.]/), bug8138) bug = '[ruby-core:82911]' hello = "hello" @@ -2727,13 +2620,10 @@ CODE assert_equal([S("abcdb"), S("c"), S("e")], S("abcdbce").rpartition(/b\Kc/)) end - def test_fs_setter - return unless @cls == String - + def test_setter assert_raise(TypeError) { $/ = 1 } name = "\u{5206 884c}" - assert_separately([], "#{<<~"do;"}\n#{<<~"end;"}") - do; + assert_separately([], <<-"end;") # do alias $#{name} $/ assert_raise_with_message(TypeError, /\\$#{name}/) { $#{name} = 1 } end; @@ -2766,19 +2656,16 @@ CODE end def test_gsub_enumerator - e = S("abc").gsub(/./) - assert_equal("a", e.next, "[ruby-dev:34828]") - assert_equal("b", e.next) - assert_equal("c", e.next) + assert_normal_exit %q{"abc".gsub(/./).next}, "[ruby-dev:34828]" end def test_clear_nonasciicompat - assert_equal("", S("\u3042".encode("ISO-2022-JP")).clear) + assert_equal("", "\u3042".encode("ISO-2022-JP").clear) end def test_try_convert - assert_equal(nil, @cls.try_convert(1)) - assert_equal("foo", @cls.try_convert("foo")) + assert_equal(nil, String.try_convert(1)) + assert_equal("foo", String.try_convert("foo")) end def test_substr_negative_begin @@ -2787,55 +2674,55 @@ CODE =begin def test_compare_different_encoding_string - s1 = S("\xff".force_encoding("UTF-8")) - s2 = S("\xff".force_encoding("ISO-2022-JP")) + s1 = "\xff".force_encoding("UTF-8") + s2 = "\xff".force_encoding("ISO-2022-JP") assert_equal([-1, 1], [s1 <=> s2, s2 <=> s1].sort) end =end def test_casecmp - assert_equal(0, S("FoO").casecmp("fOO")) - assert_equal(1, S("FoO").casecmp("BaR")) - assert_equal(-1, S("baR").casecmp("FoO")) - assert_equal(1, S("\u3042B").casecmp("\u3042a")) - assert_equal(-1, S("foo").casecmp("foo\0")) + assert_equal(0, "FoO".casecmp("fOO")) + assert_equal(1, "FoO".casecmp("BaR")) + assert_equal(-1, "baR".casecmp("FoO")) + assert_equal(1, "\u3042B".casecmp("\u3042a")) + assert_equal(-1, "foo".casecmp("foo\0")) - assert_nil(S("foo").casecmp(:foo)) - assert_nil(S("foo").casecmp(Object.new)) + assert_nil("foo".casecmp(:foo)) + assert_nil("foo".casecmp(Object.new)) o = Object.new def o.to_str; "fOO"; end - assert_equal(0, S("FoO").casecmp(o)) + assert_equal(0, "FoO".casecmp(o)) end def test_casecmp? - assert_equal(true, S('FoO').casecmp?('fOO')) - assert_equal(false, S('FoO').casecmp?('BaR')) - assert_equal(false, S('baR').casecmp?('FoO')) - assert_equal(true, S('äöü').casecmp?('ÄÖÜ')) - assert_equal(false, S("foo").casecmp?("foo\0")) + assert_equal(true, 'FoO'.casecmp?('fOO')) + assert_equal(false, 'FoO'.casecmp?('BaR')) + assert_equal(false, 'baR'.casecmp?('FoO')) + assert_equal(true, 'äöü'.casecmp?('ÄÖÜ')) + assert_equal(false, "foo".casecmp?("foo\0")) - assert_nil(S("foo").casecmp?(:foo)) - assert_nil(S("foo").casecmp?(Object.new)) + assert_nil("foo".casecmp?(:foo)) + assert_nil("foo".casecmp?(Object.new)) o = Object.new def o.to_str; "fOO"; end - assert_equal(true, S("FoO").casecmp?(o)) + assert_equal(true, "FoO".casecmp?(o)) end def test_upcase2 - assert_equal("\u3042AB", S("\u3042aB").upcase) + assert_equal("\u3042AB", "\u3042aB".upcase) end def test_downcase2 - assert_equal("\u3042ab", S("\u3042aB").downcase) + assert_equal("\u3042ab", "\u3042aB".downcase) end def test_rstrip - assert_equal(" hello", S(" hello ").rstrip) - assert_equal("\u3042", S("\u3042 ").rstrip) - assert_equal("\u3042", S("\u3042\u0000").rstrip) - assert_raise(Encoding::CompatibilityError) { S("\u3042".encode("ISO-2022-JP")).rstrip } + assert_equal(" hello", " hello ".rstrip) + assert_equal("\u3042", "\u3042 ".rstrip) + assert_equal("\u3042", "\u3042\u0000".rstrip) + assert_raise(Encoding::CompatibilityError) { "\u3042".encode("ISO-2022-JP").rstrip } end def test_rstrip_bang @@ -2859,18 +2746,13 @@ CODE assert_equal("\u3042", s5.rstrip!) assert_equal("\u3042", s5) - assert_raise(Encoding::CompatibilityError) { S("\u3042".encode("ISO-2022-JP")).rstrip! } - assert_raise(Encoding::CompatibilityError) { S("abc \x80 ".force_encoding('UTF-8')).rstrip! } - assert_raise(Encoding::CompatibilityError) { S("abc\x80 ".force_encoding('UTF-8')).rstrip! } - assert_raise(Encoding::CompatibilityError) { S("abc \x80".force_encoding('UTF-8')).rstrip! } - assert_raise(Encoding::CompatibilityError) { S("\x80".force_encoding('UTF-8')).rstrip! } - assert_raise(Encoding::CompatibilityError) { S(" \x80 ".force_encoding('UTF-8')).rstrip! } + assert_raise(Encoding::CompatibilityError) { "\u3042".encode("ISO-2022-JP").rstrip! } end def test_lstrip - assert_equal("hello ", S(" hello ").lstrip) - assert_equal("\u3042", S(" \u3042").lstrip) - assert_equal("hello ", S("\x00hello ").lstrip) + assert_equal("hello ", " hello ".lstrip) + assert_equal("\u3042", " \u3042".lstrip) + assert_equal("hello ", "\x00hello ".lstrip) end def test_lstrip_bang @@ -2896,13 +2778,11 @@ CODE end - def test_delete_prefix_type_error - assert_raise(TypeError) { S('hello').delete_prefix(nil) } - assert_raise(TypeError) { S('hello').delete_prefix(1) } - assert_raise(TypeError) { S('hello').delete_prefix(/hel/) } - end - def test_delete_prefix + assert_raise(TypeError) { 'hello'.delete_prefix(nil) } + assert_raise(TypeError) { 'hello'.delete_prefix(1) } + assert_raise(TypeError) { 'hello'.delete_prefix(/hel/) } + s = S("hello") assert_equal("lo", s.delete_prefix('hel')) assert_equal("hello", s) @@ -2922,9 +2802,8 @@ CODE s = S("hello") assert_equal("hello", s.delete_prefix("\u{3053 3093}")) assert_equal("hello", s) - end - def test_delete_prefix_broken_encoding + # skip if argument is a broken string s = S("\xe3\x81\x82") assert_equal("\xe3\x81\x82", s.delete_prefix("\xe3")) assert_equal("\xe3\x81\x82", s) @@ -2933,31 +2812,23 @@ CODE assert_equal("\x95\x5c".force_encoding("Shift_JIS"), s.delete_prefix("\x95")) assert_equal("\x95\x5c".force_encoding("Shift_JIS"), s) - assert_equal("\xFE", S("\xFF\xFE").delete_prefix("\xFF")) - assert_equal("\xBE", S("hello\xBE").delete_prefix("hello")) - assert_equal("\xBE", S("\xFFhello\xBE").delete_prefix("\xFFhello")) - end - - def test_delete_prefix_clear_coderange + # clear coderange s = S("\u{3053 3093}hello") assert_not_predicate(s, :ascii_only?) assert_predicate(s.delete_prefix("\u{3053 3093}"), :ascii_only?) - end - def test_delete_prefix_argument_conversion + # argument should be converted to String klass = Class.new { def to_str; 'a'; end } s = S("abba") assert_equal("bba", s.delete_prefix(klass.new)) assert_equal("abba", s) end - def test_delete_prefix_bang_type_error - assert_raise(TypeError) { S('hello').delete_prefix!(nil) } - assert_raise(TypeError) { S('hello').delete_prefix!(1) } - assert_raise(TypeError) { S('hello').delete_prefix!(/hel/) } - end - def test_delete_prefix_bang + assert_raise(TypeError) { 'hello'.delete_prefix!(nil) } + assert_raise(TypeError) { 'hello'.delete_prefix!(1) } + assert_raise(TypeError) { 'hello'.delete_prefix!(/hel/) } + s = S("hello") assert_equal("lo", s.delete_prefix!('hel')) assert_equal("lo", s) @@ -2977,32 +2848,23 @@ CODE s = S("hello") assert_equal(nil, s.delete_prefix!("\u{3053 3093}")) assert_equal("hello", s) - end - def test_delete_prefix_bang_broken_encoding + # skip if argument is a broken string s = S("\xe3\x81\x82") assert_equal(nil, s.delete_prefix!("\xe3")) assert_equal("\xe3\x81\x82", s) - s = S("\xFF\xFE") - assert_equal("\xFE", s.delete_prefix!("\xFF")) - assert_equal("\xFE", s) - end - - def test_delete_prefix_bang_clear_coderange + # clear coderange s = S("\u{3053 3093}hello") assert_not_predicate(s, :ascii_only?) assert_predicate(s.delete_prefix!("\u{3053 3093}"), :ascii_only?) - end - def test_delete_prefix_bang_argument_conversion + # argument should be converted to String klass = Class.new { def to_str; 'a'; end } s = S("abba") assert_equal("bba", s.delete_prefix!(klass.new)) assert_equal("bba", s) - end - def test_delete_prefix_bang_frozen_error s = S("ax").freeze assert_raise_with_message(FrozenError, /frozen/) {s.delete_prefix!("a")} @@ -3015,13 +2877,11 @@ CODE assert_raise_with_message(FrozenError, /frozen/) {s.delete_prefix!(o)} end - def test_delete_suffix_type_error - assert_raise(TypeError) { S('hello').delete_suffix(nil) } - assert_raise(TypeError) { S('hello').delete_suffix(1) } - assert_raise(TypeError) { S('hello').delete_suffix(/hel/) } - end - def test_delete_suffix + assert_raise(TypeError) { 'hello'.delete_suffix(nil) } + assert_raise(TypeError) { 'hello'.delete_suffix(1) } + assert_raise(TypeError) { 'hello'.delete_suffix(/hel/) } + s = S("hello") assert_equal("hel", s.delete_suffix('lo')) assert_equal("hello", s) @@ -3041,28 +2901,23 @@ CODE s = S("hello") assert_equal("hello", s.delete_suffix("\u{3061 306f}")) assert_equal("hello", s) - end - def test_delete_suffix_broken_encoding + # skip if argument is a broken string s = S("\xe3\x81\x82") assert_equal("\xe3\x81\x82", s.delete_suffix("\x82")) assert_equal("\xe3\x81\x82", s) - end - def test_delete_suffix_clear_coderange + # clear coderange s = S("hello\u{3053 3093}") assert_not_predicate(s, :ascii_only?) assert_predicate(s.delete_suffix("\u{3053 3093}"), :ascii_only?) - end - def test_delete_suffix_argument_conversion + # argument should be converted to String klass = Class.new { def to_str; 'a'; end } s = S("abba") assert_equal("abb", s.delete_suffix(klass.new)) assert_equal("abba", s) - end - def test_delete_suffix_newline # chomp removes any of "\n", "\r\n", "\r" when "\n" is specified, # but delete_suffix does not s = "foo\n" @@ -3073,13 +2928,11 @@ CODE assert_equal("foo\r", s.delete_suffix("\n")) end - def test_delete_suffix_bang_type_error - assert_raise(TypeError) { S('hello').delete_suffix!(nil) } - assert_raise(TypeError) { S('hello').delete_suffix!(1) } - assert_raise(TypeError) { S('hello').delete_suffix!(/hel/) } - end + def test_delete_suffix_bang + assert_raise(TypeError) { 'hello'.delete_suffix!(nil) } + assert_raise(TypeError) { 'hello'.delete_suffix!(1) } + assert_raise(TypeError) { 'hello'.delete_suffix!(/hel/) } - def test_delete_suffix_bang_frozen_error s = S("hello").freeze assert_raise_with_message(FrozenError, /frozen/) {s.delete_suffix!('lo')} @@ -3090,9 +2943,7 @@ CODE "x" end assert_raise_with_message(FrozenError, /frozen/) {s.delete_suffix!(o)} - end - def test_delete_suffix_bang s = S("hello") assert_equal("hel", s.delete_suffix!('lo')) assert_equal("hel", s) @@ -3112,9 +2963,8 @@ CODE s = S("hello") assert_equal(nil, s.delete_suffix!("\u{3061 306f}")) assert_equal("hello", s) - end - def test_delete_suffix_bang_broken_encoding + # skip if argument is a broken string s = S("\xe3\x81\x82") assert_equal(nil, s.delete_suffix!("\x82")) assert_equal("\xe3\x81\x82", s) @@ -3122,22 +2972,18 @@ CODE s = S("\x95\x5c").force_encoding("Shift_JIS") assert_equal(nil, s.delete_suffix!("\x5c")) assert_equal("\x95\x5c".force_encoding("Shift_JIS"), s) - end - def test_delete_suffix_bang_clear_coderange + # clear coderange s = S("hello\u{3053 3093}") assert_not_predicate(s, :ascii_only?) assert_predicate(s.delete_suffix!("\u{3053 3093}"), :ascii_only?) - end - def test_delete_suffix_bang_argument_conversion + # argument should be converted to String klass = Class.new { def to_str; 'a'; end } s = S("abba") assert_equal("abb", s.delete_suffix!(klass.new)) assert_equal("abb", s) - end - def test_delete_suffix_bang_newline # chomp removes any of "\n", "\r\n", "\r" when "\n" is specified, # but delete_suffix does not s = "foo\n" @@ -3174,7 +3020,7 @@ CODE end def test_shared_force_encoding - s = S("\u{3066}\u{3059}\u{3068}").gsub(//, '') + s = "\u{3066}\u{3059}\u{3068}".gsub(//, '') h = {} h[s] = nil k = h.keys[0] @@ -3189,16 +3035,16 @@ CODE def test_ascii_incomat_inspect bug4081 = '[ruby-core:33283]' WIDE_ENCODINGS.each do |e| - assert_equal('"abc"', S("abc".encode(e)).inspect) - assert_equal('"\\u3042\\u3044\\u3046"', S("\u3042\u3044\u3046".encode(e)).inspect) - assert_equal('"ab\\"c"', S("ab\"c".encode(e)).inspect, bug4081) + assert_equal('"abc"', "abc".encode(e).inspect) + assert_equal('"\\u3042\\u3044\\u3046"', "\u3042\u3044\u3046".encode(e).inspect) + assert_equal('"ab\\"c"', "ab\"c".encode(e).inspect, bug4081) end begin verbose, $VERBOSE = $VERBOSE, nil ext = Encoding.default_external Encoding.default_external = "us-ascii" $VERBOSE = verbose - i = S("abc\"\\".force_encoding("utf-8")).inspect + i = "abc\"\\".force_encoding("utf-8").inspect ensure $VERBOSE = nil Encoding.default_external = ext @@ -3209,11 +3055,11 @@ CODE def test_dummy_inspect assert_equal('"\e\x24\x42\x22\x4C\x22\x68\e\x28\x42"', - S("\u{ffe2}\u{2235}".encode("cp50220")).inspect) + "\u{ffe2}\u{2235}".encode("cp50220").inspect) end def test_prepend - assert_equal(S("hello world!"), S("!").prepend("hello ", "world")) + assert_equal(S("hello world!"), "!".prepend("hello ", "world")) b = S("ue") assert_equal(S("ueueue"), b.prepend(b, b)) @@ -3221,7 +3067,7 @@ CODE def foo.to_str "b" end - assert_equal(S("ba"), S("a").prepend(foo)) + assert_equal(S("ba"), "a".prepend(foo)) a = S("world") b = S("hello ") @@ -3235,34 +3081,34 @@ CODE end def test_byteslice - assert_equal("h", S("hello").byteslice(0)) - assert_equal(nil, S("hello").byteslice(5)) - assert_equal("o", S("hello").byteslice(-1)) - assert_equal(nil, S("hello").byteslice(-6)) - - assert_equal("", S("hello").byteslice(0, 0)) - assert_equal("hello", S("hello").byteslice(0, 6)) - assert_equal("hello", S("hello").byteslice(0, 6)) - assert_equal("", S("hello").byteslice(5, 1)) - assert_equal("o", S("hello").byteslice(-1, 6)) - assert_equal(nil, S("hello").byteslice(-6, 1)) - assert_equal(nil, S("hello").byteslice(0, -1)) - - assert_equal("h", S("hello").byteslice(0..0)) - assert_equal("", S("hello").byteslice(5..0)) - assert_equal("o", S("hello").byteslice(4..5)) - assert_equal(nil, S("hello").byteslice(6..0)) - assert_equal("", S("hello").byteslice(-1..0)) - assert_equal("llo", S("hello").byteslice(-3..5)) - - assert_equal(u("\x81"), S("\u3042").byteslice(1)) - assert_equal(u("\x81\x82"), S("\u3042").byteslice(1, 2)) - assert_equal(u("\x81\x82"), S("\u3042").byteslice(1..2)) - - assert_equal(u("\x82")+("\u3042"*9), S("\u3042"*10).byteslice(2, 28)) + assert_equal("h", "hello".byteslice(0)) + assert_equal(nil, "hello".byteslice(5)) + assert_equal("o", "hello".byteslice(-1)) + assert_equal(nil, "hello".byteslice(-6)) + + assert_equal("", "hello".byteslice(0, 0)) + assert_equal("hello", "hello".byteslice(0, 6)) + assert_equal("hello", "hello".byteslice(0, 6)) + assert_equal("", "hello".byteslice(5, 1)) + assert_equal("o", "hello".byteslice(-1, 6)) + assert_equal(nil, "hello".byteslice(-6, 1)) + assert_equal(nil, "hello".byteslice(0, -1)) + + assert_equal("h", "hello".byteslice(0..0)) + assert_equal("", "hello".byteslice(5..0)) + assert_equal("o", "hello".byteslice(4..5)) + assert_equal(nil, "hello".byteslice(6..0)) + assert_equal("", "hello".byteslice(-1..0)) + assert_equal("llo", "hello".byteslice(-3..5)) + + assert_equal(u("\x81"), "\u3042".byteslice(1)) + assert_equal(u("\x81\x82"), "\u3042".byteslice(1, 2)) + assert_equal(u("\x81\x82"), "\u3042".byteslice(1..2)) + + assert_equal(u("\x82")+("\u3042"*9), ("\u3042"*10).byteslice(2, 28)) bug7954 = '[ruby-dev:47108]' - assert_equal(false, S("\u3042").byteslice(0, 2).valid_encoding?, bug7954) + assert_equal(false, "\u3042".byteslice(0, 2).valid_encoding?, bug7954) assert_equal(false, ("\u3042"*10).byteslice(0, 20).valid_encoding?, bug7954) end @@ -3277,8 +3123,6 @@ CODE end def test_eq_tilde_can_be_overridden - return unless @cls == String - assert_separately([], <<-RUBY) class String undef =~ @@ -3296,7 +3140,7 @@ CODE end def test_regexp_match_subclass - s = Bug9581.new(S("abc")) + s = Bug9581.new("abc") r = /abc/ assert_equal(:foo, s =~ r) assert_equal(:foo, s.send(:=~, r)) @@ -3306,7 +3150,6 @@ CODE def test_LSHIFT_neary_long_max return unless @cls == String - assert_ruby_status([], <<-'end;', '[ruby-core:61886] [Bug #9709]', timeout: 20) begin a = "a" * 0x4000_0000 @@ -3318,8 +3161,6 @@ CODE # enable only when string size range is smaller than memory space def test_uplus_minus - return unless @cls == String - str = "foo" assert_not_predicate(str, :frozen?) assert_not_predicate(+str, :frozen?) @@ -3341,8 +3182,6 @@ CODE end def test_uminus_frozen - return unless @cls == String - # embedded str1 = ("foobar" * 3).freeze str2 = ("foobar" * 3).freeze @@ -3359,274 +3198,45 @@ CODE end def test_uminus_no_freeze_not_bare - str = S("foo") + str = @cls.new("foo") assert_instance_of(@cls, -str) assert_equal(false, str.frozen?) - str = S("foo") + str = @cls.new("foo") str.instance_variable_set(:@iv, 1) assert_instance_of(@cls, -str) assert_equal(false, str.frozen?) assert_equal(1, str.instance_variable_get(:@iv)) - str = S("foo") + str = @cls.new("foo") assert_instance_of(@cls, -str) assert_equal(false, str.frozen?) end def test_ord - assert_equal(97, S("a").ord) - assert_equal(97, S("abc").ord) - assert_equal(0x3042, S("\u3042\u3043").ord) - assert_raise(ArgumentError) { S("").ord } + assert_equal(97, "a".ord) + assert_equal(97, "abc".ord) + assert_equal(0x3042, "\u3042\u3043".ord) + assert_raise(ArgumentError) { "".ord } end def test_chr - assert_equal("a", S("abcde").chr) - assert_equal("a", S("a").chr) - assert_equal("\u3042", S("\u3042\u3043").chr) - assert_equal('', S('').chr) + assert_equal("a", "abcde".chr) + assert_equal("a", "a".chr) + assert_equal("\u3042", "\u3042\u3043".chr) + assert_equal('', ''.chr) end def test_substr_code_range - data = S("\xff" + "a"*200) + data = "\xff" + "a"*200 assert_not_predicate(data, :valid_encoding?) assert_predicate(data[100..-1], :valid_encoding?) end - def test_byteindex - assert_byteindex(0, S("hello"), ?h) - assert_byteindex(1, S("hello"), S("ell")) - assert_byteindex(2, S("hello"), /ll./) - - assert_byteindex(3, S("hello"), ?l, 3) - assert_byteindex(3, S("hello"), S("l"), 3) - assert_byteindex(3, S("hello"), /l./, 3) - - assert_byteindex(nil, S("hello"), ?z, 3) - assert_byteindex(nil, S("hello"), S("z"), 3) - assert_byteindex(nil, S("hello"), /z./, 3) - - assert_byteindex(nil, S("hello"), ?z) - assert_byteindex(nil, S("hello"), S("z")) - assert_byteindex(nil, S("hello"), /z./) - - assert_byteindex(0, S(""), S("")) - assert_byteindex(0, S(""), //) - assert_byteindex(nil, S(""), S("hello")) - assert_byteindex(nil, S(""), /hello/) - assert_byteindex(0, S("hello"), S("")) - assert_byteindex(0, S("hello"), //) - - s = S("long") * 1000 << "x" - assert_byteindex(nil, s, S("y")) - assert_byteindex(4 * 1000, s, S("x")) - s << "yx" - assert_byteindex(4 * 1000, s, S("x")) - assert_byteindex(4 * 1000, s, S("xyx")) - - o = Object.new - def o.to_str; "bar"; end - assert_byteindex(3, S("foobarbarbaz"), o) - assert_raise(TypeError) { S("foo").byteindex(Object.new) } - - assert_byteindex(nil, S("foo"), //, -100) - assert_byteindex(nil, S("foo"), //, -4) - - assert_byteindex(2, S("abcdbce"), /b\Kc/) - - assert_byteindex(0, S("こんにちは"), ?こ) - assert_byteindex(3, S("こんにちは"), S("んにち")) - assert_byteindex(6, S("こんにちは"), /にち./) - - assert_byteindex(0, S("にんにちは"), ?に, 0) - assert_raise(IndexError) { S("にんにちは").byteindex(?に, 1) } - assert_raise(IndexError) { S("にんにちは").byteindex(?に, 5) } - assert_byteindex(6, S("にんにちは"), ?に, 6) - assert_byteindex(6, S("にんにちは"), S("に"), 6) - assert_byteindex(6, S("にんにちは"), /に./, 6) - assert_raise(IndexError) { S("にんにちは").byteindex(?に, 7) } - - s = S("foobarbarbaz") - assert !1000.times.any? {s.byteindex("", 100_000_000)} - end - - def test_byterindex - assert_byterindex(3, S("hello"), ?l) - assert_byterindex(6, S("ell, hello"), S("ell")) - assert_byterindex(7, S("ell, hello"), /ll./) - - assert_byterindex(3, S("hello,lo"), ?l, 3) - assert_byterindex(3, S("hello,lo"), S("l"), 3) - assert_byterindex(3, S("hello,lo"), /l./, 3) - - assert_byterindex(nil, S("hello"), ?z, 3) - assert_byterindex(nil, S("hello"), S("z"), 3) - assert_byterindex(nil, S("hello"), /z./, 3) - - assert_byterindex(nil, S("hello"), ?z) - assert_byterindex(nil, S("hello"), S("z")) - assert_byterindex(nil, S("hello"), /z./) - - assert_byterindex(5, S("hello"), S("")) - assert_byterindex(5, S("hello"), S(""), 5) - assert_byterindex(4, S("hello"), S(""), 4) - assert_byterindex(0, S("hello"), S(""), 0) - - o = Object.new - def o.to_str; "bar"; end - assert_byterindex(6, S("foobarbarbaz"), o) - assert_raise(TypeError) { S("foo").byterindex(Object.new) } - - assert_byterindex(nil, S("foo"), //, -100) - - m = assert_byterindex(3, S("foo"), //) - assert_equal([3, 3], m.offset(0)) - assert_byterindex(3, S("foo"), //, 4) - - assert_byterindex(5, S("abcdbce"), /b\Kc/) - - assert_byterindex(6, S("こんにちは"), ?に) - assert_byterindex(18, S("にちは、こんにちは"), S("にちは")) - assert_byterindex(18, S("にちは、こんにちは"), /にち./) - - assert_raise(IndexError) { S("にちは、こんにちは").byterindex(S("にちは"), 19) } - assert_raise(IndexError) { S("にちは、こんにちは").byterindex(S("にちは"), -2) } - assert_byterindex(18, S("にちは、こんにちは"), S("にちは"), 18) - assert_byterindex(18, S("にちは、こんにちは"), S("にちは"), -3) - assert_raise(IndexError) { S("にちは、こんにちは").byterindex(S("にちは"), 17) } - assert_raise(IndexError) { S("にちは、こんにちは").byterindex(S("にちは"), -4) } - assert_raise(IndexError) { S("にちは、こんにちは").byterindex(S("にちは"), 1) } - assert_byterindex(0, S("にちは、こんにちは"), S("にちは"), 0) - - assert_byterindex(0, S("こんにちは"), S("こんにちは")) - assert_byterindex(nil, S("こんにち"), S("こんにちは")) - assert_byterindex(nil, S("こ"), S("こんにちは")) - assert_byterindex(nil, S(""), S("こんにちは")) - end - - def test_bytesplice - assert_bytesplice_raise(IndexError, S("hello"), -6, 0, "bye") - assert_bytesplice_result("byehello", S("hello"), -5, 0, "bye") - assert_bytesplice_result("byehello", S("hello"), 0, 0, "bye") - assert_bytesplice_result("byeello", S("hello"), 0, 1, "bye") - assert_bytesplice_result("bye", S("hello"), 0, 5, "bye") - assert_bytesplice_result("bye", S("hello"), 0, 6, "bye") - - assert_bytesplice_raise(IndexError, S("hello"), -5, 0, "bye", -4, 0) - assert_bytesplice_result("byehello", S("hello"), 0, 0, "bye", 0, 3) - assert_bytesplice_result("yehello", S("hello"), 0, 0, "bye", 1, 3) - assert_bytesplice_result("yehello", S("hello"), 0, 0, "bye", 1, 2) - assert_bytesplice_result("ehello", S("hello"), 0, 0, "bye", 2, 1) - assert_bytesplice_result("hello", S("hello"), 0, 0, "bye", 3, 0) - assert_bytesplice_result("hello", s = S("hello"), 0, 5, s, 0, 5) - assert_bytesplice_result("elloo", s = S("hello"), 0, 4, s, 1, 4) - assert_bytesplice_result("llolo", s = S("hello"), 0, 3, s, 2, 3) - assert_bytesplice_result("lollo", s = S("hello"), 0, 2, s, 3, 2) - assert_bytesplice_result("oello", s = S("hello"), 0, 1, s, 4, 1) - assert_bytesplice_result("hhell", s = S("hello"), 1, 4, s, 0, 4) - assert_bytesplice_result("hehel", s = S("hello"), 2, 3, s, 0, 3) - assert_bytesplice_result("helhe", s = S("hello"), 3, 2, s, 0, 2) - assert_bytesplice_result("hellh", s = S("hello"), 4, 1, s, 0, 1) - - assert_bytesplice_raise(RangeError, S("hello"), -6...-6, "bye") - assert_bytesplice_result("byehello", S("hello"), -5...-5, "bye") - assert_bytesplice_result("byehello", S("hello"), 0...0, "bye") - assert_bytesplice_result("byeello", S("hello"), 0..0, "bye") - assert_bytesplice_result("byeello", S("hello"), 0...1, "bye") - assert_bytesplice_result("byello", S("hello"), 0..1, "bye") - assert_bytesplice_result("bye", S("hello"), 0..-1, "bye") - assert_bytesplice_result("bye", S("hello"), 0...5, "bye") - assert_bytesplice_result("bye", S("hello"), 0...6, "bye") - assert_bytesplice_result("llolo", s = S("hello"), 0..2, s, 2..4) - - assert_bytesplice_raise(RangeError, S("hello"), -5...-5, "bye", -6...-6) - assert_bytesplice_result("byehello", S("hello"), -5...-5, "bye", 0..-1) - assert_bytesplice_result("byehello", S("hello"), 0...0, "bye", 0..-1) - assert_bytesplice_result("bhello", S("hello"), 0...0, "bye", 0..0) - assert_bytesplice_result("byhello", S("hello"), 0...0, "bye", 0..1) - assert_bytesplice_result("byehello", S("hello"), 0...0, "bye", 0..2) - assert_bytesplice_result("yehello", S("hello"), 0...0, "bye", 1..2) - - assert_bytesplice_raise(TypeError, S("hello"), 0, "bye") - - assert_bytesplice_raise(IndexError, S("こんにちは"), -16, 0, "bye") - assert_bytesplice_result("byeこんにちは", S("こんにちは"), -15, 0, "bye") - assert_bytesplice_result("byeこんにちは", S("こんにちは"), 0, 0, "bye") - assert_bytesplice_raise(IndexError, S("こんにちは"), 1, 0, "bye") - assert_bytesplice_raise(IndexError, S("こんにちは"), 0, 1, "bye") - assert_bytesplice_raise(IndexError, S("こんにちは"), 0, 2, "bye") - assert_bytesplice_result("byeんにちは", S("こんにちは"), 0, 3, "bye") - assert_bytesplice_result("こんにちはbye", S("こんにちは"), 15, 0, "bye") - - assert_bytesplice_raise(IndexError, S("こんにちは"), 0, 0, "さようなら", -16, 0) - assert_bytesplice_result("こんにちはさようなら", S("こんにちは"), 15, 0, "さようなら", 0, 15) - assert_bytesplice_result("さようなら", S("こんにちは"), 0, 15, "さようなら", 0, 15) - assert_bytesplice_result("さんにちは", S("こんにちは"), 0, 3, "さようなら", 0, 3) - assert_bytesplice_result("さようちは", S("こんにちは"), 0, 9, "さようなら", 0, 9) - assert_bytesplice_result("ようなちは", S("こんにちは"), 0, 9, "さようなら", 3, 9) - assert_bytesplice_result("ようちは", S("こんにちは"), 0, 9, "さようなら", 3, 6) - assert_bytesplice_result("ようならちは", S("こんにちは"), 0, 9, "さようなら", 3, 12) - assert_bytesplice_raise(IndexError, S("こんにちは"), 0, 15, "さようなら", -16, 0) - assert_bytesplice_raise(IndexError, S("こんにちは"), 0, 15, "さようなら", 1, 0) - assert_bytesplice_raise(IndexError, S("こんにちは"), 0, 15, "さようなら", 2, 0) - assert_bytesplice_raise(IndexError, S("こんにちは"), 0, 15, "さようなら", 0, 1) - assert_bytesplice_raise(IndexError, S("こんにちは"), 0, 15, "さようなら", 0, 2) - assert_bytesplice_result("にちはちは", s = S("こんにちは"), 0, 9, s, 6, 9) - - assert_bytesplice_result("", S(""), 0, 0, "") - assert_bytesplice_result("xxx", S(""), 0, 0, "xxx") - - assert_bytesplice_raise(ArgumentError, S("hello"), 0, 5, "bye", 0) - assert_bytesplice_raise(ArgumentError, S("hello"), 0, 5, "bye", 0..-1) - assert_bytesplice_raise(ArgumentError, S("hello"), 0..-1, "bye", 0, 3) - end - - private - - def assert_bytesplice_result(expected, s, *args) - assert_equal(expected, s.send(:bytesplice, *args)) - assert_equal(expected, s) - end - - def assert_bytesplice_raise(e, s, *args) - assert_raise(e) { s.send(:bytesplice, *args) } - end - - def assert_index_like(method, expected, string, match, *rest) - message = "#{method} with string does not affect $~" - /.*/ =~ message - md_before = $~ - assert_equal(expected, string.__send__(method, match, *rest)) - md_after = $~ - case match - when Regexp - if expected - assert_not_nil(md_after) - assert_not_same(md_before, md_after) - else - assert_nil(md_after) - end - else - assert_same(md_before, md_after) - end - md_after - end - - def assert_index(expected, string, match, *rest) - assert_index_like(:index, expected, string, match, *rest) - end - - def assert_rindex(expected, string, match, *rest) - assert_index_like(:rindex, expected, string, match, *rest) - end - - def assert_byteindex(expected, string, match, *rest) - assert_index_like(:byteindex, expected, string, match, *rest) - end - - def assert_byterindex(expected, string, match, *rest) - assert_index_like(:byterindex, expected, string, match, *rest) + def test_slice_bang_code_range + str = "[Bug #19739] ABC OÜ" + str.slice!(/ oü$/i) + assert_predicate str, :ascii_only? end end diff --git a/test/ruby/test_string_memory.rb b/test/ruby/test_string_memory.rb deleted file mode 100644 index 3b4694f36f..0000000000 --- a/test/ruby/test_string_memory.rb +++ /dev/null @@ -1,55 +0,0 @@ -# frozen_string_literal: false -require 'test/unit' -require 'objspace' - -class TestStringMemory < Test::Unit::TestCase - def capture_allocations(klass) - allocations = [] - - GC.start - GC.disable - generation = GC.count - - ObjectSpace.trace_object_allocations do - yield - - ObjectSpace.each_object(klass) do |instance| - allocations << instance if ObjectSpace.allocation_generation(instance) == generation - end - end - - return allocations - ensure - GC.enable - end - - def test_byteslice_prefix - string = ("a" * 100_000).freeze - - allocations = capture_allocations(String) do - string.byteslice(0, 50_000) - end - - assert_equal 1, allocations.size - end - - def test_byteslice_postfix - string = ("a" * 100_000).freeze - - allocations = capture_allocations(String) do - string.byteslice(50_000, 100_000) - end - - assert_equal 1, allocations.size - end - - def test_byteslice_postfix_twice - string = ("a" * 100_000).freeze - - allocations = capture_allocations(String) do - string.byteslice(50_000, 100_000).byteslice(25_000, 50_000) - end - - assert_equal 2, allocations.size - end -end diff --git a/test/ruby/test_struct.rb b/test/ruby/test_struct.rb index ed750b91f7..176e2ac5de 100644 --- a/test/ruby/test_struct.rb +++ b/test/ruby/test_struct.rb @@ -41,14 +41,6 @@ module TestStruct end end - def test_larger_than_largest_pool - count = (GC::INTERNAL_CONSTANTS[:RVARGC_MAX_ALLOCATE_SIZE] / RbConfig::SIZEOF["void*"]) + 1 - list = Array(0..count) - klass = @Struct.new(*list.map { |i| :"a_#{i}"}) - struct = klass.new(*list) - assert_equal 0, struct.a_0 - end - def test_small_structs names = [:a, :b, :c, :d] 1.upto(4) {|n| @@ -108,9 +100,8 @@ module TestStruct assert_equal([:utime, :stime, :cutime, :cstime], Process.times.members) end - def test_struct_new_with_hash - assert_raise_with_message(TypeError, /not a symbol/) {Struct.new(:a, {})} - assert_raise_with_message(TypeError, /not a symbol/) {Struct.new(:a, {name: "b"})} + def test_struct_new_with_empty_hash + assert_equal({:a=>1}, Struct.new(:a, {}).new({:a=>1}).a) end def test_struct_new_with_keyword_init @@ -371,8 +362,9 @@ module TestStruct end def test_keyword_args_warning - assert_warn('') { assert_equal(1, @Struct.new(:a).new(a: 1).a) } - assert_warn('') { assert_equal(1, @Struct.new(:a, keyword_init: nil).new(a: 1).a) } + warning = /warning: Passing only keyword arguments to Struct#initialize will behave differently from Ruby 3\.2\./ + assert_warn(warning) { assert_equal({a: 1}, @Struct.new(:a).new(a: 1).a) } + assert_warn(warning) { assert_equal({a: 1}, @Struct.new(:a, keyword_init: nil).new(a: 1).a) } assert_warn('') { assert_equal({a: 1}, @Struct.new(:a).new({a: 1}).a) } assert_warn('') { assert_equal({a: 1}, @Struct.new(:a, :b).new(1, a: 1).b) } assert_warn('') { assert_equal(1, @Struct.new(:a, keyword_init: true).new(a: 1).a) } diff --git a/test/ruby/test_symbol.rb b/test/ruby/test_symbol.rb index 1d2a18d734..f7f17b8d67 100644 --- a/test/ruby/test_symbol.rb +++ b/test/ruby/test_symbol.rb @@ -36,19 +36,6 @@ class TestSymbol < Test::Unit::TestCase assert_eval_inspected(:"@@1", false) assert_eval_inspected(:"@", false) assert_eval_inspected(:"@@", false) - assert_eval_inspected(:"[]=") - assert_eval_inspected(:"[][]", false) - assert_eval_inspected(:"[][]=", false) - assert_eval_inspected(:"@=", false) - assert_eval_inspected(:"@@=", false) - assert_eval_inspected(:"@x=", false) - assert_eval_inspected(:"@@x=", false) - assert_eval_inspected(:"$$=", false) - assert_eval_inspected(:"$==", false) - assert_eval_inspected(:"$x=", false) - assert_eval_inspected(:"$$$=", false) - assert_eval_inspected(:"foo?=", false) - assert_eval_inspected(:"foo!=", false) end def assert_inspect_evaled(n) diff --git a/test/ruby/test_syntax.rb b/test/ruby/test_syntax.rb index cda84c6368..53036cab3b 100644 --- a/test/ruby/test_syntax.rb +++ b/test/ruby/test_syntax.rb @@ -13,7 +13,8 @@ class TestSyntax < Test::Unit::TestCase def assert_syntax_files(test) srcdir = File.expand_path("../../..", __FILE__) srcdir = File.join(srcdir, test) - assert_separately(%W[- #{srcdir}], __FILE__, __LINE__, <<-'eom', timeout: Float::INFINITY) + assert_separately(%W[--disable-gem - #{srcdir}], + __FILE__, __LINE__, <<-'eom', timeout: Float::INFINITY) dir = ARGV.shift for script in Dir["#{dir}/**/*.rb"].sort assert_valid_syntax(IO::read(script), script) @@ -140,44 +141,6 @@ class TestSyntax < Test::Unit::TestCase end; end - def test_anonymous_rest_forwarding - assert_syntax_error("def b; c(*); end", /no anonymous rest parameter/) - assert_syntax_error("def b; c(1, *); end", /no anonymous rest parameter/) - assert_separately([], "#{<<-"begin;"}\n#{<<-'end;'}") - begin; - def b(*); c(*) end - def c(*a); a end - def d(*); b(*, *) end - assert_equal([1, 2], b(1, 2)) - assert_equal([1, 2, 1, 2], d(1, 2)) - end; - end - - def test_anonymous_keyword_rest_forwarding - assert_syntax_error("def b; c(**); end", /no anonymous keyword rest parameter/) - assert_syntax_error("def b; c(k: 1, **); end", /no anonymous keyword rest parameter/) - assert_separately([], "#{<<-"begin;"}\n#{<<-'end;'}") - begin; - def b(**); c(**) end - def c(**kw); kw end - def d(**); b(k: 1, **) end - def e(**); b(**, k: 1) end - def f(a: nil, **); b(**) end - assert_equal({a: 1, k: 3}, b(a: 1, k: 3)) - assert_equal({a: 1, k: 3}, d(a: 1, k: 3)) - assert_equal({a: 1, k: 1}, e(a: 1, k: 3)) - assert_equal({k: 3}, f(a: 1, k: 3)) - end; - end - - def test_argument_forwarding_with_anon_rest_kwrest_and_block - assert_syntax_error("def f(*, **, &); g(...); end", /unexpected \.\.\./) - assert_syntax_error("def f(...); g(*); end", /no anonymous rest parameter/) - assert_syntax_error("def f(...); g(0, *); end", /no anonymous rest parameter/) - assert_syntax_error("def f(...); g(**); end", /no anonymous keyword rest parameter/) - assert_syntax_error("def f(...); g(x: 1, **); end", /no anonymous keyword rest parameter/) - end - def test_newline_in_block_parameters bug = '[ruby-dev:45292]' ["", "a", "a, b"].product(["", ";x", [";", "x"]]) do |params| @@ -989,7 +952,7 @@ eom ["p ", ""], # no-pop ["", "p Foo::Bar"], # pop ].each do |p1, p2| - src = <<~EOM + src = <<-EOM.gsub(/^\s*\n/, '') class Foo #{"Bar = " + preset if preset} end @@ -1021,7 +984,7 @@ eom ["p ", ""], # no-pop ["", "p ::Bar"], # pop ].each do |p1, p2| - src = <<~EOM + src = <<-EOM.gsub(/^\s*\n/, '') #{"Bar = " + preset if preset} class Foo #{p1}::Bar #{op}= 42 @@ -1368,8 +1331,6 @@ eom begin raise; ensure return; end and self nil&defined?0--begin e=no_method_error(); return; 0;end return puts('ignored') #=> ignored - BEGIN {return} - END {return if false} end; .split(/\n/).map {|s|[(line+=1), *s.split(/#=> /, 2)]} failed = proc do |n, s| @@ -1407,20 +1368,6 @@ eom assert_in_out_err(['-e', 'class TestSyntax; proc{ return }.call; end'], "", [], /^-e:1:.*unexpected return \(LocalJumpError\)/) end - def test_return_in_END - assert_normal_exit('END {return}') - end - - def test_return_in_BEGIN_in_eval - # `BEGIN` in `eval` is allowed, even inside a method, and `return` - # from that block exits from that method without `LocalJumpError`. - obj = Object.new - def obj.ok - eval("BEGIN {return :ok}") - end - assert_equal :ok, assert_nothing_raised(LocalJumpError) {obj.ok} - end - def test_syntax_error_in_rescue bug12613 = '[ruby-core:76531] [Bug #12613]' assert_syntax_error("#{<<-"begin;"}\n#{<<-"end;"}", /Invalid retry/, bug12613) @@ -1640,29 +1587,6 @@ eom def test_command_with_cmd_brace_block assert_valid_syntax('obj.foo (1) {}') assert_valid_syntax('obj::foo (1) {}') - assert_valid_syntax('bar {}') - assert_valid_syntax('Bar {}') - assert_valid_syntax('bar() {}') - assert_valid_syntax('Bar() {}') - assert_valid_syntax('Foo::bar {}') - assert_valid_syntax('Foo::Bar {}') - assert_valid_syntax('Foo::bar() {}') - assert_valid_syntax('Foo::Bar() {}') - end - - def test_command_newline_in_tlparen_args - assert_valid_syntax("p (1\n2\n),(3),(4)") - assert_valid_syntax("p (\n),(),()") - assert_valid_syntax("a.b (1\n2\n),(3),(4)") - assert_valid_syntax("a.b (\n),(),()") - end - - def test_command_semicolon_in_tlparen_at_the_first_arg - bug19281 = '[ruby-core:111499] [Bug #19281]' - assert_valid_syntax('p (1;2),(3),(4)', bug19281) - assert_valid_syntax('p (;),(),()', bug19281) - assert_valid_syntax('a.b (1;2),(3),(4)', bug19281) - assert_valid_syntax('a.b (;),(),()', bug19281) end def test_numbered_parameter @@ -1708,9 +1632,6 @@ eom assert_raise(NameError) {eval("_1")}, ] } - - assert_valid_syntax("proc {def foo(_);end;_1}") - assert_valid_syntax("p { [_1 **2] }") end def test_value_expr_in_condition @@ -1758,8 +1679,6 @@ eom assert_syntax_error('def foo(...) foo[...] = x; end', /unexpected/) assert_syntax_error('def foo(...) foo(...) { }; end', /both block arg and actual block given/) assert_syntax_error('def foo(...) defined?(...); end', /unexpected/) - assert_syntax_error('def foo(*rest, ...) end', '... after rest argument') - assert_syntax_error('def foo(*, ...) end', '... after rest argument') obj1 = Object.new def obj1.bar(*args, **kws, &block) @@ -1960,21 +1879,6 @@ eom assert_equal 0...1, exp.call(a: 0) end - def test_class_module_Object_ancestors - assert_separately([], <<-RUBY) - m = Module.new - m::Bug18832 = 1 - include m - class Bug18832; end - RUBY - assert_separately([], <<-RUBY) - m = Module.new - m::Bug18832 = 1 - include m - module Bug18832; end - RUBY - end - def test_cdhash assert_separately([], <<-RUBY) n = case 1 when 2r then false else true end diff --git a/test/ruby/test_system.rb b/test/ruby/test_system.rb index 3fcdaa6aad..31c9cd7654 100644 --- a/test/ruby/test_system.rb +++ b/test/ruby/test_system.rb @@ -146,19 +146,6 @@ class TestSystem < Test::Unit::TestCase end end - def test_system_closed - assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") - begin; - ios = [] - ObjectSpace.each_object(IO) {|io| ios << io} - `echo` - ObjectSpace.each_object(IO) do |io| - next if ios.include?(io) - assert_nothing_raised {io.close} - end - end; - end - def test_empty_evstr assert_equal("", eval('"#{}"', nil, __FILE__, __LINE__), "[ruby-dev:25113]") end diff --git a/test/ruby/test_thread.rb b/test/ruby/test_thread.rb index 703373b11e..41cee124be 100644 --- a/test/ruby/test_thread.rb +++ b/test/ruby/test_thread.rb @@ -29,19 +29,13 @@ class TestThread < Test::Unit::TestCase end def test_inspect - m = Thread::Mutex.new - m.lock line = __LINE__+1 - th = Module.new {break module_eval("class C\u{30b9 30ec 30c3 30c9} < Thread; self; end")}.start do - m.synchronize {} - end - Thread.pass until th.stop? + th = Module.new {break module_eval("class C\u{30b9 30ec 30c3 30c9} < Thread; self; end")}.start{} s = th.inspect assert_include(s, "::C\u{30b9 30ec 30c3 30c9}:") assert_include(s, " #{__FILE__}:#{line} ") assert_equal(s, th.to_s) ensure - m.unlock th.join end @@ -323,7 +317,7 @@ class TestThread < Test::Unit::TestCase s += 1 end Thread.pass until t.stop? - sleep 1 if defined?(RubyVM::RJIT) && RubyVM::RJIT.enabled? # t.stop? behaves unexpectedly with --jit-wait + sleep 1 if defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? # t.stop? behaves unexpectedly with --jit-wait assert_equal(1, s) t.wakeup Thread.pass while t.alive? @@ -395,7 +389,7 @@ class TestThread < Test::Unit::TestCase end INPUT - assert_in_out_err(%w(-d), <<-INPUT, %w(false 2), %r".+") + assert_in_out_err(%w(--disable-gems -d), <<-INPUT, %w(false 2), %r".+") p Thread.abort_on_exception begin t = Thread.new { raise } @@ -506,7 +500,7 @@ class TestThread < Test::Unit::TestCase def test_ignore_deadlock if /mswin|mingw/ =~ RUBY_PLATFORM - omit "can't trap a signal from another process on Windows" + skip "can't trap a signal from another process on Windows" end assert_in_out_err([], <<-INPUT, %w(false :sig), [], :signal=>:INT, timeout: 1, timeout_error: nil) p Thread.ignore_deadlock @@ -737,7 +731,7 @@ class TestThread < Test::Unit::TestCase end def test_no_valid_cfp - omit 'with win32ole, cannot run this testcase because win32ole redefines Thread#initialize' if defined?(WIN32OLE) + skip 'with win32ole, cannot run this testcase because win32ole redefines Thread#initialize' if defined?(WIN32OLE) bug5083 = '[ruby-dev:44208]' assert_equal([], Thread.new(&Module.method(:nesting)).value, bug5083) assert_instance_of(Thread, Thread.new(:to_s, &Class.new.method(:undef_method)).join, bug5083) @@ -972,8 +966,6 @@ _eom end def test_thread_timer_and_interrupt - omit "[Bug #18613]" if /freebsd/ =~ RUBY_PLATFORM - bug5757 = '[ruby-dev:44985]' pid = nil cmd = 'Signal.trap(:INT, "DEFAULT"); pipe=IO.pipe; Thread.start {Thread.pass until Thread.main.stop?; puts; STDOUT.flush}; pipe[0].read' @@ -1076,7 +1068,7 @@ q.pop puts mth.status Process.kill(:INT, $$) } - sleep + sleep 0.1 INPUT end @@ -1263,7 +1255,6 @@ q.pop assert_predicate(status, :success?, bug18902) ensure th.kill - th.join end end if Process.respond_to?(:fork) @@ -1279,7 +1270,7 @@ q.pop end if Process.respond_to?(:fork) def test_fork_while_parent_locked - omit 'needs fork' unless Process.respond_to?(:fork) + skip 'needs fork' unless Process.respond_to?(:fork) m = Thread::Mutex.new nr = 1 thrs = [] @@ -1300,7 +1291,7 @@ q.pop end def test_fork_while_mutex_locked_by_forker - omit 'needs fork' unless Process.respond_to?(:fork) + skip 'needs fork' unless Process.respond_to?(:fork) m = Thread::Mutex.new m.synchronize do pid = fork do @@ -1361,61 +1352,6 @@ q.pop t.join end - def test_yield_across_thread_through_enum - bug18649 = '[ruby-core:107980] [Bug #18649]' - @log = [] - - def self.p(arg) - @log << arg - end - - def self.synchronize - yield - end - - def self.execute(task) - success = true - value = reason = nil - end_sync = false - - synchronize do - begin - p :before - value = task.call - p :never_reached - success = true - rescue StandardError => ex - ex = ex.class - p [:rescue, ex] - reason = ex - success = false - end - - end_sync = true - p :end_sync - end - - p :should_not_reach_here! unless end_sync - [success, value, reason] - end - - def self.foo - Thread.new do - result = execute(-> { yield 42 }) - p [:result, result] - end.join - end - - value = to_enum(:foo).first - expected = [:before, - [:rescue, LocalJumpError], - :end_sync, - [:result, [false, nil, LocalJumpError]]] - - assert_equal(expected, @log, bug18649) - assert_equal(42, value, bug18649) - end - def test_thread_setname_in_initialize bug12290 = '[ruby-core:74963] [Bug #12290]' c = Class.new(Thread) {def initialize() self.name = "foo"; super; end} @@ -1423,7 +1359,7 @@ q.pop end def test_thread_native_thread_id - omit "don't support native_thread_id" unless Thread.method_defined?(:native_thread_id) + skip "don't support native_thread_id" unless Thread.method_defined?(:native_thread_id) assert_instance_of Integer, Thread.main.native_thread_id th1 = Thread.start{sleep} @@ -1446,8 +1382,8 @@ q.pop def test_thread_interrupt_for_killed_thread opts = { timeout: 5, timeout_error: nil } - # prevent SIGABRT from slow shutdown with RJIT - opts[:reprieve] = 3 if defined?(RubyVM::RJIT) && RubyVM::RJIT.enabled? + # prevent SIGABRT from slow shutdown with MJIT + opts[:reprieve] = 3 if defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? assert_normal_exit(<<-_end, '[Bug #8996]', **opts) Thread.report_on_exception = false @@ -1462,14 +1398,9 @@ q.pop def test_signal_at_join if /mswin|mingw/ =~ RUBY_PLATFORM - omit "can't trap a signal from another process on Windows" + skip "can't trap a signal from another process on Windows" # opt = {new_pgroup: true} end - - if /freebsd/ =~ RUBY_PLATFORM - omit "[Bug #18613]" - end - assert_separately([], "#{<<~"{#"}\n#{<<~'};'}", timeout: 120) {# n = 1000 @@ -1516,12 +1447,4 @@ q.pop end }; end - - def test_pending_interrupt? - t = Thread.handle_interrupt(Exception => :never) { Thread.new { Thread.stop } } - t.raise(StandardError) - assert_equal(true, t.pending_interrupt?) - assert_equal(true, t.pending_interrupt?(Exception)) - assert_equal(false, t.pending_interrupt?(ArgumentError)) - end end diff --git a/test/ruby/test_thread_cv.rb b/test/ruby/test_thread_cv.rb index eb88b9606c..88733419da 100644 --- a/test/ruby/test_thread_cv.rb +++ b/test/ruby/test_thread_cv.rb @@ -6,6 +6,12 @@ class TestThreadConditionVariable < Test::Unit::TestCase ConditionVariable = Thread::ConditionVariable Mutex = Thread::Mutex + def test_initialized + assert_raise(TypeError) { + ConditionVariable.allocate.wait(nil) + } + end + def test_condvar_signal_and_wait mutex = Thread::Mutex.new condvar = Thread::ConditionVariable.new diff --git a/test/ruby/test_thread_queue.rb b/test/ruby/test_thread_queue.rb index fd77853f0e..3fa0eae2c1 100644 --- a/test/ruby/test_thread_queue.rb +++ b/test/ruby/test_thread_queue.rb @@ -8,13 +8,13 @@ class TestThreadQueue < Test::Unit::TestCase SizedQueue = Thread::SizedQueue def test_queue_initialized - assert_raise_with_message(TypeError, /\bQueue.* not initialized/) { + assert_raise(TypeError) { Queue.allocate.push(nil) } end def test_sized_queue_initialized - assert_raise_with_message(TypeError, /\bSizedQueue.* not initialized/) { + assert_raise(TypeError) { SizedQueue.allocate.push(nil) } end @@ -111,23 +111,6 @@ class TestThreadQueue < Test::Unit::TestCase assert_equal(0, q.num_waiting) end - def test_queue_pop_timeout - q = Thread::Queue.new - q << 1 - assert_equal 1, q.pop(timeout: 1) - - t1 = Thread.new { q.pop(timeout: 1) } - assert_equal t1, t1.join(2) - assert_nil t1.value - - t2 = Thread.new { q.pop(timeout: 0.1) } - assert_equal t2, t2.join(1) - assert_nil t2.value - ensure - t1&.kill&.join - t2&.kill&.join - end - def test_queue_pop_non_block q = Thread::Queue.new assert_raise_with_message(ThreadError, /empty/) do @@ -143,24 +126,6 @@ class TestThreadQueue < Test::Unit::TestCase assert_equal(0, q.num_waiting) end - def test_sized_queue_pop_timeout - q = Thread::SizedQueue.new(1) - - q << 1 - assert_equal 1, q.pop(timeout: 1) - - t1 = Thread.new { q.pop(timeout: 1) } - assert_equal t1, t1.join(2) - assert_nil t1.value - - t2 = Thread.new { q.pop(timeout: 0.1) } - assert_equal t2, t2.join(1) - assert_nil t2.value - ensure - t1&.kill&.join - t2&.kill&.join - end - def test_sized_queue_pop_non_block q = Thread::SizedQueue.new(1) assert_raise_with_message(ThreadError, /empty/) do @@ -168,24 +133,6 @@ class TestThreadQueue < Test::Unit::TestCase end end - def test_sized_queue_push_timeout - q = Thread::SizedQueue.new(1) - - q << 1 - assert_equal 1, q.size - - t1 = Thread.new { q.push(2, timeout: 1) } - assert_equal t1, t1.join(2) - assert_nil t1.value - - t2 = Thread.new { q.push(2, timeout: 0.1) } - assert_equal t2, t2.join(1) - assert_nil t2.value - ensure - t1&.kill&.join - t2&.kill&.join - end - def test_sized_queue_push_interrupt q = Thread::SizedQueue.new(1) q.push(1) @@ -204,18 +151,16 @@ class TestThreadQueue < Test::Unit::TestCase end def test_thr_kill - omit "[Bug #18613]" if /freebsd/ =~ RUBY_PLATFORM - bug5343 = '[ruby-core:39634]' Dir.mktmpdir {|d| - timeout = 60 + timeout = EnvUtil.apply_timeout_scale(60) total_count = 250 begin - assert_normal_exit(<<-"_eom", bug5343, timeout: timeout, chdir: d) - r, w = IO.pipe + assert_normal_exit(<<-"_eom", bug5343, **{:timeout => timeout, :chdir=>d}) #{total_count}.times do |i| - File.open("test_thr_kill_count", "w") {|f| f.puts i } + open("test_thr_kill_count", "w") {|f| f.puts i } queue = Thread::Queue.new + r, w = IO.pipe th = Thread.start { queue.push(nil) r.read 1 @@ -585,14 +530,9 @@ class TestThreadQueue < Test::Unit::TestCase count_items = rand(3000..5000) count_producers = rand(10..20) - # ensure threads do not start running too soon and complete before we check status - mutex = Mutex.new - mutex.lock - producers = count_producers.times.map do Thread.new do - mutex.lock - mutex.unlock + sleep(rand / 100) count_items.times{|i| q << [i,"#{i} for #{Thread.current.inspect}"]} end end @@ -610,11 +550,9 @@ class TestThreadQueue < Test::Unit::TestCase # No dead or finished threads, give up to 10 seconds to start running t = Time.now - Thread.pass until Time.now - t > 10 || (consumers + producers).all?{|thr| thr.status.to_s =~ /\A(?:run|sleep)\z/} - - assert (consumers + producers).all?{|thr| thr.status.to_s =~ /\A(?:run|sleep)\z/}, 'no threads running' + Thread.pass until Time.now - t > 10 || (consumers + producers).all?{|thr| thr.status =~ /\A(?:run|sleep)\z/} - mutex.unlock + assert (consumers + producers).all?{|thr| thr.status =~ /\A(?:run|sleep)\z/}, 'no threads running' # just exercising the concurrency of the support methods. counter = Thread.new do @@ -642,10 +580,10 @@ class TestThreadQueue < Test::Unit::TestCase def test_queue_with_trap if ENV['APPVEYOR'] == 'True' && RUBY_PLATFORM.match?(/mswin/) - omit 'This test fails too often on AppVeyor vs140' + skip 'This test fails too often on AppVeyor vs140' end if RUBY_PLATFORM.match?(/mingw/) - omit 'This test fails too often on MinGW' + skip 'This test fails too often on MinGW' end assert_in_out_err([], <<-INPUT, %w(INT INT exit), []) diff --git a/test/ruby/test_time.rb b/test/ruby/test_time.rb index 40b7ac79f8..36c79273db 100644 --- a/test/ruby/test_time.rb +++ b/test/ruby/test_time.rb @@ -58,101 +58,6 @@ class TestTime < Test::Unit::TestCase assert_equal([0, 0, 0, 2, 1, 2000, 0, 2, false, "UTC"], Time.new(2000, 1, 1, 24, 0, 0, "-00:00").to_a) end - def test_new_from_string - assert_raise(ArgumentError) { Time.new(2021, 1, 1, "+09:99") } - - t = Time.utc(2020, 12, 24, 15, 56, 17) - assert_equal(t, Time.new("2020-12-24T15:56:17Z")) - assert_equal(t, Time.new("2020-12-25 00:56:17 +09:00")) - assert_equal(t, Time.new("2020-12-25 00:57:47 +09:01:30")) - assert_equal(t, Time.new("2020-12-25 00:56:17 +0900")) - assert_equal(t, Time.new("2020-12-25 00:57:47 +090130")) - assert_equal(t, Time.new("2020-12-25T00:56:17+09:00")) - assert_raise_with_message(ArgumentError, /missing sec part/) { - Time.new("2020-12-25 00:56 +09:00") - } - assert_raise_with_message(ArgumentError, /missing min part/) { - Time.new("2020-12-25 00 +09:00") - } - - assert_equal(Time.new(2021), Time.new("2021")) - assert_equal(Time.new(2021, 12, 25, in: "+09:00"), Time.new("2021-12-25+09:00")) - - assert_equal(0.123456r, Time.new("2021-12-25 00:00:00.123456 +09:00").subsec) - assert_equal(0.123456789r, Time.new("2021-12-25 00:00:00.123456789876 +09:00").subsec) - assert_equal(0.123r, Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: 3).subsec) - assert_equal(0.123456789876r, Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: nil).subsec) - assert_raise_with_message(ArgumentError, "subsecond expected after dot: 00:56:17. ") { - Time.new("2020-12-25 00:56:17. +0900") - } - assert_raise_with_message(ArgumentError, /year must be 4 or more/) { - Time.new("021-12-25 00:00:00.123456 +09:00") - } - assert_raise_with_message(ArgumentError, /fraction min is.*56\./) { - Time.new("2020-12-25 00:56. +0900") - } - assert_raise_with_message(ArgumentError, /fraction hour is.*00\./) { - Time.new("2020-12-25 00. +0900") - } - assert_raise_with_message(ArgumentError, /two digits sec.*:017\b/) { - Time.new("2020-12-25 00:56:017 +0900") - } - assert_raise_with_message(ArgumentError, /two digits sec.*:9\b/) { - Time.new("2020-12-25 00:56:9 +0900") - } - assert_raise_with_message(ArgumentError, /sec out of range/) { - Time.new("2020-12-25 00:56:64 +0900") - } - assert_raise_with_message(ArgumentError, /two digits min.*:056\b/) { - Time.new("2020-12-25 00:056:17 +0900") - } - assert_raise_with_message(ArgumentError, /two digits min.*:5\b/) { - Time.new("2020-12-25 00:5:17 +0900") - } - assert_raise_with_message(ArgumentError, /min out of range/) { - Time.new("2020-12-25 00:64:17 +0900") - } - assert_raise_with_message(ArgumentError, /two digits hour.*\b000\b/) { - Time.new("2020-12-25 000:56:17 +0900") - } - assert_raise_with_message(ArgumentError, /two digits hour.*\b0\b/) { - Time.new("2020-12-25 0:56:17 +0900") - } - assert_raise_with_message(ArgumentError, /hour out of range/) { - Time.new("2020-12-25 33:56:17 +0900") - } - assert_raise_with_message(ArgumentError, /two digits mday.*\b025\b/) { - Time.new("2020-12-025 00:56:17 +0900") - } - assert_raise_with_message(ArgumentError, /two digits mday.*\b5\b/) { - Time.new("2020-12-5 00:56:17 +0900") - } - assert_raise_with_message(ArgumentError, /mday out of range/) { - Time.new("2020-12-33 00:56:17 +0900") - } - assert_raise_with_message(ArgumentError, /two digits mon.*\b012\b/) { - Time.new("2020-012-25 00:56:17 +0900") - } - assert_raise_with_message(ArgumentError, /two digits mon.*\b1\b/) { - Time.new("2020-1-25 00:56:17 +0900") - } - assert_raise_with_message(ArgumentError, /mon out of range/) { - Time.new("2020-17-25 00:56:17 +0900") - } - assert_raise_with_message(ArgumentError, /no time information/) { - Time.new("2020-12") - } - assert_raise_with_message(ArgumentError, /no time information/) { - Time.new("2020-12-02") - } - assert_raise_with_message(ArgumentError, /can't parse/) { - Time.new(" 2020-12-02 00:00:00") - } - assert_raise_with_message(ArgumentError, /can't parse/) { - Time.new("2020-12-02 00:00:00 ") - } - end - def test_time_add() assert_equal(Time.utc(2000, 3, 21, 3, 30) + 3 * 3600, Time.utc(2000, 3, 21, 6, 30)) @@ -214,7 +119,7 @@ class TestTime < Test::Unit::TestCase assert_equal(946684800, Time.utc(2000, 1, 1, 0, 0, 0).tv_sec) # Giveup to try 2nd test because some state is changed. - omit if Test::Unit::Runner.current_repeat_count > 0 + skip if Test::Unit::Runner.current_repeat_count > 0 assert_equal(0x7fffffff, Time.utc(2038, 1, 19, 3, 14, 7).tv_sec) assert_equal(0x80000000, Time.utc(2038, 1, 19, 3, 14, 8).tv_sec) @@ -438,7 +343,7 @@ class TestTime < Test::Unit::TestCase end def test_marshal_zone_gc - assert_separately([], <<-'end;', timeout: 30) + assert_separately(%w(--disable-gems), <<-'end;', timeout: 30) ENV["TZ"] = "JST-9" s = Marshal.dump(Time.now) t = Marshal.load(s) @@ -1281,7 +1186,7 @@ class TestTime < Test::Unit::TestCase def test_2038 # Giveup to try 2nd test because some state is changed. - omit if Test::Unit::Runner.current_repeat_count > 0 + skip if Test::Unit::Runner.current_repeat_count > 0 if no_leap_seconds? assert_equal(0x80000000, Time.utc(2038, 1, 19, 3, 14, 8).tv_sec) @@ -1406,38 +1311,21 @@ class TestTime < Test::Unit::TestCase def test_memsize # Time objects are common in some code, try to keep them small - omit "Time object size test" if /^(?:i.?86|x86_64)-linux/ !~ RUBY_PLATFORM - omit "GC is in debug" if GC::INTERNAL_CONSTANTS[:DEBUG] + skip "Time object size test" if /^(?:i.?86|x86_64)-linux/ !~ RUBY_PLATFORM + skip "GC is in debug" if GC::INTERNAL_CONSTANTS[:DEBUG] require 'objspace' t = Time.at(0) - sizeof_timew = - if RbConfig::SIZEOF.key?("uint64_t") && RbConfig::SIZEOF["long"] * 2 <= RbConfig::SIZEOF["uint64_t"] - RbConfig::SIZEOF["uint64_t"] - else - RbConfig::SIZEOF["void*"] # Same size as VALUE - end - sizeof_vtm = RbConfig::SIZEOF["void*"] * 4 + 8 - expect = GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE] + sizeof_timew + sizeof_vtm + size = GC::INTERNAL_CONSTANTS[:RVALUE_SIZE] + case size + when 20 then expect = 50 + when 24 then expect = 54 + when 40 then expect = 86 + when 48 then expect = 94 + else + flunk "Unsupported RVALUE_SIZE=#{size}, update test_memsize" + end assert_equal expect, ObjectSpace.memsize_of(t) rescue LoadError => e - omit "failed to load objspace: #{e.message}" - end - - def test_deconstruct_keys - t = in_timezone('JST-9') { Time.local(2022, 10, 16, 14, 1, 30, 500) } - assert_equal( - {year: 2022, month: 10, day: 16, wday: 0, yday: 289, - hour: 14, min: 1, sec: 30, subsec: 1/2000r, dst: false, zone: 'JST'}, - t.deconstruct_keys(nil) - ) - - assert_equal( - {year: 2022, month: 10, sec: 30}, - t.deconstruct_keys(%i[year month sec nonexistent]) - ) - end - - def test_parse_zero_bigint - assert_equal 0, Time.new("2020-10-28T16:48:07.000Z").nsec, '[Bug #19390]' + skip "failed to load objspace: #{e.message}" end end diff --git a/test/ruby/test_time_tz.rb b/test/ruby/test_time_tz.rb index 531d76b040..26fe680acf 100644 --- a/test/ruby/test_time_tz.rb +++ b/test/ruby/test_time_tz.rb @@ -115,7 +115,7 @@ class TestTimeTZ < Test::Unit::TestCase t = with_tz("America/Los_Angeles") { Time.local(2000, 1, 1) } - omit "force_tz_test is false on this environment" unless t + skip "force_tz_test is false on this environment" unless t z1 = t.zone z2 = with_tz(tz="Asia/Singapore") { t.localtime.zone diff --git a/test/ruby/test_transcode.rb b/test/ruby/test_transcode.rb index 24ee9b9533..c8b0034e06 100644 --- a/test/ruby/test_transcode.rb +++ b/test/ruby/test_transcode.rb @@ -2232,12 +2232,12 @@ class TestTranscode < Test::Unit::TestCase assert_equal("U+3042", "\u{3042}".encode("US-ASCII", fallback: fallback)) end - def test_pseudo_encoding_inspect - s = 'aaa'.encode "UTF-16" - assert_equal '"\xFE\xFF\x00\x61\x00\x61\x00\x61"', s.inspect - - s = 'aaa'.encode "UTF-32" - assert_equal '"\x00\x00\xFE\xFF\x00\x00\x00\x61\x00\x00\x00\x61\x00\x00\x00\x61"', s.inspect + bug8940 = '[ruby-core:57318] [Bug #8940]' + %w[UTF-32 UTF-16].each do |enc| + define_method("test_pseudo_encoding_inspect(#{enc})") do + assert_normal_exit("'aaa'.encode('#{enc}').inspect", bug8940) + assert_equal(4, 'aaa'.encode(enc).length, "should count in #{enc} with BOM") + end end def test_encode_with_invalid_chars @@ -2305,7 +2305,5 @@ class TestTranscode < Test::Unit::TestCase assert_equal("A\rB\r\rC", s.encode(usascii, newline: :cr)) assert_equal("A\r\nB\r\r\nC", s.encode(usascii, crlf_newline: true)) assert_equal("A\r\nB\r\r\nC", s.encode(usascii, newline: :crlf)) - assert_equal("A\nB\nC", s.encode(usascii, lf_newline: true)) - assert_equal("A\nB\nC", s.encode(usascii, newline: :lf)) end end diff --git a/test/ruby/test_variable.rb b/test/ruby/test_variable.rb index e50b681ce8..d425b43b0d 100644 --- a/test/ruby/test_variable.rb +++ b/test/ruby/test_variable.rb @@ -174,21 +174,6 @@ class TestVariable < Test::Unit::TestCase end end - def test_set_class_variable_on_frozen_object - set_cvar = EnvUtil.labeled_class("SetCVar") - set_cvar.class_eval "#{<<~"begin;"}\n#{<<~'end;'}" - begin; - def self.set(val) - @@a = val # inline cache - end - end; - set_cvar.set(1) # fill write cache - set_cvar.freeze - assert_raise(FrozenError, "[Bug #19341]") do - set_cvar.set(2) # hit write cache, but should check frozen status - end - end - def test_variable assert_instance_of(Integer, $$) @@ -266,84 +251,6 @@ class TestVariable < Test::Unit::TestCase assert_include(gv, :$12) end - def prepare_klass_for_test_svar_with_ifunc - Class.new do - include Enumerable - def each(&b) - @b = b - end - - def check1 - check2.merge({check1: $1}) - end - - def check2 - @b.call('foo') - {check2: $1} - end - end - end - - def test_svar_with_ifunc - c = prepare_klass_for_test_svar_with_ifunc - - expected_check1_result = { - check1: nil, check2: nil - }.freeze - - obj = c.new - result = nil - obj.grep(/(f..)/){ - result = $1 - } - assert_equal nil, result - assert_equal nil, $1 - assert_equal expected_check1_result, obj.check1 - assert_equal 'foo', result - assert_equal 'foo', $1 - - # this frame was escaped so try it again - $~ = nil - obj = c.new - result = nil - obj.grep(/(f..)/){ - result = $1 - } - assert_equal nil, result - assert_equal nil, $1 - assert_equal expected_check1_result, obj.check1 - assert_equal 'foo', result - assert_equal 'foo', $1 - - # different context - result = nil - Fiber.new{ - obj = c.new - obj.grep(/(f..)/){ - result = $1 - } - }.resume # obj is created in antoher Fiber - assert_equal nil, result - assert_equal expected_check1_result, obj.check1 - assert_equal 'foo', result - assert_equal 'foo', $1 - - # different thread context - result = nil - Thread.new{ - obj = c.new - obj.grep(/(f..)/){ - result = $1 - } - }.join # obj is created in another Thread - - assert_equal nil, result - assert_equal expected_check1_result, obj.check1 - assert_equal 'foo', result - assert_equal 'foo', $1 - end - - def test_global_variable_0 assert_in_out_err(["-e", "$0='t'*1000;print $0"], "", /\At+\z/, []) end @@ -373,12 +280,6 @@ class TestVariable < Test::Unit::TestCase v.instance_variable_set(:@foo, :bar) end - assert_raise_with_message(FrozenError, msg, "[Bug #19339]") do - v.instance_eval do - @a = 1 - end - end - assert_nil EnvUtil.suppress_warning {v.instance_variable_get(:@foo)} assert_not_send([v, :instance_variable_defined?, :@foo]) diff --git a/test/ruby/test_vm_dump.rb b/test/ruby/test_vm_dump.rb index 9c06ec14fb..679ce94b91 100644 --- a/test/ruby/test_vm_dump.rb +++ b/test/ruby/test_vm_dump.rb @@ -3,7 +3,7 @@ require 'test/unit' class TestVMDump < Test::Unit::TestCase def assert_darwin_vm_dump_works(args) - omit if RUBY_PLATFORM !~ /darwin/ + skip if RUBY_PLATFORM !~ /darwin/ assert_in_out_err(args, "", [], /^\[IMPORTANT\]/) end diff --git a/test/ruby/test_weakkeymap.rb b/test/ruby/test_weakkeymap.rb deleted file mode 100644 index be3e80cec4..0000000000 --- a/test/ruby/test_weakkeymap.rb +++ /dev/null @@ -1,140 +0,0 @@ -# frozen_string_literal: false -require 'test/unit' - -class TestWeakKeyMap < Test::Unit::TestCase - def setup - @wm = ObjectSpace::WeakKeyMap.new - end - - def test_map - x = Object.new - k = "foo" - @wm[k] = x - assert_same(x, @wm[k]) - assert_same(x, @wm["FOO".downcase]) - end - - def test_aset_const - x = Object.new - assert_raise(ArgumentError) { @wm[true] = x } - assert_raise(ArgumentError) { @wm[false] = x } - assert_raise(ArgumentError) { @wm[nil] = x } - assert_raise(ArgumentError) { @wm[42] = x } - assert_raise(ArgumentError) { @wm[2**128] = x } - assert_raise(ArgumentError) { @wm[1.23] = x } - assert_raise(ArgumentError) { @wm[:foo] = x } - assert_raise(ArgumentError) { @wm["foo#{rand}".to_sym] = x } - end - - def test_getkey - k = "foo" - @wm[k] = true - assert_same(k, @wm.getkey("FOO".downcase)) - end - - def test_key? - assert_weak_include(:key?, "foo") - assert_not_send([@wm, :key?, "bar"]) - end - - def test_delete - k1 = "foo" - x1 = Object.new - @wm[k1] = x1 - assert_equal x1, @wm[k1] - assert_equal x1, @wm.delete(k1) - assert_nil @wm[k1] - assert_nil @wm.delete(k1) - - fallback = @wm.delete(k1) do |key| - assert_equal k1, key - 42 - end - assert_equal 42, fallback - end - - def test_clear - k = "foo" - @wm[k] = true - assert @wm[k] - assert_same @wm, @wm.clear - refute @wm[k] - end - - def test_inspect - x = Object.new - k = Object.new - @wm[k] = x - assert_match(/\A\#<#{@wm.class.name}:[\dxa-f]+ size=\d+>\z/, @wm.inspect) - - 1000.times do |i| - @wm[i.to_s] = Object.new - @wm.inspect - end - assert_match(/\A\#<#{@wm.class.name}:[\dxa-f]+ size=\d+>\z/, @wm.inspect) - end - - def test_no_hash_method - k = BasicObject.new - assert_raise NoMethodError do - @wm[k] = 42 - end - end - - def test_frozen_object - o = Object.new.freeze - assert_nothing_raised(FrozenError) {@wm[o] = 'foo'} - assert_nothing_raised(FrozenError) {@wm['foo'] = o} - end - - def test_inconsistent_hash_key - assert_no_memory_leak [], '', <<~RUBY - class BadHash - def initialize - @hash = 0 - end - - def hash - @hash += 1 - end - end - - k = BadHash.new - wm = ObjectSpace::WeakKeyMap.new - - 100_000.times do |i| - wm[k] = i - end - RUBY - end - - def test_compaction - omit "compaction is not supported on this platform" unless GC.respond_to?(:compact) - - assert_separately(%w(-robjspace), <<-'end;') - wm = ObjectSpace::WeakKeyMap.new - key = Object.new - val = Object.new - wm[key] = val - - GC.verify_compaction_references(expand_heap: true, toward: :empty) - - assert_equal(val, wm[key]) - end; - end - - private - - def assert_weak_include(m, k, n = 100) - if n > 0 - return assert_weak_include(m, k, n-1) - end - 1.times do - x = Object.new - @wm[k] = x - assert_send([@wm, m, k]) - assert_send([@wm, m, "FOO".downcase]) - x = Object.new - end - end -end diff --git a/test/ruby/test_weakmap.rb b/test/ruby/test_weakmap.rb index a30004bce3..5ca6b0fbdd 100644 --- a/test/ruby/test_weakmap.rb +++ b/test/ruby/test_weakmap.rb @@ -59,7 +59,7 @@ class TestWeakMap < Test::Unit::TestCase assert_weak_include(m, k) end GC.start - pend('TODO: failure introduced from 837fd5e494731d7d44786f29e7d6e8c27029806f') + skip('TODO: failure introduced from r60440') assert_not_send([@wm, m, k]) end alias test_member? test_include? @@ -82,22 +82,6 @@ class TestWeakMap < Test::Unit::TestCase @wm.inspect) end - def test_delete - k1 = "foo" - x1 = Object.new - @wm[k1] = x1 - assert_equal x1, @wm[k1] - assert_equal x1, @wm.delete(k1) - assert_nil @wm[k1] - assert_nil @wm.delete(k1) - - fallback = @wm.delete(k1) do |key| - assert_equal k1, key - 42 - end - assert_equal 42, fallback - end - def test_each m = __callee__[/test_(.*)/, 1] x1 = Object.new @@ -193,17 +177,14 @@ class TestWeakMap < Test::Unit::TestCase end; end - def test_compaction - omit "compaction is not supported on this platform" unless GC.respond_to?(:compact) - - # [Bug #19529] + def test_compaction_bug_19529 obj = Object.new 100.times do |i| GC.compact @wm[i] = obj end - assert_separately([], <<-'end;') + assert_separately(%w(--disable-gems), <<-'end;') wm = ObjectSpace::WeakMap.new obj = Object.new 100.times do @@ -212,45 +193,5 @@ class TestWeakMap < Test::Unit::TestCase end GC.compact end; - - assert_separately(%w(-robjspace), <<-'end;') - wm = ObjectSpace::WeakMap.new - key = Object.new - val = Object.new - wm[key] = val - - GC.verify_compaction_references(expand_heap: true, toward: :empty) - - assert_equal(val, wm[key]) - end; - - assert_separately(["-W0"], <<-'end;') - wm = ObjectSpace::WeakMap.new - - ary = 10_000.times.map do - o = Object.new - wm[o] = 1 - o - end - - GC.verify_compaction_references(expand_heap: true, toward: :empty) - end; - end - - def test_replaced_values_bug_19531 - a = "A".dup - b = "B".dup - - @wm[1] = a - @wm[1] = a - @wm[1] = a - - @wm[1] = b - assert_equal b, @wm[1] - - a = nil - GC.start - - assert_equal b, @wm[1] end end diff --git a/test/ruby/test_yjit.rb b/test/ruby/test_yjit.rb index cc9507aff4..48b3e4acea 100644 --- a/test/ruby/test_yjit.rb +++ b/test/ruby/test_yjit.rb @@ -1,25 +1,17 @@ # frozen_string_literal: true -# -# This set of tests can be run with: -# make test-all TESTS='test/ruby/test_yjit.rb' - require 'test/unit' require 'envutil' require 'tmpdir' -require_relative '../lib/jit_support' -return unless JITSupport.yjit_supported? +return unless defined?(RubyVM::YJIT) && RubyVM::YJIT.enabled? # Tests for YJIT with assertions on compilation and side exits -# insipired by the RJIT tests in test/ruby/test_rjit.rb +# insipired by the MJIT tests in test/ruby/test_jit.rb class TestYJIT < Test::Unit::TestCase - running_with_yjit = defined?(RubyVM::YJIT) && RubyVM::YJIT.enabled? - def test_yjit_in_ruby_description assert_includes(RUBY_DESCRIPTION, '+YJIT') - end if running_with_yjit + end - # Check that YJIT is in the version string def test_yjit_in_version [ %w(--version --yjit), @@ -29,49 +21,29 @@ class TestYJIT < Test::Unit::TestCase %w(--version --disable=yjit --yjit), %w(--version --disable=yjit --enable-yjit), %w(--version --disable=yjit --enable=yjit), - %w(--version --jit), - %w(--version --disable-jit --jit), - %w(--version --disable-jit --enable-jit), - %w(--version --disable-jit --enable=jit), - %w(--version --disable=jit --yjit), - %w(--version --disable=jit --enable-jit), - %w(--version --disable=jit --enable=jit), + *([ + %w(--version --jit), + %w(--version --disable-jit --jit), + %w(--version --disable-jit --enable-jit), + %w(--version --disable-jit --enable=jit), + %w(--version --disable=jit --yjit), + %w(--version --disable=jit --enable-jit), + %w(--version --disable=jit --enable=jit), + ] if RUBY_PLATFORM.start_with?('x86_64-') && RUBY_PLATFORM !~ /mswin|mingw|msys/), ].each do |version_args| assert_in_out_err(version_args) do |stdout, stderr| assert_equal(RUBY_DESCRIPTION, stdout.first) assert_equal([], stderr) end end - end if running_with_yjit + end def test_command_line_switches assert_in_out_err('--yjit-', '', [], /invalid option --yjit-/) assert_in_out_err('--yjithello', '', [], /invalid option --yjithello/) - #assert_in_out_err('--yjit-call-threshold', '', [], /--yjit-call-threshold needs an argument/) - #assert_in_out_err('--yjit-call-threshold=', '', [], /--yjit-call-threshold needs an argument/) - end - - def test_starting_paused - program = <<~RUBY - def not_compiled = nil - def will_compile = nil - def compiled_counts = RubyVM::YJIT.runtime_stats[:compiled_iseq_count] - counts = [] - not_compiled - counts << compiled_counts - - RubyVM::YJIT.resume - - will_compile - counts << compiled_counts - - if counts[0] == 0 && counts[1] > 0 - p :ok - end - RUBY - assert_in_out_err(%w[--yjit-pause --yjit-stats --yjit-call-threshold=1], program, success: true) do |stdout, stderr| - assert_equal([":ok"], stdout) - end + assert_in_out_err('--yjit-call-threshold', '', [], /--yjit-call-threshold needs an argument/) + assert_in_out_err('--yjit-call-threshold=', '', [], /--yjit-call-threshold needs an argument/) + assert_in_out_err('--yjit-greedy-versioning=1', '', [], /warning: argument to --yjit-greedy-versioning is ignored/) end def test_yjit_stats_and_v_no_error @@ -87,7 +59,7 @@ class TestYJIT < Test::Unit::TestCase end assert_in_out_err([yjit_child_env, '-e puts RUBY_DESCRIPTION'], '', [RUBY_DESCRIPTION]) assert_in_out_err([yjit_child_env, '-e p RubyVM::YJIT.enabled?'], '', ['true']) - end if running_with_yjit + end def test_compile_setclassvariable script = 'class Foo; def self.foo; @@foo = 1; end; end; Foo.foo' @@ -109,10 +81,6 @@ class TestYJIT < Test::Unit::TestCase assert_compiles(':foo', insns: %i[putobject], result: :foo) end - def test_compile_opt_succ - assert_compiles('1.succ', insns: %i[opt_succ], result: 2) - end - def test_compile_opt_not assert_compiles('!false', insns: %i[opt_not], result: true) assert_compiles('!nil', insns: %i[opt_not], result: true) @@ -343,32 +311,6 @@ class TestYJIT < Test::Unit::TestCase RUBY end - def test_string_concat_utf8 - assert_compiles(<<~RUBY, frozen_string_literal: true, result: true) - def str_cat_utf8 - s = String.new - 10.times { s << "✅" } - s - end - - str_cat_utf8 == "✅" * 10 - RUBY - end - - def test_string_concat_ascii - # Constant-get for classes (e.g. String, Encoding) can cause a side-exit in getinlinecache. For now, ignore exits. - assert_compiles(<<~RUBY, exits: :any) - str_arg = "b".encode(Encoding::ASCII) - def str_cat_ascii(arg) - s = String.new(encoding: Encoding::ASCII) - 10.times { s << arg } - s - end - - str_cat_ascii(str_arg) == str_arg * 10 - RUBY - end - def test_opt_length_in_method assert_compiles(<<~RUBY, insns: %i[opt_length], result: 5) def foo(str) @@ -412,31 +354,8 @@ class TestYJIT < Test::Unit::TestCase assert_compiles("'foo' =~ /(o)./; $2", insns: %i[getspecial], result: nil) end - def test_compile_getconstant - assert_compiles(<<~RUBY, insns: %i[getconstant], result: [], call_threshold: 1) - def get_argv(klass) - klass::ARGV - end - - get_argv(Object) - RUBY - end - - def test_compile_getconstant_with_sp_offset - assert_compiles(<<~RUBY, insns: %i[getconstant], result: 2, call_threshold: 1) - class Foo - Bar = 1 - end - - 2.times do - s = Foo # this opt_getconstant_path needs warmup, so 2.times is needed - Class.new(Foo).const_set(:Bar, s::Bar) - end - RUBY - end - - def test_compile_opt_getconstant_path - assert_compiles(<<~RUBY, insns: %i[opt_getconstant_path], result: 123, call_threshold: 2) + def test_compile_opt_getinlinecache + assert_compiles(<<~RUBY, insns: %i[opt_getinlinecache], result: 123, min_calls: 2) def get_foo FOO end @@ -448,8 +367,8 @@ class TestYJIT < Test::Unit::TestCase RUBY end - def test_opt_getconstant_path_slowpath - assert_compiles(<<~RUBY, exits: { opt_getconstant_path: 1 }, result: [42, 42, 1, 1], call_threshold: 2) + def test_opt_getinlinecache_slowpath + assert_compiles(<<~RUBY, exits: { opt_getinlinecache: 1 }, result: [42, 42, 1, 1], min_calls: 2) class A FOO = 42 class << self @@ -477,7 +396,7 @@ class TestYJIT < Test::Unit::TestCase end def test_string_interpolation - assert_compiles(<<~'RUBY', insns: %i[objtostring anytostring concatstrings], result: "foobar", call_threshold: 2) + assert_compiles(<<~'RUBY', insns: %i[objtostring anytostring concatstrings], result: "foobar", min_calls: 2) def make_str(foo, bar) "#{foo}#{bar}" end @@ -533,249 +452,6 @@ class TestYJIT < Test::Unit::TestCase RUBY end - def test_getblockparam - assert_compiles(<<~'RUBY', insns: [:getblockparam]) - def foo &blk - 2.times do - blk - end - end - - foo {} - foo {} - RUBY - end - - def test_getblockparamproxy - assert_compiles(<<~'RUBY', insns: [:getblockparamproxy], exits: {}) - def foo &blk - p blk.call - p blk.call - end - - foo { 1 } - foo { 2 } - RUBY - end - - def test_ifunc_getblockparamproxy - assert_compiles(<<~'RUBY', insns: [:getblockparamproxy], exits: {}) - class Foo - include Enumerable - - def each(&block) - block.call 1 - block.call 2 - block.call 3 - end - end - - foo = Foo.new - foo.map { _1 * 2 } - foo.map { _1 * 2 } - RUBY - end - - def test_send_blockarg - assert_compiles(<<~'RUBY', insns: [:getblockparamproxy, :send], exits: {}) - def bar - end - - def foo &blk - bar(&blk) - bar(&blk) - end - - foo - foo - - foo { } - foo { } - RUBY - end - - def test_send_splat - assert_compiles(<<~'RUBY', result: "3#1,2,3/P", exits: {}) - def internal_method(*args) - "#{args.size}##{args.join(",")}" - end - - def jit_method - send(:internal_method, *[1, 2, 3]) + "/P" - end - - jit_method - RUBY - end - - def test_send_multiarg - assert_compiles(<<~'RUBY', result: "3#1,2,3/Q") - def internal_method(*args) - "#{args.size}##{args.join(",")}" - end - - def jit_method - send(:internal_method, 1, 2, 3) + "/Q" - end - - jit_method - RUBY - end - - def test_send_kwargs - # For now, this side-exits when calls include keyword args - assert_compiles(<<~'RUBY', result: "2#a:1,b:2/A") - def internal_method(**kw) - "#{kw.size}##{kw.keys.map { |k| "#{k}:#{kw[k]}" }.join(",")}" - end - - def jit_method - send(:internal_method, a: 1, b: 2) + "/A" - end - jit_method - RUBY - end - - def test_send_kwargs_in_receiver_only - assert_compiles(<<~'RUBY', result: "0/RK", exits: {}) - def internal_method(**kw) - "#{kw.size}" - end - - def jit_method - send(:internal_method) + "/RK" - end - jit_method - RUBY - end - - def test_send_with_underscores - assert_compiles(<<~'RUBY', result: "0/RK", exits: {}) - def internal_method(**kw) - "#{kw.size}" - end - - def jit_method - __send__(:internal_method) + "/RK" - end - jit_method - RUBY - end - - def test_send_kwargs_splat - # For now, this side-exits when calling with a splat - assert_compiles(<<~'RUBY', result: "2#a:1,b:2/B") - def internal_method(**kw) - "#{kw.size}##{kw.keys.map { |k| "#{k}:#{kw[k]}" }.join(",")}" - end - - def jit_method - send(:internal_method, **{ a: 1, b: 2 }) + "/B" - end - jit_method - RUBY - end - - def test_send_block - # Setlocal_wc_0 sometimes side-exits on write barrier - assert_compiles(<<~'RUBY', result: "b:n/b:y/b:y/b:n") - def internal_method(&b) - "b:#{block_given? ? "y" : "n"}" - end - - def jit_method - b7 = proc { 7 } - [ - send(:internal_method), - send(:internal_method, &b7), - send(:internal_method) { 7 }, - send(:internal_method, &nil), - ].join("/") - end - jit_method - RUBY - end - - def test_send_block_calling - assert_compiles(<<~'RUBY', result: "1a2", exits: {}) - def internal_method - out = yield - "1" + out + "2" - end - - def jit_method - __send__(:internal_method) { "a" } - end - jit_method - RUBY - end - - def test_send_block_only_receiver - assert_compiles(<<~'RUBY', result: "b:n", exits: {}) - def internal_method(&b) - "b:#{block_given? ? "y" : "n"}" - end - - def jit_method - send(:internal_method) - end - jit_method - RUBY - end - - def test_send_block_only_sender - assert_compiles(<<~'RUBY', result: "Y/Y/Y/Y", exits: {}) - def internal_method - "Y" - end - - def jit_method - b7 = proc { 7 } - [ - send(:internal_method), - send(:internal_method, &b7), - send(:internal_method) { 7 }, - send(:internal_method, &nil), - ].join("/") - end - jit_method - RUBY - end - - def test_multisend - assert_compiles(<<~'RUBY', result: "77") - def internal_method - "7" - end - - def jit_method - send(:send, :internal_method) + send(:send, :send, :internal_method) - end - jit_method - RUBY - end - - def test_getivar_opt_plus - assert_no_exits(<<~RUBY) - class TheClass - def initialize - @levar = 1 - end - - def get_sum - sum = 0 - # The type of levar is unknown, - # but this still should not exit - sum += @levar - sum - end - end - - obj = TheClass.new - obj.get_sum - RUBY - end - def test_super_iseq assert_compiles(<<~'RUBY', insns: %i[invokesuper opt_plus opt_mult], result: 15) class A @@ -794,25 +470,6 @@ class TestYJIT < Test::Unit::TestCase RUBY end - def test_super_with_alias - assert_compiles(<<~'RUBY', insns: %i[invokesuper opt_plus opt_mult], result: 15) - class A - def foo = 1 + 2 - end - - module M - def foo = super() * 5 - alias bar foo - - def foo = :bad - end - - A.prepend M - - A.new.bar - RUBY - end - def test_super_cfunc assert_compiles(<<~'RUBY', insns: %i[invokesuper], result: "Hello") class Gnirts < String @@ -831,7 +488,7 @@ class TestYJIT < Test::Unit::TestCase # Tests calling a variadic cfunc with many args def test_build_large_struct - assert_compiles(<<~RUBY, insns: %i[opt_send_without_block], call_threshold: 2) + assert_compiles(<<~RUBY, insns: %i[opt_send_without_block], min_calls: 2) ::Foo = Struct.new(:a, :b, :c, :d, :e, :f, :g, :h) def build_foo @@ -865,15 +522,8 @@ class TestYJIT < Test::Unit::TestCase RUBY end - def test_cfunc_kwarg - assert_no_exits('{}.store(:value, foo: 123)') - assert_no_exits('{}.store(:value, foo: 123, bar: 456, baz: 789)') - assert_no_exits('{}.merge(foo: 123)') - assert_no_exits('{}.merge(foo: 123, bar: 456, baz: 789)') - end - - # regression test simplified from URI::Generic#hostname= def test_ctx_different_mappings + # regression test simplified from URI::Generic#hostname= assert_compiles(<<~'RUBY', frozen_string_literal: true) def foo(v) !(v&.start_with?('[')) && v&.index(':') @@ -909,468 +559,12 @@ class TestYJIT < Test::Unit::TestCase RUBY end - def test_int_equal - assert_compiles(<<~'RUBY', exits: :any, result: [true, false, true, false, true, false, true, false]) - def eq(a, b) - a == b - end - - def eqq(a, b) - a === b - end - - big1 = 2 ** 65 - big2 = big1 + 1 - [eq(1, 1), eq(1, 2), eq(big1, big1), eq(big1, big2), eqq(1, 1), eqq(1, 2), eqq(big1, big1), eqq(big1, big2)] - RUBY - end - - def test_opt_case_dispatch - assert_compiles(<<~'RUBY', exits: :any, result: [:"1", "2", 3]) - def case_dispatch(val) - case val - when 1 - :"#{val}" - when 2 - "#{val}" - else - val - end - end - - [case_dispatch(1), case_dispatch(2), case_dispatch(3)] - RUBY - end - - def test_code_gc - assert_compiles(code_gc_helpers + <<~'RUBY', exits: :any, result: :ok) - return :not_paged unless add_pages(100) # prepare freeable pages - RubyVM::YJIT.code_gc # first code GC - return :not_compiled1 unless compiles { nil } # should be JITable again - - RubyVM::YJIT.code_gc # second code GC - return :not_compiled2 unless compiles { nil } # should be JITable again - - code_gc_count = RubyVM::YJIT.runtime_stats[:code_gc_count] - return :"code_gc_#{code_gc_count}" if code_gc_count != 2 - - :ok - RUBY - end - - def test_on_stack_code_gc_call - assert_compiles(code_gc_helpers + <<~'RUBY', exits: :any, result: :ok) - fiber = Fiber.new { - # Loop to call the same basic block again after Fiber.yield - while true - Fiber.yield(nil.to_i) - end - } - - return :not_paged1 unless add_pages(400) # go to a page without initial ocb code - return :broken_resume1 if fiber.resume != 0 # JIT the fiber - RubyVM::YJIT.code_gc # first code GC, which should not free the fiber page - return :broken_resume2 if fiber.resume != 0 # The code should be still callable - - code_gc_count = RubyVM::YJIT.runtime_stats[:code_gc_count] - return :"code_gc_#{code_gc_count}" if code_gc_count != 1 - - :ok - RUBY - end - - def test_on_stack_code_gc_twice - assert_compiles(code_gc_helpers + <<~'RUBY', exits: :any, result: :ok) - fiber = Fiber.new { - # Loop to call the same basic block again after Fiber.yield - while Fiber.yield(nil.to_i); end - } - - return :not_paged1 unless add_pages(400) # go to a page without initial ocb code - return :broken_resume1 if fiber.resume(true) != 0 # JIT the fiber - RubyVM::YJIT.code_gc # first code GC, which should not free the fiber page - - return :not_paged2 unless add_pages(300) # add some stuff to be freed - # Not calling fiber.resume here to test the case that the YJIT payload loses some - # information at the previous code GC. The payload should still be there, and - # thus we could know the fiber ISEQ is still on stack on this second code GC. - RubyVM::YJIT.code_gc # second code GC, which should still not free the fiber page - - return :not_paged3 unless add_pages(200) # attempt to overwrite the fiber page (it shouldn't) - return :broken_resume2 if fiber.resume(true) != 0 # The fiber code should be still fine - - return :broken_resume3 if fiber.resume(false) != nil # terminate the fiber - RubyVM::YJIT.code_gc # third code GC, freeing a page that used to be on stack - - return :not_paged4 unless add_pages(100) # check everything still works - - code_gc_count = RubyVM::YJIT.runtime_stats[:code_gc_count] - return :"code_gc_#{code_gc_count}" if code_gc_count != 3 - - :ok - RUBY - end - - def test_code_gc_with_many_iseqs - assert_compiles(code_gc_helpers + <<~'RUBY', exits: :any, result: :ok, mem_size: 1) - fiber = Fiber.new { - # Loop to call the same basic block again after Fiber.yield - while true - Fiber.yield(nil.to_i) - end - } - - return :not_paged1 unless add_pages(250) # use some pages - return :broken_resume1 if fiber.resume != 0 # leave an on-stack code as well - - add_pages(2000) # use a whole lot of pages to run out of 1MiB - return :broken_resume2 if fiber.resume != 0 # on-stack code should be callable - - code_gc_count = RubyVM::YJIT.runtime_stats[:code_gc_count] - return :"code_gc_#{code_gc_count}" if code_gc_count == 0 - - :ok - RUBY - end - - def test_code_gc_partial_last_page - # call_threshold: 2 to avoid JIT-ing code_gc itself. If code_gc were JITed right before - # code_gc is called, the last page would be on stack. - assert_compiles(<<~'RUBY', exits: :any, result: :ok, call_threshold: 2) - # Leave a bunch of off-stack pages - i = 0 - while i < 1000 - eval("x = proc { 1.to_s }; x.call; x.call") - i += 1 - end - - # On Linux, memory page size != code page size. So the last code page could be partially - # mapped. This call tests that assertions and other things work fine under the situation. - RubyVM::YJIT.code_gc - - :ok - RUBY - end - - def test_trace_script_compiled # not ISEQ_TRACE_EVENTS - assert_compiles(<<~'RUBY', exits: :any, result: :ok) - @eval_counter = 0 - def eval_script - eval('@eval_counter += 1') - end - - @trace_counter = 0 - trace = TracePoint.new(:script_compiled) do |t| - @trace_counter += 1 - end - - eval_script # JIT without TracePoint - trace.enable - eval_script # call with TracePoint - trace.disable - - return :"eval_#{@eval_counter}" if @eval_counter != 2 - return :"trace_#{@trace_counter}" if @trace_counter != 1 - - :ok - RUBY - end - - def test_trace_b_call # ISEQ_TRACE_EVENTS - assert_compiles(<<~'RUBY', exits: :any, result: :ok) - @call_counter = 0 - def block_call - 1.times { @call_counter += 1 } - end - - @trace_counter = 0 - trace = TracePoint.new(:b_call) do |t| - @trace_counter += 1 - end - - block_call # JIT without TracePoint - trace.enable - block_call # call with TracePoint - trace.disable - - return :"call_#{@call_counter}" if @call_counter != 2 - return :"trace_#{@trace_counter}" if @trace_counter != 1 - - :ok - RUBY - end - - def test_send_to_call - assert_compiles(<<~'RUBY', result: :ok) - ->{ :ok }.send(:call) - RUBY - end - - def test_invokeblock_many_locals - # [Bug #19299] - assert_compiles(<<~'RUBY', result: :ok) - def foo - yield - end - - foo do - a1=a2=a3=a4=a5=a6=a7=a8=a9=a10=a11=a12=a13=a14=a15=a16=a17=a18=a19=a20=a21=a22=a23=a24=a25=a26=a27=a28=a29=a30 = :ok - a30 - end - RUBY - end - - def test_bug_19316 - n = 2 ** 64 - # foo's extra param and the splats are relevant - assert_compiles(<<~'RUBY', result: [[n, -n], [n, -n]]) - def foo(_, a, b, c) - [a & b, ~c] - end - - n = 2 ** 64 - args = [0, -n, n, n-1] - - GC.stress = true - [foo(*args), foo(*args)] - RUBY - end - - def test_gc_compact_cyclic_branch - assert_compiles(<<~'RUBY', result: 2) - def foo - i = 0 - while i < 2 - i += 1 - end - i - end - - foo - GC.compact - foo - RUBY - end - - def test_invalidate_cyclic_branch - assert_compiles(<<~'RUBY', result: 2) - def foo - i = 0 - while i < 2 - i += 1 - end - i - end - - foo - class Integer - def +(x) = self - -x - end - foo - RUBY - end - - def test_tracing_str_uplus - assert_compiles(<<~RUBY, frozen_string_literal: true, result: :ok) - def str_uplus - _ = 1 - _ = 2 - ret = [+"frfr", __LINE__] - _ = 3 - _ = 4 - - ret - end - - str_uplus - require 'objspace' - ObjectSpace.trace_object_allocations_start - - str, expected_line = str_uplus - alloc_line = ObjectSpace.allocation_sourceline(str) - - if expected_line == alloc_line - :ok - else - [expected_line, alloc_line] - end - RUBY - end - - def test_str_uplus_subclass - assert_compiles(<<~RUBY, frozen_string_literal: true, result: :subclass) - class S < String - def encoding - :subclass - end - end - - def test(str) - (+str).encoding - end - - test "" - test S.new - RUBY - end - - def test_return_to_invalidated_block - # [Bug #19463] - assert_compiles(<<~RUBY, result: [1, 1, :ugokanai]) - klass = Class.new do - def self.lookup(hash, key) = hash[key] - - def self.foo(a, b) = [] - - def self.test(hash, key) - [lookup(hash, key), key, "".freeze] - # 05 opt_send_without_block :lookup - # 07 getlocal_WC_0 :hash - # 09 opt_str_freeze "" - # 12 newarray 3 - # 14 leave - # - # YJIT will put instructions (07..14) into a block. - # When String#freeze is redefined from within lookup(), - # the return address to the block is still on-stack. We rely - # on invalidation patching the code at the return address - # to service this situation correctly. - end - end - - # get YJIT to compile test() - hash = { 1 => [] } - 31.times { klass.test(hash, 1) } - - # inject invalidation into lookup() - evil_hash = Hash.new do |_, key| - class String - undef :freeze - def freeze = :ugokanai - end - - key - end - klass.test(evil_hash, 1) - RUBY - end - - def test_setivar_on_class - # Bug in https://github.com/ruby/ruby/pull/8152 - assert_compiles(<<~RUBY, result: :ok) - class Base - def self.or_equal - @or_equal ||= Object.new - end - end - - Base.or_equal # ensure compiled - - class Child < Base - end - - 200.times do |iv| # Need to be more than MAX_IVAR - Child.instance_variable_set("@_iv_\#{iv}", Object.new) - end - - Child.or_equal - :ok - RUBY - end - - def test_nested_send - #[Bug #19464] - assert_compiles(<<~RUBY, result: [:ok, :ok]) - klass = Class.new do - class << self - alias_method :my_send, :send - - def bar = :ok - - def foo = bar - end - end - - with_break = -> { break klass.send(:my_send, :foo) } - wo_break = -> { klass.send(:my_send, :foo) } - - [with_break[], wo_break[]] - RUBY - end - - def test_str_concat_encoding_mismatch - assert_compiles(<<~'RUBY', result: "incompatible character encodings: ASCII-8BIT and EUC-JP") - def bar(a, b) - a << b - rescue => e - e.message - end - - def foo(a, b, h) - h[nil] - bar(a, b) # Ruby call, not set cfp->pc - end - - h = Hash.new { nil } - foo("\x80".b, "\xA1A1".force_encoding("EUC-JP"), h) - foo("\x80".b, "\xA1A1".force_encoding("EUC-JP"), h) - RUBY - end - - def test_io_reopen_clobbering_singleton_class - assert_compiles(<<~RUBY, result: [:ok, :ok]) - def $stderr.to_i = :i - - def test = $stderr.to_i - - [test, test] - $stderr.reopen($stderr.dup) - [test, test].map { :ok unless _1 == :i } - RUBY - end - - def test_opt_aref_with - assert_compiles(<<~RUBY, insns: %i[opt_aref_with], result: "bar") - h = {"foo" => "bar"} - - h["foo"] - RUBY - end - - def test_proc_block_arg - assert_compiles(<<~RUBY, result: [:proc, :no_block]) - def yield_if_given = block_given? ? yield : :no_block - - def call(block_arg = nil) = yield_if_given(&block_arg) - - [call(-> { :proc }), call] - RUBY - end - - private - - def code_gc_helpers - <<~'RUBY' - def compiles(&block) - failures = RubyVM::YJIT.runtime_stats[:compilation_failure] - block.call - failures == RubyVM::YJIT.runtime_stats[:compilation_failure] - end - - def add_pages(num_jits) - pages = RubyVM::YJIT.runtime_stats[:compiled_page_count] - num_jits.times { return false unless eval('compiles { nil.to_i }') } - pages.nil? || pages < RubyVM::YJIT.runtime_stats[:compiled_page_count] - end - RUBY - end - def assert_no_exits(script) assert_compiles(script) end ANY = Object.new - def assert_compiles(test_script, insns: [], call_threshold: 1, stdout: nil, exits: {}, result: ANY, frozen_string_literal: nil, mem_size: nil) + def assert_compiles(test_script, insns: [], min_calls: 1, stdout: nil, exits: {}, result: ANY, frozen_string_literal: nil) reset_stats = <<~RUBY RubyVM::YJIT.runtime_stats RubyVM::YJIT.reset_stats! @@ -1379,17 +573,29 @@ class TestYJIT < Test::Unit::TestCase write_results = <<~RUBY stats = RubyVM::YJIT.runtime_stats - def collect_insns(iseq) - insns = RubyVM::YJIT.insns_compiled(iseq) - iseq.each_child { |c| insns.concat collect_insns(c) } - insns + def collect_blocks(blocks) + blocks.sort_by(&:address).map { |b| [b.iseq_start_index, b.iseq_end_index] } + end + + def collect_iseqs(iseq) + iseq_array = iseq.to_a + insns = iseq_array.last.grep(Array) + blocks = RubyVM::YJIT.blocks_for(iseq) + h = { + name: iseq_array[5], + insns: insns, + blocks: collect_blocks(blocks), + } + arr = [h] + iseq.each_child { |c| arr.concat collect_iseqs(c) } + arr end iseq = RubyVM::InstructionSequence.of(_test_proc) IO.open(3).write Marshal.dump({ result: #{result == ANY ? "nil" : "result"}, stats: stats, - insns: collect_insns(iseq), + iseqs: collect_iseqs(iseq), disasm: iseq.disasm }) RUBY @@ -1404,7 +610,7 @@ class TestYJIT < Test::Unit::TestCase #{write_results} RUBY - status, out, err, stats = eval_with_jit(script, call_threshold:, mem_size:) + status, out, err, stats = eval_with_jit(script, min_calls: min_calls) assert status.success?, "exited with status #{status.to_i}, stderr:\n#{err}" @@ -1415,76 +621,83 @@ class TestYJIT < Test::Unit::TestCase end runtime_stats = stats[:stats] - insns_compiled = stats[:insns] + iseqs = stats[:iseqs] disasm = stats[:disasm] - # Check that exit counts are as expected - # Full stats are only available when --enable-yjit=dev + # Only available when RUBY_DEBUG enabled if runtime_stats[:all_stats] recorded_exits = runtime_stats.select { |k, v| k.to_s.start_with?("exit_") } recorded_exits = recorded_exits.reject { |k, v| v == 0 } recorded_exits.transform_keys! { |k| k.to_s.gsub("exit_", "").to_sym } - # Exits can be specified as a hash of stat-name symbol to integer for exact exits. - # or stat-name symbol to range if the number of side exits might vary (e.g. write - # barriers, cache misses.) - if exits != :any && - exits != recorded_exits && - !exits.all? { |k, v| v === recorded_exits[k] } # triple-equal checks range membership or integer equality + if exits != :any && exits != recorded_exits flunk "Expected #{exits.empty? ? "no" : exits.inspect} exits" \ ", but got\n#{recorded_exits.inspect}" end end - # Only available when --enable-yjit=dev + # Only available when RUBY_DEBUG enabled if runtime_stats[:all_stats] missed_insns = insns.dup + all_compiled_blocks = {} + iseqs.each do |iseq| + compiled_blocks = iseq[:blocks].map { |from, to| (from...to) } + all_compiled_blocks[iseq[:name]] = compiled_blocks + compiled_insns = iseq[:insns] + next_idx = 0 + compiled_insns.map! do |insn| + # TODO: not sure this is accurate for determining insn size + idx = next_idx + next_idx += insn.length + [idx, *insn] + end + + compiled_insns.each do |idx, op, *arguments| + next unless missed_insns.include?(op) + next unless compiled_blocks.any? { |block| block === idx } - insns_compiled.each do |op| - if missed_insns.include?(op) # This instruction was compiled missed_insns.delete(op) end end unless missed_insns.empty? - flunk "Expected to compile instructions #{missed_insns.join(", ")} but didn't.\niseq:\n#{disasm}" + flunk "Expected to compile instructions #{missed_insns.join(", ")} but didn't.\nCompiled ranges: #{all_compiled_blocks.inspect}\niseq:\n#{disasm}" end end end - def script_shell_encode(s) - # We can't pass utf-8-encoded characters directly in a shell arg. But we can use Ruby \u constants. - s.chars.map { |c| c.ascii_only? ? c : "\\u%x" % c.codepoints[0] }.join - end - - def eval_with_jit(script, call_threshold: 1, timeout: 1000, mem_size: nil) + def eval_with_jit(script, min_calls: 1, timeout: 1000) args = [ "--disable-gems", - "--yjit-call-threshold=#{call_threshold}", + "--yjit-call-threshold=#{min_calls}", "--yjit-stats" ] - args << "--yjit-exec-mem-size=#{mem_size}" if mem_size - args << "-e" << script_shell_encode(script) + args << "-e" << script stats_r, stats_w = IO.pipe - # Separate thread so we don't deadlock when - # the child ruby blocks writing the stats to fd 3 - stats = '' - stats_reader = Thread.new do - stats = stats_r.read - stats_r.close - end out, err, status = EnvUtil.invoke_ruby(args, '', true, true, timeout: timeout, ios: {3 => stats_w} ) stats_w.close - stats_reader.join(timeout) + stats = stats_r.read stats = Marshal.load(stats) if !stats.empty? + stats_r.close [status, out, err, stats] - ensure - stats_reader&.kill - stats_reader&.join(timeout) - stats_r&.close - stats_w&.close + end + + def test_bug_19316 + n = 2 ** 64 + # foo's extra param and the splats are relevant + assert_compiles(<<~'RUBY', result: [[n, -n], [n, -n]], exits: :any) + def foo(_, a, b, c) + [a & b, ~c] + end + + n = 2 ** 64 + args = [0, -n, n, n-1] + + GC.stress = true + [foo(*args), foo(*args)] + RUBY end end diff --git a/test/ruby/test_yjit_exit_locations.rb b/test/ruby/test_yjit_exit_locations.rb deleted file mode 100644 index 851a582470..0000000000 --- a/test/ruby/test_yjit_exit_locations.rb +++ /dev/null @@ -1,110 +0,0 @@ -# frozen_string_literal: true -# -# This set of tests can be run with: -# make test-all TESTS='test/ruby/test_yjit_exit_locations.rb' - -require 'test/unit' -require 'envutil' -require 'tmpdir' -require_relative '../lib/jit_support' - -return unless JITSupport.yjit_supported? - -# Tests for YJIT with assertions on tracing exits -# insipired by the RJIT tests in test/ruby/test_yjit.rb -class TestYJITExitLocations < Test::Unit::TestCase - def test_yjit_trace_exits_and_v_no_error - _stdout, stderr, _status = EnvUtil.invoke_ruby(%w(-v --yjit-trace-exits), '', true, true) - refute_includes(stderr, "NoMethodError") - end - - def test_trace_exits_setclassvariable - script = 'class Foo; def self.foo; @@foo = 1; end; end; Foo.foo' - assert_exit_locations(script) - end - - def test_trace_exits_putobject - assert_exit_locations('true') - assert_exit_locations('123') - assert_exit_locations(':foo') - end - - def test_trace_exits_opt_not - assert_exit_locations('!false') - assert_exit_locations('!nil') - assert_exit_locations('!true') - assert_exit_locations('![]') - end - - private - - def assert_exit_locations(test_script) - write_results = <<~RUBY - IO.open(3).write Marshal.dump({ - enabled: RubyVM::YJIT.trace_exit_locations_enabled?, - exit_locations: RubyVM::YJIT.exit_locations - }) - RUBY - - script = <<~RUBY - _test_proc = -> { - #{test_script} - } - result = _test_proc.call - #{write_results} - RUBY - - run_script = eval_with_jit(script) - # If stats are disabled when configuring, --yjit-exit-locations - # can't be true. We don't want to check if exit_locations hash - # is not empty because that could indicate a bug in the exit - # locations collection. - return unless run_script[:enabled] - exit_locations = run_script[:exit_locations] - - assert exit_locations.key?(:raw) - assert exit_locations.key?(:frames) - assert exit_locations.key?(:lines) - assert exit_locations.key?(:samples) - assert exit_locations.key?(:missed_samples) - assert exit_locations.key?(:gc_samples) - - assert_equal 0, exit_locations[:missed_samples] - assert_equal 0, exit_locations[:gc_samples] - - assert_not_empty exit_locations[:raw] - assert_not_empty exit_locations[:frames] - assert_not_empty exit_locations[:lines] - - exit_locations[:frames].each do |frame_id, frame| - assert frame.key?(:name) - assert frame.key?(:file) - assert frame.key?(:samples) - assert frame.key?(:total_samples) - assert frame.key?(:edges) - end - end - - def eval_with_jit(script) - args = [ - "--disable-gems", - "--yjit-call-threshold=1", - "--yjit-trace-exits" - ] - args << "-e" << script_shell_encode(script) - stats_r, stats_w = IO.pipe - _out, _err, _status = EnvUtil.invoke_ruby(args, - '', true, true, timeout: 1000, ios: { 3 => stats_w } - ) - stats_w.close - stats = stats_r.read - stats = Marshal.load(stats) if !stats.empty? - stats_r.close - stats - end - - def script_shell_encode(s) - # We can't pass utf-8-encoded characters directly in a shell arg. But we can use Ruby \u constants. - s.chars.map { |c| c.ascii_only? ? c : "\\u%x" % c.codepoints[0] }.join - end -end |
