diff options
Diffstat (limited to 'test/ruby')
103 files changed, 3926 insertions, 15545 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 fbf780d6c3..0000000000 --- a/test/ruby/rjit/test_assembler.rb +++ /dev/null @@ -1,368 +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([:rbx, 8], 0x100) # CMP r/m64, imm32 (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 [rbx + 8], 0x100 - 0x18: cmp qword ptr [rax + 0x100], 8 - 0x20: cmp rax, 8 - 0x24: cmp rax, 0x100 - 0x2b: cmp qword ptr [rax + 8], rbx - 0x2f: cmp qword ptr [rax - 0x100], rbx - 0x36: 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 97e2fa3de8..0ed8ada95c 100644 --- a/test/ruby/test_array.rb +++ b/test/ruby/test_array.rb @@ -529,19 +529,14 @@ class TestArray < Test::Unit::TestCase end def test_assoc - def (a4 = Object.new).to_ary - %w( pork porcine ) - end - a1 = @cls[*%w( cat feline )] a2 = @cls[*%w( dog canine )] a3 = @cls[*%w( mule asinine )] - a = @cls[ a1, a2, a3, a4 ] + a = @cls[ a1, a2, a3 ] assert_equal(a1, a.assoc('cat')) assert_equal(a3, a.assoc('mule')) - assert_equal(%w( pork porcine ), a.assoc("pork")) assert_equal(nil, a.assoc('asinine')) assert_equal(nil, a.assoc('wombat')) assert_equal(nil, a.assoc(1..2)) @@ -1334,17 +1329,13 @@ class TestArray < Test::Unit::TestCase end def test_rassoc - def (a4 = Object.new).to_ary - %w( pork porcine ) - end a1 = @cls[*%w( cat feline )] a2 = @cls[*%w( dog canine )] a3 = @cls[*%w( mule asinine )] - a = @cls[ a1, a2, a3, a4 ] + a = @cls[ a1, a2, a3 ] assert_equal(a1, a.rassoc('feline')) assert_equal(a3, a.rassoc('asinine')) - assert_equal(%w( pork porcine ), a.rassoc("porcine")) assert_equal(nil, a.rassoc('dog')) assert_equal(nil, a.rassoc('mule')) assert_equal(nil, a.rassoc(1..2)) @@ -1454,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) @@ -1595,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 @@ -1702,14 +1595,6 @@ class TestArray < Test::Unit::TestCase assert_equal([100], a.slice(-1, 1_000_000_000)) end - def test_slice_gc_compact_stress - EnvUtil.under_gc_compact_stress { assert_equal([1, 2, 3, 4, 5], (0..10).to_a[1, 5]) } - EnvUtil.under_gc_compact_stress do - a = [0, 1, 2, 3, 4, 5] - assert_equal([2, 1, 0], a.slice((2..).step(-1))) - end - end - def test_slice! a = @cls[1, 2, 3, 4, 5] assert_equal(3, a.slice!(2)) @@ -3003,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([]) @@ -3015,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 @@ -3030,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) } @@ -3050,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| @@ -3069,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 @@ -3084,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| @@ -3135,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 @@ -3150,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) } @@ -3415,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 234c7af219..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,147 +185,6 @@ class TestAst < Test::Unit::TestCase end end - def assert_parse(code, warning: '') - node = assert_warning(warning) {RubyVM::AbstractSyntaxTree.parse(code)} - assert_kind_of(RubyVM::AbstractSyntaxTree::Node, node, code) - end - - def assert_invalid_parse(msg, code) - assert_raise_with_message(SyntaxError, msg, code) do - RubyVM::AbstractSyntaxTree.parse(code) - end - end - - def test_invalid_exit - [ - "break", - "break true", - "next", - "next true", - "redo", - ].each do |code, *args| - msg = /Invalid #{code[/\A\w+/]}/ - assert_parse("while false; #{code}; end") - assert_parse("until true; #{code}; end") - assert_parse("begin #{code}; end while false") - assert_parse("begin #{code}; end until true") - assert_parse("->{#{code}}") - assert_parse("->{class X; #{code}; end}") - assert_invalid_parse(msg, "#{code}") - assert_invalid_parse(msg, "def m; #{code}; end") - assert_invalid_parse(msg, "begin; #{code}; end") - assert_parse("END {#{code}}") - - assert_parse("!defined?(#{code})") - assert_parse("def m; defined?(#{code}); end") - assert_parse("!begin; defined?(#{code}); end") - - next if code.include?(" ") - assert_parse("!defined? #{code}") - assert_parse("def m; defined? #{code}; end") - assert_parse("!begin; defined? #{code}; end") - end - end - - def test_invalid_retry - msg = /Invalid retry/ - assert_invalid_parse(msg, "retry") - assert_invalid_parse(msg, "def m; retry; end") - assert_invalid_parse(msg, "begin retry; end") - assert_parse("begin rescue; retry; end") - assert_invalid_parse(msg, "begin rescue; else; retry; end") - assert_invalid_parse(msg, "begin rescue; ensure; retry; end") - assert_parse("nil rescue retry") - assert_invalid_parse(msg, "END {retry}") - assert_invalid_parse(msg, "begin rescue; END {retry}; end") - - assert_parse("!defined?(retry)") - assert_parse("def m; defined?(retry); end") - assert_parse("!begin defined?(retry); end") - assert_parse("begin rescue; else; defined?(retry); end") - assert_parse("begin rescue; ensure; defined?(retry); end") - assert_parse("END {defined?(retry)}") - assert_parse("begin rescue; END {defined?(retry)}; end") - assert_parse("!defined? retry") - - assert_parse("def m; defined? retry; end") - assert_parse("!begin defined? retry; end") - assert_parse("begin rescue; else; defined? retry; end") - assert_parse("begin rescue; ensure; defined? retry; end") - assert_parse("END {defined? retry}") - assert_parse("begin rescue; END {defined? retry}; end") - - assert_parse("#{<<-"begin;"}\n#{<<-'end;'}") - begin; - def foo - begin - yield - rescue StandardError => e - begin - puts "hi" - retry - rescue - retry unless e - raise e - else - retry - ensure - retry - end - end - end - end; - end - - def test_invalid_yield - msg = /Invalid yield/ - assert_invalid_parse(msg, "yield") - assert_invalid_parse(msg, "class C; yield; end") - assert_invalid_parse(msg, "BEGIN {yield}") - assert_invalid_parse(msg, "END {yield}") - assert_invalid_parse(msg, "-> {yield}") - - assert_invalid_parse(msg, "yield true") - assert_invalid_parse(msg, "class C; yield true; end") - assert_invalid_parse(msg, "BEGIN {yield true}") - assert_invalid_parse(msg, "END {yield true}") - assert_invalid_parse(msg, "-> {yield true}") - - assert_parse("!defined?(yield)") - assert_parse("class C; defined?(yield); end") - assert_parse("BEGIN {defined?(yield)}") - assert_parse("END {defined?(yield)}") - - assert_parse("!defined?(yield true)") - assert_parse("class C; defined?(yield true); end") - assert_parse("BEGIN {defined?(yield true)}") - assert_parse("END {defined?(yield true)}") - - assert_parse("!defined? yield") - assert_parse("class C; defined? yield; end") - assert_parse("BEGIN {defined? yield}") - assert_parse("END {defined? yield}") - 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__) @@ -425,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 @@ -474,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 @@ -617,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") @@ -649,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 @@ -746,45 +538,7 @@ dummy assert_equal("def test_keep_script_lines_for_of\n", node_method.source.lines.first) end - def test_source_with_multibyte_characters - ast = RubyVM::AbstractSyntaxTree.parse(%{a("\u00a7");b("\u00a9")}, keep_script_lines: true) - a_fcall, b_fcall = ast.children[2].children - - assert_equal(%{a("\u00a7")}, a_fcall.source) - assert_equal(%{b("\u00a9")}, b_fcall.source) - 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) @@ -795,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 1eb3551e57..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 @@ -274,11 +271,6 @@ p Foo::Bar end def test_bug_13526 - # Skip this on macOS 10.13 because of the following error: - # http://rubyci.s3.amazonaws.com/osx1013/ruby-master/log/20231011T014505Z.fail.html.gz - require "rbconfig" - omit if RbConfig::CONFIG["target_os"] == "darwin17" - script = File.join(__dir__, 'bug-13526.rb') assert_ruby_status([script], '', '[ruby-core:81016] [Bug #13526]') end @@ -469,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; @@ -505,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)) @@ -535,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 09146efa41..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,207 +92,6 @@ class TestCall < Test::Unit::TestCase } end - def test_frozen_splat_and_keywords - a = [1, 2].freeze - def self.f(*a); a end - assert_equal([1, 2, {kw: 3}], f(*a, kw: 3)) - 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_op_asgn_keywords - h = Class.new do - attr_reader :get, :set - def v; yield; [*@get, *@set] end - def [](*a, **b, &c) @get = [a, b, c]; @set = []; 3 end - def []=(*a, **b, &c) @set = [a, b, c] end - end.new - - a = [] - kw = {} - b = lambda{} - - # +=, without block, non-popped - assert_equal([[], {}, nil, [4], {}, nil], h.v{h[**kw] += 1}) - assert_equal([[0], {}, nil, [0, 4], {}, nil], h.v{h[0, **kw] += 1}) - assert_equal([[0], {}, nil, [0, 4], {}, nil], h.v{h[0, *a, **kw] += 1}) - assert_equal([[], {kw: 5}, nil, [4], {kw: 5}, nil], h.v{h[kw: 5] += 1}) - assert_equal([[], {kw: 5, a: 2}, nil, [4], {kw: 5, a: 2}, nil], h.v{h[kw: 5, a: 2] += 1}) - assert_equal([[], {kw: 5, a: 2}, nil, [4], {kw: 5, a: 2}, nil], h.v{h[kw: 5, a: 2] += 1}) - assert_equal([[0], {kw: 5, a: 2}, nil, [0, 4], {kw: 5, a: 2}, nil], h.v{h[0, kw: 5, a: 2] += 1}) - assert_equal([[0], {kw: 5, a: 2, nil: 3}, nil, [0, 4], {kw: 5, a: 2, nil: 3}, nil], h.v{h[0, *a, kw: 5, a: 2, nil: 3] += 1}) - - # +=, with block, non-popped - assert_equal([[], {}, b, [4], {}, b], h.v{h[**kw, &b] += 1}) - assert_equal([[0], {}, b, [0, 4], {}, b], h.v{h[0, **kw, &b] += 1}) - assert_equal([[0], {}, b, [0, 4], {}, b], h.v{h[0, *a, **kw, &b] += 1}) - assert_equal([[], {kw: 5}, b, [4], {kw: 5}, b], h.v{h[kw: 5, &b] += 1}) - assert_equal([[], {kw: 5, a: 2}, b, [4], {kw: 5, a: 2}, b], h.v{h[kw: 5, a: 2, &b] += 1}) - assert_equal([[], {kw: 5, a: 2}, b, [4], {kw: 5, a: 2}, b], h.v{h[kw: 5, a: 2, &b] += 1}) - assert_equal([[0], {kw: 5, a: 2}, b, [0, 4], {kw: 5, a: 2}, b], h.v{h[0, kw: 5, a: 2, &b] += 1}) - assert_equal([[0], {kw: 5, a: 2, b: 3}, b, [0, 4], {kw: 5, a: 2, b: 3}, b], h.v{h[0, *a, kw: 5, a: 2, b: 3, &b] += 1}) - - # +=, without block, popped - assert_equal([[], {}, nil, [4], {}, nil], h.v{h[**kw] += 1; nil}) - assert_equal([[0], {}, nil, [0, 4], {}, nil], h.v{h[0, **kw] += 1; nil}) - assert_equal([[0], {}, nil, [0, 4], {}, nil], h.v{h[0, *a, **kw] += 1; nil}) - assert_equal([[], {kw: 5}, nil, [4], {kw: 5}, nil], h.v{h[kw: 5] += 1; nil}) - assert_equal([[], {kw: 5, a: 2}, nil, [4], {kw: 5, a: 2}, nil], h.v{h[kw: 5, a: 2] += 1; nil}) - assert_equal([[], {kw: 5, a: 2}, nil, [4], {kw: 5, a: 2}, nil], h.v{h[kw: 5, a: 2] += 1; nil}) - assert_equal([[0], {kw: 5, a: 2}, nil, [0, 4], {kw: 5, a: 2}, nil], h.v{h[0, kw: 5, a: 2] += 1; nil}) - assert_equal([[0], {kw: 5, a: 2, nil: 3}, nil, [0, 4], {kw: 5, a: 2, nil: 3}, nil], h.v{h[0, *a, kw: 5, a: 2, nil: 3] += 1; nil}) - - # +=, with block, popped - assert_equal([[], {}, b, [4], {}, b], h.v{h[**kw, &b] += 1; nil}) - assert_equal([[0], {}, b, [0, 4], {}, b], h.v{h[0, **kw, &b] += 1; nil}) - assert_equal([[0], {}, b, [0, 4], {}, b], h.v{h[0, *a, **kw, &b] += 1; nil}) - assert_equal([[], {kw: 5}, b, [4], {kw: 5}, b], h.v{h[kw: 5, &b] += 1; nil}) - assert_equal([[], {kw: 5, a: 2}, b, [4], {kw: 5, a: 2}, b], h.v{h[kw: 5, a: 2, &b] += 1; nil}) - assert_equal([[], {kw: 5, a: 2}, b, [4], {kw: 5, a: 2}, b], h.v{h[kw: 5, a: 2, &b] += 1; nil}) - assert_equal([[0], {kw: 5, a: 2}, b, [0, 4], {kw: 5, a: 2}, b], h.v{h[0, kw: 5, a: 2, &b] += 1; nil}) - assert_equal([[0], {kw: 5, a: 2, b: 3}, b, [0, 4], {kw: 5, a: 2, b: 3}, b], h.v{h[0, *a, kw: 5, a: 2, b: 3, &b] += 1; nil}) - - # &&=, without block, non-popped - assert_equal([[], {}, nil, [1], {}, nil], h.v{h[**kw] &&= 1}) - assert_equal([[0], {}, nil, [0, 1], {}, nil], h.v{h[0, **kw] &&= 1}) - assert_equal([[0], {}, nil, [0, 1], {}, nil], h.v{h[0, *a, **kw] &&= 1}) - assert_equal([[], {kw: 5}, nil, [1], {kw: 5}, nil], h.v{h[kw: 5] &&= 1}) - assert_equal([[], {kw: 5, a: 2}, nil, [1], {kw: 5, a: 2}, nil], h.v{h[kw: 5, a: 2] &&= 1}) - assert_equal([[], {kw: 5, a: 2}, nil, [1], {kw: 5, a: 2}, nil], h.v{h[kw: 5, a: 2] &&= 1}) - assert_equal([[0], {kw: 5, a: 2}, nil, [0, 1], {kw: 5, a: 2}, nil], h.v{h[0, kw: 5, a: 2] &&= 1}) - assert_equal([[0], {kw: 5, a: 2, nil: 3}, nil, [0, 1], {kw: 5, a: 2, nil: 3}, nil], h.v{h[0, *a, kw: 5, a: 2, nil: 3] &&= 1}) - - # &&=, with block, non-popped - assert_equal([[], {}, b, [1], {}, b], h.v{h[**kw, &b] &&= 1}) - assert_equal([[0], {}, b, [0, 1], {}, b], h.v{h[0, **kw, &b] &&= 1}) - assert_equal([[0], {}, b, [0, 1], {}, b], h.v{h[0, *a, **kw, &b] &&= 1}) - assert_equal([[], {kw: 5}, b, [1], {kw: 5}, b], h.v{h[kw: 5, &b] &&= 1}) - assert_equal([[], {kw: 5, a: 2}, b, [1], {kw: 5, a: 2}, b], h.v{h[kw: 5, a: 2, &b] &&= 1}) - assert_equal([[], {kw: 5, a: 2}, b, [1], {kw: 5, a: 2}, b], h.v{h[kw: 5, a: 2, &b] &&= 1}) - assert_equal([[0], {kw: 5, a: 2}, b, [0, 1], {kw: 5, a: 2}, b], h.v{h[0, kw: 5, a: 2, &b] &&= 1}) - assert_equal([[0], {kw: 5, a: 2, b: 3}, b, [0, 1], {kw: 5, a: 2, b: 3}, b], h.v{h[0, *a, kw: 5, a: 2, b: 3, &b] &&= 1}) - - # &&=, without block, popped - assert_equal([[], {}, nil, [1], {}, nil], h.v{h[**kw] &&= 1; nil}) - assert_equal([[0], {}, nil, [0, 1], {}, nil], h.v{h[0, **kw] &&= 1; nil}) - assert_equal([[0], {}, nil, [0, 1], {}, nil], h.v{h[0, *a, **kw] &&= 1; nil}) - assert_equal([[], {kw: 5}, nil, [1], {kw: 5}, nil], h.v{h[kw: 5] &&= 1; nil}) - assert_equal([[], {kw: 5, a: 2}, nil, [1], {kw: 5, a: 2}, nil], h.v{h[kw: 5, a: 2] &&= 1; nil}) - assert_equal([[], {kw: 5, a: 2}, nil, [1], {kw: 5, a: 2}, nil], h.v{h[kw: 5, a: 2] &&= 1; nil}) - assert_equal([[0], {kw: 5, a: 2}, nil, [0, 1], {kw: 5, a: 2}, nil], h.v{h[0, kw: 5, a: 2] &&= 1; nil}) - assert_equal([[0], {kw: 5, a: 2, nil: 3}, nil, [0, 1], {kw: 5, a: 2, nil: 3}, nil], h.v{h[0, *a, kw: 5, a: 2, nil: 3] &&= 1; nil}) - - # &&=, with block, popped - assert_equal([[], {}, b, [1], {}, b], h.v{h[**kw, &b] &&= 1; nil}) - assert_equal([[0], {}, b, [0, 1], {}, b], h.v{h[0, **kw, &b] &&= 1; nil}) - assert_equal([[0], {}, b, [0, 1], {}, b], h.v{h[0, *a, **kw, &b] &&= 1; nil}) - assert_equal([[], {kw: 5}, b, [1], {kw: 5}, b], h.v{h[kw: 5, &b] &&= 1; nil}) - assert_equal([[], {kw: 5, a: 2}, b, [1], {kw: 5, a: 2}, b], h.v{h[kw: 5, a: 2, &b] &&= 1; nil}) - assert_equal([[], {kw: 5, a: 2}, b, [1], {kw: 5, a: 2}, b], h.v{h[kw: 5, a: 2, &b] &&= 1; nil}) - assert_equal([[0], {kw: 5, a: 2}, b, [0, 1], {kw: 5, a: 2}, b], h.v{h[0, kw: 5, a: 2, &b] &&= 1; nil}) - assert_equal([[0], {kw: 5, a: 2, b: 3}, b, [0, 1], {kw: 5, a: 2, b: 3}, b], h.v{h[0, *a, kw: 5, a: 2, b: 3, &b] &&= 1; nil}) - - # ||=, without block, non-popped - assert_equal([[], {}, nil], h.v{h[**kw] ||= 1}) - assert_equal([[0], {}, nil], h.v{h[0, **kw] ||= 1}) - assert_equal([[0], {}, nil], h.v{h[0, *a, **kw] ||= 1}) - assert_equal([[], {kw: 5}, nil], h.v{h[kw: 5] ||= 1}) - assert_equal([[], {kw: 5, a: 2}, nil], h.v{h[kw: 5, a: 2] ||= 1}) - assert_equal([[], {kw: 5, a: 2}, nil], h.v{h[kw: 5, a: 2] ||= 1}) - assert_equal([[0], {kw: 5, a: 2}, nil], h.v{h[0, kw: 5, a: 2] ||= 1}) - assert_equal([[0], {kw: 5, a: 2, nil: 3}, nil], h.v{h[0, *a, kw: 5, a: 2, nil: 3] ||= 1}) - - # ||=, with block, non-popped - assert_equal([[], {}, b], h.v{h[**kw, &b] ||= 1}) - assert_equal([[0], {}, b], h.v{h[0, **kw, &b] ||= 1}) - assert_equal([[0], {}, b], h.v{h[0, *a, **kw, &b] ||= 1}) - assert_equal([[], {kw: 5}, b], h.v{h[kw: 5, &b] ||= 1}) - assert_equal([[], {kw: 5, a: 2}, b], h.v{h[kw: 5, a: 2, &b] ||= 1}) - assert_equal([[], {kw: 5, a: 2}, b], h.v{h[kw: 5, a: 2, &b] ||= 1}) - assert_equal([[0], {kw: 5, a: 2}, b], h.v{h[0, kw: 5, a: 2, &b] ||= 1}) - assert_equal([[0], {kw: 5, a: 2, b: 3}, b], h.v{h[0, *a, kw: 5, a: 2, b: 3, &b] ||= 1}) - - # ||=, without block, popped - assert_equal([[], {}, nil], h.v{h[**kw] ||= 1; nil}) - assert_equal([[0], {}, nil], h.v{h[0, **kw] ||= 1; nil}) - assert_equal([[0], {}, nil], h.v{h[0, *a, **kw] ||= 1; nil}) - assert_equal([[], {kw: 5}, nil], h.v{h[kw: 5] ||= 1; nil}) - assert_equal([[], {kw: 5, a: 2}, nil], h.v{h[kw: 5, a: 2] ||= 1; nil}) - assert_equal([[], {kw: 5, a: 2}, nil], h.v{h[kw: 5, a: 2] ||= 1; nil}) - assert_equal([[0], {kw: 5, a: 2}, nil], h.v{h[0, kw: 5, a: 2] ||= 1; nil}) - assert_equal([[0], {kw: 5, a: 2, nil: 3}, nil], h.v{h[0, *a, kw: 5, a: 2, nil: 3] ||= 1; nil}) - - # ||=, with block, popped - assert_equal([[], {}, b], h.v{h[**kw, &b] ||= 1; nil}) - assert_equal([[0], {}, b], h.v{h[0, **kw, &b] ||= 1; nil}) - assert_equal([[0], {}, b], h.v{h[0, *a, **kw, &b] ||= 1; nil}) - assert_equal([[], {kw: 5}, b], h.v{h[kw: 5, &b] ||= 1; nil}) - assert_equal([[], {kw: 5, a: 2}, b], h.v{h[kw: 5, a: 2, &b] ||= 1; nil}) - assert_equal([[], {kw: 5, a: 2}, b], h.v{h[kw: 5, a: 2, &b] ||= 1; nil}) - assert_equal([[0], {kw: 5, a: 2}, b], h.v{h[0, kw: 5, a: 2, &b] ||= 1; nil}) - assert_equal([[0], {kw: 5, a: 2, b: 3}, b], h.v{h[0, *a, kw: 5, a: 2, b: 3, &b] ||= 1; nil}) - - end - - def test_kwsplat_block_order_op_asgn - o = Object.new - ary = [] - o.define_singleton_method(:to_a) {ary << :to_a; []} - o.define_singleton_method(:to_hash) {ary << :to_hash; {}} - o.define_singleton_method(:to_proc) {ary << :to_proc; lambda{}} - - def o.[](...) 2 end - def o.[]=(...) end - - o[kw: 1] += 1 - assert_equal([], ary) - - o[**o] += 1 - assert_equal([:to_hash], ary) - - ary.clear - o[**o, &o] += 1 - # to_proc called twice because no VM instruction for coercing to proc - assert_equal([:to_hash, :to_proc, :to_proc], ary) - - ary.clear - o[*o, **o, &o] += 1 - assert_equal([:to_a, :to_hash, :to_proc, :to_proc], ary) - end - - def test_call_op_asgn_keywords_mutable - h = Class.new do - attr_reader :get, :set - def v; yield; [*@get, *@set] end - def [](*a, **b) - @get = [a.dup, b.dup] - a << :splat_modified - b[:kw_splat_modified] = true - @set = [] - 3 - end - def []=(*a, **b) @set = [a, b] end - end.new - - a = [] - kw = {} - - assert_equal([[2], {b: 5}, [2, 4], {b: 5}], h.v{h[*a, 2, b: 5, **kw] += 1}) - end - def test_call_splat_order bug12860 = '[ruby-core:77701] [Bug# 12860]' ary = [1, 2] @@ -317,1014 +108,4 @@ class TestCall < Test::Unit::TestCase ary = [1, 2, b] assert_equal([0, 1, 2, b], aaa(0, *ary, &ary.pop), bug16504) end - - def test_call_args_splat_with_nonhash_keyword_splat - o = Object.new - def o.to_hash; {a: 1} end - def self.f(*a, **kw) - kw - end - assert_equal Hash, f(*[], **o).class - end - - def test_kwsplat_block_order - o = Object.new - ary = [] - o.define_singleton_method(:to_a) {ary << :to_a; []} - o.define_singleton_method(:to_hash) {ary << :to_hash; {}} - o.define_singleton_method(:to_proc) {ary << :to_proc; lambda{}} - - def self.t(...) end - - t(**o, &o) - assert_equal([:to_hash, :to_proc], ary) - - ary.clear - t(*o, **o, &o) - assert_equal([:to_a, :to_hash, :to_proc], ary) - end - - def test_kwsplat_block_order_super - def self.t(splat) - o = Object.new - ary = [] - o.define_singleton_method(:to_a) {ary << :to_a; []} - o.define_singleton_method(:to_hash) {ary << :to_hash; {}} - o.define_singleton_method(:to_proc) {ary << :to_proc; lambda{}} - if splat - super(*o, **o, &o) - else - super(**o, &o) - end - ary - end - extend Module.new{def t(...) end} - - assert_equal([:to_hash, :to_proc], t(false)) - assert_equal([:to_a, :to_hash, :to_proc], t(true)) - 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 775c9ed848..321feb07c7 100644 --- a/test/ruby/test_clone.rb +++ b/test/ruby/test_clone.rb @@ -27,59 +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_proc_obj_id_flag_reset - # [Bug #20250] - proc = Proc.new { } - proc.object_id - proc.clone.object_id # Would crash with RUBY_DEBUG=1 - end - def test_user_flags assert_separately([], <<-EOS) # diff --git a/test/ruby/test_comparable.rb b/test/ruby/test_comparable.rb index b689469d9e..b849217b7d 100644 --- a/test/ruby/test_comparable.rb +++ b/test/ruby/test_comparable.rb @@ -85,13 +85,7 @@ class TestComparable < Test::Unit::TestCase assert_equal(1, @o.clamp(1, 1)) assert_equal(@o, @o.clamp(0, 0)) - assert_equal(@o, @o.clamp(nil, 2)) - assert_equal(-2, @o.clamp(nil, -2)) - assert_equal(@o, @o.clamp(-2, nil)) - assert_equal(2, @o.clamp(2, nil)) - assert_equal(@o, @o.clamp(nil, nil)) - - 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 @@ -121,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_compile_prism.rb b/test/ruby/test_compile_prism.rb deleted file mode 100644 index 5482a1529d..0000000000 --- a/test/ruby/test_compile_prism.rb +++ /dev/null @@ -1,2110 +0,0 @@ -# frozen_string_literal: true - -# This file is organized to match itemization in https://github.com/ruby/prism/issues/1335 -module Prism - class TestCompilePrism < Test::Unit::TestCase - # Subclass is used for tests which need it - class Subclass; end - ############################################################################ - # Literals # - ############################################################################ - - def test_FalseNode - assert_prism_eval("false") - end - - def test_FloatNode - assert_prism_eval("1.2") - assert_prism_eval("1.2e3") - assert_prism_eval("+1.2e+3") - assert_prism_eval("-1.2e-3") - end - - def test_ImaginaryNode - assert_prism_eval("1i") - assert_prism_eval("+1.0i") - assert_prism_eval("1ri") - end - - def test_IntegerNode - assert_prism_eval("1") - assert_prism_eval("+1") - assert_prism_eval("-1") - assert_prism_eval("0x10") - assert_prism_eval("0b10") - assert_prism_eval("0o10") - assert_prism_eval("010") - assert_prism_eval("(0o00)") - end - - def test_NilNode - assert_prism_eval("nil") - end - - def test_RationalNode - assert_prism_eval("1.2r") - assert_prism_eval("+1.2r") - end - - def test_SelfNode - assert_prism_eval("self") - end - - def test_SourceEncodingNode - assert_prism_eval("__ENCODING__") - end - - def test_SourceFileNode - assert_prism_eval("__FILE__") - end - - def test_SourceLineNode - ruby_eval = RubyVM::InstructionSequence.compile("__LINE__").eval - prism_eval = RubyVM::InstructionSequence.compile_prism("__LINE__").eval - - assert_equal ruby_eval, prism_eval - end - - def test_TrueNode - assert_prism_eval("true") - end - - ############################################################################ - # Reads # - ############################################################################ - - def test_BackReferenceReadNode - assert_prism_eval("$+") - end - - def test_ClassVariableReadNode - assert_prism_eval("class Prism::TestCompilePrism; @@pit = 1; @@pit; end") - end - - def test_ConstantPathNode - assert_prism_eval("Prism::TestCompilePrism") - end - - def test_ConstantReadNode - assert_prism_eval("Prism") - end - - Z = 1 - - def test_DefinedNode - assert_prism_eval("defined? nil") - assert_prism_eval("defined? self") - assert_prism_eval("defined? true") - assert_prism_eval("defined? false") - assert_prism_eval("defined? 1") - assert_prism_eval("defined? 1i") - assert_prism_eval("defined? 1.0") - assert_prism_eval("defined? 1..2") - assert_prism_eval("defined? [A, B, C]") - assert_prism_eval("defined? [1, 2, 3]") - assert_prism_eval("defined?({ a: 1 })") - assert_prism_eval("defined? 'str'") - assert_prism_eval('defined?("#{expr}")') - assert_prism_eval("defined? :sym") - assert_prism_eval("defined? /foo/") - assert_prism_eval('defined?(/#{1}/)') - assert_prism_eval("defined? -> { 1 + 1 }") - assert_prism_eval("defined? a && b") - assert_prism_eval("defined? a || b") - assert_prism_eval("defined? __ENCODING__") - assert_prism_eval("defined? __FILE__") - assert_prism_eval("defined? __LINE__") - - assert_prism_eval("defined? %[1,2,3]") - assert_prism_eval("defined? %q[1,2,3]") - assert_prism_eval("defined? %Q[1,2,3]") - assert_prism_eval("defined? %r[1,2,3]") - assert_prism_eval("defined? %i[1,2,3]") - assert_prism_eval("defined? %I[1,2,3]") - assert_prism_eval("defined? %w[1,2,3]") - assert_prism_eval("defined? %W[1,2,3]") - assert_prism_eval("defined? %s[1,2,3]") - assert_prism_eval("defined? %x[1,2,3]") - - assert_prism_eval("defined? [*b]") - assert_prism_eval("defined? [[*1..2], 3, *4..5]") - assert_prism_eval("defined? [a: [:b, :c]]") - assert_prism_eval("defined? 1 in 1") - - assert_prism_eval("defined? @a") - assert_prism_eval("defined? $a") - assert_prism_eval("defined? @@a") - assert_prism_eval("defined? A") - assert_prism_eval("defined? ::A") - assert_prism_eval("defined? A::B") - assert_prism_eval("defined? A::B::C") - assert_prism_eval("defined? #{self.class.name}::Z::A") - assert_prism_eval("defined? yield") - assert_prism_eval("defined? super") - - assert_prism_eval("defined? X = 1") - assert_prism_eval("defined? X *= 1") - assert_prism_eval("defined? X /= 1") - assert_prism_eval("defined? X &= 1") - assert_prism_eval("defined? X ||= 1") - - assert_prism_eval("defined? $1") - assert_prism_eval("defined? $2") - assert_prism_eval("defined? $`") - assert_prism_eval("defined? $'") - assert_prism_eval("defined? $+") - - assert_prism_eval("defined? $X = 1") - assert_prism_eval("defined? $X *= 1") - assert_prism_eval("defined? $X /= 1") - assert_prism_eval("defined? $X &= 1") - assert_prism_eval("defined? $X ||= 1") - - assert_prism_eval("defined? @@X = 1") - assert_prism_eval("defined? @@X *= 1") - assert_prism_eval("defined? @@X /= 1") - assert_prism_eval("defined? @@X &= 1") - assert_prism_eval("defined? @@X ||= 1") - - assert_prism_eval("defined? @X = 1") - assert_prism_eval("defined? @X *= 1") - assert_prism_eval("defined? @X /= 1") - assert_prism_eval("defined? @X &= 1") - assert_prism_eval("defined? @X ||= 1") - - assert_prism_eval("x = 1; defined? x = 1") - assert_prism_eval("x = 1; defined? x *= 1") - assert_prism_eval("x = 1; defined? x /= 1") - assert_prism_eval("x = 1; defined? x &= 1") - assert_prism_eval("x = 1; defined? x ||= 1") - - assert_prism_eval("if defined? A; end") - - assert_prism_eval("defined?(())") - assert_prism_eval("defined?(('1'))") - - # method chain starting with self that's truthy - assert_prism_eval("defined?(self.itself.itself.itself)") - - # method chain starting with self that's false (exception swallowed) - assert_prism_eval("defined?(self.itself.itself.neat)") - - # single self with method, truthy - assert_prism_eval("defined?(self.itself)") - - # single self with method, false - assert_prism_eval("defined?(self.neat!)") - - # method chain implicit self that's truthy - assert_prism_eval("defined?(itself.itself.itself)") - - # method chain implicit self that's false - assert_prism_eval("defined?(itself.neat.itself)") - - ## single method implicit self that's truthy - assert_prism_eval("defined?(itself)") - - ## single method implicit self that's false - assert_prism_eval("defined?(neatneat)") - - assert_prism_eval("defined?(a(itself))") - assert_prism_eval("defined?(itself(itself))") - end - - def test_GlobalVariableReadNode - assert_prism_eval("$pit = 1; $pit") - end - - def test_InstanceVariableReadNode - assert_prism_eval("class Prism::TestCompilePrism; @pit = 1; @pit; end") - end - - def test_LocalVariableReadNode - assert_prism_eval("pit = 1; pit") - end - - def test_NumberedReferenceReadNode - assert_prism_eval("$1") - assert_prism_eval("$99999") - end - - ############################################################################ - # Writes # - ############################################################################ - - def test_ClassVariableAndWriteNode - assert_prism_eval("class Prism::TestCompilePrism; @@pit = 0; @@pit &&= 1; end") - end - - def test_ClassVariableOperatorWriteNode - assert_prism_eval("class Prism::TestCompilePrism; @@pit = 0; @@pit += 1; end") - end - - def test_ClassVariableOrWriteNode - assert_prism_eval("class Prism::TestCompilePrism; @@pit = 1; @@pit ||= 0; end") - assert_prism_eval("class Prism::TestCompilePrism; @@pit = nil; @@pit ||= 1; end") - end - - def test_ClassVariableWriteNode - assert_prism_eval("class Prism::TestCompilePrism; @@pit = 1; end") - end - - def test_ConstantAndWriteNode - assert_prism_eval("Constant = 1; Constant &&= 1") - end - - def test_ConstantOperatorWriteNode - assert_prism_eval("Constant = 1; Constant += 1") - end - - def test_ConstantOrWriteNode - assert_prism_eval("Constant = 1; Constant ||= 1") - end - - def test_ConstantWriteNode - # We don't call assert_prism_eval directly in this case because we - # don't want to assign the constant multiple times if we run - # with `--repeat-count` - # Instead, we eval manually here, and remove the constant to - constant_name = "YCT" - source = "#{constant_name} = 1" - prism_eval = RubyVM::InstructionSequence.compile_prism(source).eval - assert_equal prism_eval, 1 - Object.send(:remove_const, constant_name) - end - - def test_ConstantPathWriteNode - assert_prism_eval("Prism::CPWN = 1") - assert_prism_eval("::CPWN = 1") - end - - def test_ConstantPathAndWriteNode - assert_prism_eval("Prism::CPAWN = 1; Prism::CPAWN &&= 2") - assert_prism_eval("Prism::CPAWN &&= 1") - assert_prism_eval("::CPAWN = 1; ::CPAWN &&= 2") - end - - def test_ConstantPathOrWriteNode - assert_prism_eval("Prism::CPOrWN = nil; Prism::CPOrWN ||= 1") - assert_prism_eval("Prism::CPOrWN ||= 1") - assert_prism_eval("::CPOrWN = nil; ::CPOrWN ||= 1") - end - - def test_ConstantPathOperatorWriteNode - assert_prism_eval("Prism::CPOWN = 0; Prism::CPOWN += 1") - assert_prism_eval("::CPOWN = 0; ::CPOWN += 1") - end - - def test_GlobalVariableAndWriteNode - assert_prism_eval("$pit = 0; $pit &&= 1") - end - - def test_GlobalVariableOperatorWriteNode - assert_prism_eval("$pit = 0; $pit += 1") - end - - def test_GlobalVariableOrWriteNode - assert_prism_eval("$pit ||= 1") - end - - def test_GlobalVariableWriteNode - assert_prism_eval("$pit = 1") - end - - def test_IndexAndWriteNode - assert_prism_eval("[0][0] &&= 1") - assert_prism_eval("[nil][0] &&= 1") - - # Testing `[]` with a block passed in - assert_prism_eval(<<-CODE) - class CustomHash < Hash - def []=(key, value, &block) - block ? super(block.call(key), value) : super(key, value) - end - end - - hash = CustomHash.new - - # Call the custom method with a block that modifies - # the key before assignment - hash["KEY"] = "test" - hash["key", &(Proc.new { _1.upcase })] &&= "value" - hash - CODE - end - - def test_IndexOrWriteNode - assert_prism_eval("[0][0] ||= 1") - assert_prism_eval("[nil][0] ||= 1") - - # Testing `[]` with a block passed in - assert_prism_eval(<<-CODE) - class CustomHash < Hash - def []=(key, value, &block) - super(block.call(key), value) - end - end - - hash = CustomHash.new - - # Call the custom method with a block that modifies - # the key before assignment - hash["key", &(Proc.new { _1.upcase })] ||= "value" - hash - CODE - end - - def test_IndexOperatorWriteNode - assert_prism_eval("[0][0] += 1") - - # Testing `[]` with a block passed in - assert_prism_eval(<<-CODE) - class CustomHash < Hash - def [](key, &block) - block ? super(block.call(key)) : super(key) - end - - def []=(key, value, &block) - block ? super(block.call(key), value) : super(key, value) - end - end - - hash = CustomHash.new - - # Call the custom method with a block that modifies - # the key before assignment - hash["KEY"] = "test" - hash["key", &(Proc.new { _1.upcase })] &&= "value" - hash - CODE - end - - def test_InstanceVariableAndWriteNode - assert_prism_eval("@pit = 0; @pit &&= 1") - end - - def test_InstanceVariableOperatorWriteNode - assert_prism_eval("@pit = 0; @pit += 1") - end - - def test_InstanceVariableOrWriteNode - assert_prism_eval("@pit ||= 1") - end - - def test_InstanceVariableWriteNode - assert_prism_eval("class Prism::TestCompilePrism; @pit = 1; end") - end - - def test_LocalVariableAndWriteNode - assert_prism_eval("pit = 0; pit &&= 1") - end - - def test_LocalVariableOperatorWriteNode - assert_prism_eval("pit = 0; pit += 1") - end - - def test_LocalVariableOrWriteNode - assert_prism_eval("pit ||= 1") - end - - def test_LocalVariableWriteNode - assert_prism_eval("pit = 1") - assert_prism_eval(<<-CODE) - a = 0 - [].each do - a = 1 - end - a - CODE - - assert_prism_eval(<<-CODE) - a = 1 - d = 1 - [1].each do - b = 2 - a = 2 - [2].each do - c = 3 - d = 4 - a = 2 - end - end - [a, d] - CODE - end - - def test_MatchWriteNode - assert_prism_eval("/(?<foo>bar)(?<baz>bar>)/ =~ 'barbar'") - assert_prism_eval("/(?<foo>bar)/ =~ 'barbar'") - end - - ############################################################################ - # Multi-writes # - ############################################################################ - - def test_ClassVariableTargetNode - assert_prism_eval("class Prism::TestCompilePrism; @@pit, @@pit1 = 1; end") - end - - def test_ConstantTargetNode - # We don't call assert_prism_eval directly in this case because we - # don't want to assign the constant multiple times if we run - # with `--repeat-count` - # Instead, we eval manually here, and remove the constant to - constant_names = ["YCT", "YCT2"] - source = "#{constant_names.join(",")} = 1" - prism_eval = RubyVM::InstructionSequence.compile_prism(source).eval - assert_equal prism_eval, 1 - constant_names.map { |name| - Object.send(:remove_const, name) - } - end - - def test_ConstantPathTargetNode - assert_separately([], <<~'RUBY') - verbose = $VERBOSE - # Create some temporary nested constants - Object.send(:const_set, "MyFoo", Object) - Object.const_get("MyFoo").send(:const_set, "Bar", Object) - - constant_names = ["MyBar", "MyFoo::Bar", "MyFoo::Bar::Baz"] - source = "#{constant_names.join(",")} = Object" - iseq = RubyVM::InstructionSequence.compile_prism(source) - $VERBOSE = nil - prism_eval = iseq.eval - $VERBOSE = verbose - assert_equal prism_eval, Object - RUBY - end - - def test_GlobalVariableTargetNode - assert_prism_eval("$pit, $pit1 = 1") - end - - def test_InstanceVariableTargetNode - assert_prism_eval("class Prism::TestCompilePrism; @pit, @pit1 = 1; end") - end - - def test_LocalVariableTargetNode - assert_prism_eval("pit, pit1 = 1") - assert_prism_eval(<<-CODE) - a = 1 - [1].each do - c = 2 - a, b = 2 - end - a - CODE - end - - def test_MultiTargetNode - assert_prism_eval("a, (b, c) = [1, 2, 3]") - assert_prism_eval("a, (b, c) = [1, 2, 3]; a") - assert_prism_eval("a, (b, c) = [1, 2, 3]; b") - assert_prism_eval("a, (b, c) = [1, 2, 3]; c") - assert_prism_eval("a, (b, c) = [1, [2, 3]]; c") - assert_prism_eval("a, (b, *c) = [1, [2, 3]]; c") - assert_prism_eval("a, (b, *c) = 1, [2, 3]; c") - assert_prism_eval("a, (b, *) = 1, [2, 3]; b") - assert_prism_eval("a, (b, *c, d) = 1, [2, 3, 4]; [a, b, c, d]") - assert_prism_eval("(a, (b, c, d, e), f, g), h = [1, [2, 3]], 4, 5, [6, 7]; c") - end - - def test_MultiWriteNode - assert_prism_eval("foo, bar = [1, 2]") - assert_prism_eval("foo, = [1, 2]") - assert_prism_eval("foo, *, bar = [1, 2]") - assert_prism_eval("foo, bar = 1, 2") - assert_prism_eval("foo, *, bar = 1, 2") - assert_prism_eval("foo, *, bar = 1, 2, 3, 4") - assert_prism_eval("a, b, *, d = 1, 2, 3, 4") - assert_prism_eval("a, b, *, d = 1, 2") - assert_prism_eval("(a, b), *, c = [1, 3], 4, 5") - assert_prism_eval("(a, b), *, c = [1, 3], 4, 5; a") - assert_prism_eval("(a, b), *, c = [1, 3], 4, 5; b") - assert_prism_eval("(a, b), *, c = [1, 3], 4, 5; c") - assert_prism_eval("a, *, (c, d) = [1, 3], 4, 5; a") - assert_prism_eval("a, *, (c, d) = [1, 3], 4, 5; c") - assert_prism_eval("(a, b, c), *, (d, e) = [1, 3], 4, 5, [6, 7]") - assert_prism_eval("(a, b, c), *, (d, e) = [1, 3], 4, 5, [6, 7]; b") - assert_prism_eval("(a, b, c), *, (d, e) = [1, 3], 4, 5, [6, 7]; d") - assert_prism_eval("((a, *, b), *, (c, *, (d, *, e, f, g))), *, ((h, i, *, j), *, (k, l, m, *, n, o, p), q, r) = 1; a") - assert_prism_eval("_, {}[:foo] = 1") - assert_prism_eval("_, {}[:foo], _ = 1") - assert_prism_eval("_, {}[:foo], _ = 1") - assert_prism_eval("_,{}[:foo], _, {}[:bar] = 1") - - assert_prism_eval(<<~CODE) - class Foo - def bar=(x); end - def baz=(c); end - end - foo = Foo.new - foo.bar, foo.baz = 1 - CODE - assert_prism_eval(<<~CODE) - class Foo - def bar=(x); end - def baz=(c); end - end - foo = Foo.new - _, foo.bar, foo.baz = 1 - CODE - assert_prism_eval(<<~CODE) - class Foo - def bar=(x); end - def baz=(c); end - end - foo = Foo.new - _, foo.bar, _, foo.baz = 1 - CODE - end - - ############################################################################ - # String-likes # - ############################################################################ - - def test_EmbeddedStatementsNode - assert_prism_eval('"foo #{to_s} baz"') - end - - def test_EmbeddedVariableNode - assert_prism_eval('class Prism::TestCompilePrism; @pit = 1; "#@pit"; end') - assert_prism_eval('class Prism::TestCompilePrism; @@pit = 1; "#@@pit"; end') - assert_prism_eval('$pit = 1; "#$pit"') - end - - def test_InterpolatedMatchLastLineNode - assert_prism_eval('$pit = ".oo"; if /"#{$pit}"/mix; end') - end - - def test_InterpolatedRegularExpressionNode - assert_prism_eval('$pit = 1; /1 #$pit 1/') - assert_prism_eval('$pit = 1; /#$pit/i') - assert_prism_eval('/1 #{1 + 2} 1/') - assert_prism_eval('/1 #{"2"} #{1 + 2} 1/') - end - - def test_InterpolatedStringNode - assert_prism_eval('$pit = 1; "1 #$pit 1"') - assert_prism_eval('"1 #{1 + 2} 1"') - assert_prism_eval('"Prism" "::" "TestCompilePrism"') - end - - def test_InterpolatedSymbolNode - assert_prism_eval('$pit = 1; :"1 #$pit 1"') - assert_prism_eval(':"1 #{1 + 2} 1"') - end - - def test_InterpolatedXStringNode - assert_prism_eval('`echo #{1}`') - assert_prism_eval('`printf #{"100"}`') - end - - def test_MatchLastLineNode - assert_prism_eval("if /foo/; end") - assert_prism_eval("if /foo/i; end") - assert_prism_eval("if /foo/x; end") - assert_prism_eval("if /foo/m; end") - assert_prism_eval("if /foo/im; end") - assert_prism_eval("if /foo/mx; end") - assert_prism_eval("if /foo/xi; end") - assert_prism_eval("if /foo/ixm; end") - end - - def test_RegularExpressionNode - assert_prism_eval('/pit/') - assert_prism_eval('/pit/i') - assert_prism_eval('/pit/x') - assert_prism_eval('/pit/m') - assert_prism_eval('/pit/im') - assert_prism_eval('/pit/mx') - assert_prism_eval('/pit/xi') - assert_prism_eval('/pit/ixm') - - assert_prism_eval('/pit/u') - assert_prism_eval('/pit/e') - assert_prism_eval('/pit/s') - assert_prism_eval('/pit/n') - - assert_prism_eval('/pit/me') - assert_prism_eval('/pit/ne') - - assert_prism_eval('2.times.map { /#{1}/o }') - assert_prism_eval('2.times.map { foo = 1; /#{foo}/o }') - end - - def test_StringNode - assert_prism_eval('"pit"') - assert_prism_eval('"a".frozen?') - - frozen_source = <<-CODE - # frozen_string_literal: true - "a".frozen? - CODE - ruby_eval = RubyVM::InstructionSequence.compile(frozen_source).eval - prism_eval = RubyVM::InstructionSequence.compile_prism(frozen_source).eval - - assert_equal ruby_eval, prism_eval - end - - def test_SymbolNode - assert_prism_eval(":pit") - end - - def test_XStringNode - assert_prism_eval(<<~RUBY) - class Prism::TestCompilePrism - def self.`(command) = command * 2 - `pit` - end - RUBY - end - - ############################################################################ - # Structures # - ############################################################################ - - def test_ArrayNode - assert_prism_eval("[]") - assert_prism_eval("[1, 2, 3]") - assert_prism_eval("%i[foo bar baz]") - assert_prism_eval("%w[foo bar baz]") - assert_prism_eval("[*1..2]") - assert_prism_eval("[*1..2, 3, 4, *5..6, 7, 8]") - assert_prism_eval("[*1..2, 3, 4, *5..6, 7, 8, *9..11]") - assert_prism_eval("[0, *1..2, 3, 4, *5..6, 7, 8, *9..11]") - assert_prism_eval("[-1, true, 0, *1..2, 3, 4, *5..6, 7, 8, *9..11]") - assert_prism_eval("a = [1,2]; [0, *a, 3, 4, *5..6, 7, 8, *9..11]") - assert_prism_eval("[[*1..2], 3, *4..5]") - end - - def test_AssocNode - assert_prism_eval("{ foo: :bar }") - end - - def test_AssocSplatNode - assert_prism_eval("foo = { a: 1 }; { **foo }") - assert_prism_eval("foo = { a: 1 }; bar = foo; { **foo, b: 2, **bar, c: 3 }") - assert_prism_eval("foo = { a: 1 }; { b: 2, **foo, c: 3}") - end - - def test_HashNode - assert_prism_eval("{}") - assert_prism_eval("{ a: :a }") - assert_prism_eval("{ a: :a, b: :b }") - assert_prism_eval("a = 1; { a: a }") - assert_prism_eval("a = 1; { a: }") - assert_prism_eval("{ to_s: }") - assert_prism_eval("{ Prism: }") - assert_prism_eval("[ Prism: [:b, :c]]") - assert_prism_eval("{ [] => 1}") - end - - def test_ImplicitNode - assert_prism_eval("{ to_s: }") - end - - def test_RangeNode - assert_prism_eval("1..2") - assert_prism_eval("1...2") - assert_prism_eval("..2") - assert_prism_eval("...2") - assert_prism_eval("1..") - assert_prism_eval("1...") - end - - def test_SplatNode - assert_prism_eval("*b = []; b") - assert_prism_eval("*b = [1, 2, 3]; b") - assert_prism_eval("a, *b = [1, 2, 3]; a") - assert_prism_eval("a, *b = [1, 2, 3]; b") - assert_prism_eval("a, *b, c = [1, 2, 3]; a") - assert_prism_eval("a, *b, c = [1, 2, 3]; b") - assert_prism_eval("a, *b, c = [1, 2, 3]; c") - assert_prism_eval("*b, c = [1, 2, 3]; b") - assert_prism_eval("*b, c = [1, 2, 3]; c") - assert_prism_eval("a, *, c = [1, 2, 3]; a") - assert_prism_eval("a, *, c = [1, 2, 3]; c") - end - - ############################################################################ - # Jumps # - ############################################################################ - - def test_AndNode - assert_prism_eval("true && 1") - assert_prism_eval("false && 1") - end - - def test_CaseNode - assert_prism_eval("case :a; when :a; 1; else; 2; end") - assert_prism_eval("case :a; when :b; 1; else; 2; end") - assert_prism_eval("case :a; when :a; 1; else; 2; end") - assert_prism_eval("case :a; when :a; end") - assert_prism_eval("case :a; when :b, :c; end") - assert_prism_eval("case; when :a; end") - assert_prism_eval("case; when :a, :b; 1; else; 2 end") - assert_prism_eval("case :a; when :b; else; end") - assert_prism_eval("b = 1; case :a; when b; else; end") - assert_prism_eval(<<-CODE) - def self.prism_test_case_node - case :a - when :b - else - return 2 - end - 1 - end - prism_test_case_node - CODE - end - - def test_ElseNode - assert_prism_eval("if false; 0; else; 1; end") - assert_prism_eval("if true; 0; else; 1; end") - assert_prism_eval("true ? 1 : 0") - assert_prism_eval("false ? 0 : 1") - end - - def test_FlipFlopNode - assert_prism_eval("not (1 == 1) .. (2 == 2)") - assert_prism_eval("not (1 == 1) ... (2 == 2)") - end - - def test_IfNode - assert_prism_eval("if true; 1; end") - assert_prism_eval("1 if true") - assert_prism_eval('a = b = 1; if a..b; end') - assert_prism_eval('if "a".."b"; end') - assert_prism_eval('if "a"..; end') - assert_prism_eval('if .."b"; end') - assert_prism_eval('if ..1; end') - assert_prism_eval('if 1..; end') - assert_prism_eval('if 1..2; end') - end - - def test_OrNode - assert_prism_eval("true || 1") - assert_prism_eval("false || 1") - end - - def test_UnlessNode - assert_prism_eval("1 unless true") - assert_prism_eval("1 unless false") - assert_prism_eval("unless true; 1; end") - assert_prism_eval("unless false; 1; end") - end - - def test_UntilNode - assert_prism_eval("a = 0; until a == 1; a = a + 1; end") - end - - def test_WhileNode - assert_prism_eval("a = 0; while a != 1; a = a + 1; end") - end - - def test_ForNode - assert_prism_eval("for i in [1,2] do; i; end") - assert_prism_eval("for @i in [1,2] do; @i; end") - assert_prism_eval("for $i in [1,2] do; $i; end") - - assert_prism_eval("for foo, in [1,2,3] do end") - - assert_prism_eval("for i, j in {a: 'b'} do; i; j; end") - end - - ############################################################################ - # Throws # - ############################################################################ - - def test_BeginNode - assert_prism_eval("begin; 1; end") - assert_prism_eval("begin; end; 1") - end - - def test_BreakNode - assert_prism_eval("while true; break; end") - assert_prism_eval("while true; break 1; end") - assert_prism_eval("while true; break 1, 2; end") - - assert_prism_eval("[].each { break }") - assert_prism_eval("[true].map { break }") - end - - def test_EnsureNode - assert_prism_eval("begin; 1; ensure; 2; end") - assert_prism_eval("begin; 1; begin; 3; ensure; 4; end; ensure; 2; end") - assert_prism_eval(<<-CODE) - begin - a = 2 - ensure - end - CODE - assert_prism_eval(<<-CODE) - begin - a = 2 - ensure - a = 3 - end - a - CODE - assert_prism_eval(<<-CODE) - a = 1 - begin - a = 2 - ensure - a = 3 - end - a - CODE - assert_prism_eval(<<-CODE) - a = 1 - begin - b = 2 - ensure - c = 3 - end - a + b + c - CODE - assert_prism_eval(<<~CODE) - foo = 1 - begin - ensure - begin - ensure - foo.nil? - end - end - CODE - assert_prism_eval(<<~CODE) - def test - ensure - {}.each do |key, value| - {}[key] = value - end - end - CODE - assert_prism_eval(<<~CODE) - def test - a = 1 - ensure - {}.each do |key, value| - {}[key] = a - end - end - CODE - assert_prism_eval(<<-CODE) - def self.prism_test_ensure_node - begin - ensure - end - return - end - prism_test_ensure_node - CODE - end - - def test_NextNode - assert_prism_eval("2.times do |i|; next if i == 1; end") - - assert_prism_eval(<<-CODE) - res = [] - i = 0 - while i < 5 - i += 1 - next if i == 3 - res << i - end - res - CODE - - assert_prism_eval(<<-CODE) - res = [] - (1..5).each do |i| - next if i.even? - res << i - end - res - CODE - - assert_prism_eval(<<-CODE) - (1..5).map do |i| - next i, :even if i.even? - i - end - CODE - - assert_prism_eval(<<-CODE) - res = [] - i = 0 - begin - i += 1 - next if i == 3 - res << i - end while i < 5 - res - CODE - - assert_prism_eval(<<-CODE) - while false - begin - ensure - end - next - end - CODE - end - - def test_RedoNode - assert_prism_eval(<<-CODE) - counter = 0 - - 5.times do |i| - counter += 1 - if i == 2 && counter < 3 - redo - end - end - CODE - - assert_prism_eval(<<-CODE) - for i in 1..5 - if i == 3 - i = 0 - redo - end - end - CODE - - assert_prism_eval(<<-CODE) - i = 0 - begin - i += 1 - redo if i == 3 - end while i < 5 - CODE - end - - def test_RescueNode - assert_prism_eval("begin; 1; rescue; 2; end") - assert_prism_eval(<<~CODE) - begin - 1 - rescue SyntaxError - 2 - end - CODE - assert_prism_eval(<<~CODE) - begin - 1 - raise 'boom' - rescue StandardError - 2 - end - CODE - assert_prism_eval(<<~CODE) - begin - a = 1 - rescue StandardError => e - end - CODE - assert_prism_eval(<<~CODE) - begin - raise StandardError - rescue StandardError => e - end - CODE - assert_prism_eval(<<~CODE) - begin - 1 - rescue StandardError => e - e - rescue SyntaxError => f - f - else - 4 - end - CODE - assert_prism_eval(<<-CODE) - begin - a = 2 - rescue - a = 3 - end - a - CODE - assert_prism_eval(<<-CODE) - a = 1 - begin - a = 2 - rescue - a = 3 - end - a - CODE - assert_prism_eval(<<-CODE) - a = 1 - begin - b = 2 - raise "bang" - rescue - c = 3 - end - a + b + c - CODE - assert_prism_eval("begin; rescue; end") - - assert_prism_eval(<<~CODE) - begin - rescue - args.each do |key, value| - tmp[key] = 1 - end - end - CODE - assert_prism_eval(<<~CODE) - 10.times do - begin - rescue - break - end - end - CODE - end - - def test_RescueModiferNode - assert_prism_eval("1.nil? rescue false") - assert_prism_eval("1.nil? rescue 1") - assert_prism_eval("raise 'bang' rescue nil") - assert_prism_eval("raise 'bang' rescue a = 1; a.nil?") - assert_prism_eval("a = 0 rescue (a += 1 && retry if a <= 1)") - end - - def test_RetryNode - assert_prism_eval(<<~CODE) - a = 1 - begin - a - raise "boom" - rescue - a += 1 - retry unless a > 1 - ensure - a = 3 - end - CODE - - assert_prism_eval(<<~CODE) - begin - rescue - foo = 2 - retry - end - CODE - - assert_prism_eval(<<~CODE) - begin - a = 2 - rescue - retry - end - CODE - end - - def test_ReturnNode - assert_prism_eval(<<-CODE) - def self.prism_test_return_node - return 1 - end - prism_test_return_node - CODE - - assert_prism_eval(<<-CODE) - def self.prism_test_return_node - return 1, 2 - end - prism_test_return_node - CODE - - assert_prism_eval(<<-CODE) - def self.prism_test_return_node - [1].each do |e| - return true - end - end - prism_test_return_node - CODE - - assert_prism_eval(<<-CODE) - def self.prism_test_return_node - [1].map do |i| - return i if i == 1 - 2 - end - end - prism_test_return_node - CODE - end - - ############################################################################ - # Scopes/statements # - ############################################################################ - - def test_BlockNode - assert_prism_eval("[1, 2, 3].each { |num| num }") - - assert_prism_eval("[].tap { _1 }") - - assert_prism_eval("[].each { |a,| }") - assert_prism_eval("[[1, 2, 3]].map { |_, _, a| a }") - assert_prism_eval("[[1, 2, 3]].map { |_, a| a }") - - assert_prism_eval("[[]].map { |a| a }") - assert_prism_eval("[[]].map { |a| a }") - assert_prism_eval("[[]].map { |a, &block| a }") - assert_prism_eval("[[]].map { |a, &block| a }") - assert_prism_eval("[{}].map { |a,| }") - assert_prism_eval("[[]].map { |a,b=1| a }") - assert_prism_eval("[{}].map { |a,| }") - assert_prism_eval("[{}].map { |a| a }") - end - - def test_ClassNode - assert_prism_eval("class PrismClassA; end") - assert_prism_eval("class PrismClassA; end; class PrismClassB < PrismClassA; end") - assert_prism_eval("class PrismClassA; end; class PrismClassA::PrismClassC; end") - assert_prism_eval(<<-HERE - class PrismClassA; end - class PrismClassA::PrismClassC; end - class PrismClassB; end - class PrismClassB::PrismClassD < PrismClassA::PrismClassC; end - HERE - ) - end - - # Many of these tests are versions of tests at bootstraptest/test_method.rb - def test_DefNode - assert_prism_eval("def prism_test_def_node; end") - assert_prism_eval("a = Object.new; def a.prism_singleton; :ok; end; a.prism_singleton") - assert_prism_eval("def self.prism_test_def_node() 1 end; prism_test_def_node()") - assert_prism_eval("def self.prism_test_def_node(a,b) [a, b] end; prism_test_def_node(1,2)") - assert_prism_eval("def self.prism_test_def_node(a,x=7,y=1) x end; prism_test_def_node(7,1)") - assert_prism_eval("def self.prism_test_def_node(a = 1); x = 2; end; prism_test_def_node") - - # rest argument - assert_prism_eval("def self.prism_test_def_node(*a) a end; prism_test_def_node().inspect") - assert_prism_eval("def self.prism_test_def_node(*a) a end; prism_test_def_node(1).inspect") - assert_prism_eval("def self.prism_test_def_node(x,y,*a) a end; prism_test_def_node(7,7,1,2).inspect") - assert_prism_eval("def self.prism_test_def_node(x,y=7,*a) a end; prism_test_def_node(7).inspect") - assert_prism_eval("def self.prism_test_def_node(x,y,z=7,*a) a end; prism_test_def_node(7,7).inspect") - assert_prism_eval("def self.prism_test_def_node(x,y,z=7,zz=7,*a) a end; prism_test_def_node(7,7,7).inspect") - - # keyword arguments - assert_prism_eval("def self.prism_test_def_node(a: 1, b: 2, c: 4) a + b + c; end; prism_test_def_node(a: 2)") - assert_prism_eval("def self.prism_test_def_node(a: 1, b: 2, c: 4) a + b + c; end; prism_test_def_node(b: 3)") - assert_prism_eval(<<-CODE) - def self.prism_test_def_node(x = 1, y, a: 8, b: 2, c: 4) - a + b + c + x + y - end - prism_test_def_node(10, b: 3) - CODE - assert_prism_eval(<<-CODE) - def self.prism_test_def_node(a: []) - a - end - prism_test_def_node - CODE - - # block arguments - assert_prism_eval("def self.prism_test_def_node(&block) block end; prism_test_def_node{}.class") - assert_prism_eval("def self.prism_test_def_node(&block) block end; prism_test_def_node().inspect") - assert_prism_eval("def self.prism_test_def_node(a,b=7,*c,&block) b end; prism_test_def_node(7,1).inspect") - assert_prism_eval("def self.prism_test_def_node(a,b=7,*c,&block) c end; prism_test_def_node(7,7,1).inspect") - - # splat - assert_prism_eval("def self.prism_test_def_node(a) a end; prism_test_def_node(*[1])") - assert_prism_eval("def self.prism_test_def_node(x,a) a end; prism_test_def_node(7,*[1])") - assert_prism_eval("def self.prism_test_def_node(x,y,a) a end; prism_test_def_node(7,7,*[1])") - assert_prism_eval("def self.prism_test_def_node(x,y,a,b,c) a end; prism_test_def_node(7,7,*[1,7,7])") - - # recursive call - assert_prism_eval("def self.prism_test_def_node(n) n == 0 ? 1 : prism_test_def_node(n-1) end; prism_test_def_node(5)") - - # instance method - assert_prism_eval("class PrismTestDefNode; def prism_test_def_node() 1 end end; PrismTestDefNode.new.prism_test_def_node") - assert_prism_eval("class PrismTestDefNode; def prism_test_def_node(*a) a end end; PrismTestDefNode.new.prism_test_def_node(1).inspect") - - # block argument - assert_prism_eval(<<-CODE) - def self.prism_test_def_node(&block) prism_test_def_node2(&block) end - def self.prism_test_def_node2() yield 1 end - prism_test_def_node2 {|a| a } - CODE - - # multi argument - assert_prism_eval(<<-CODE) - def self.prism_test_def_node(a, (b, *c, d)) - [a, b, c, d] - end - prism_test_def_node("a", ["b", "c", "d"]) - CODE - assert_prism_eval(<<-CODE) - def self.prism_test_def_node(a, (b, c, *)) - [a, b, c] - end - prism_test_def_node("a", ["b", "c"]) - CODE - assert_prism_eval(<<-CODE) - def self.prism_test_def_node(a, (*, b, c)) - [a, b, c] - end - prism_test_def_node("a", ["b", "c"]) - CODE - - # recursive multis - assert_prism_eval(<<-CODE) - def self.prism_test_def_node(a, (b, *c, (d, *e, f))) - [a, b, c, d, d, e, f] - end - prism_test_def_node("a", ["b", "c", ["d", "e", "f"]]) - CODE - - # Many arguments - assert_prism_eval(<<-CODE) - def self.prism_test_def_node(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m) - [a, b, c, d, e, f, g, h, i, j, k, l, m] - end - prism_test_def_node( - "a", - ["b", "c1", "c2", "d"], - "e", - "f1", "f2", - "g", - ["h", "i1", "i2", "j"], - k: "k", - l: "l", - m1: "m1", - m2: "m2" - ) - CODE - end - - def test_method_parameters - assert_prism_eval(<<-CODE) - def self.prism_test_method_parameters(a, b=1, *c, d:, e: 2, **f, &g) - end - - method(:prism_test_method_parameters).parameters - CODE - - assert_prism_eval(<<-CODE) - def self.prism_test_method_parameters(d:, e: 2, **f, &g) - end - - method(:prism_test_method_parameters).parameters - CODE - - assert_prism_eval(<<-CODE) - def self.prism_test_method_parameters(**f, &g) - end - - method(:prism_test_method_parameters).parameters - CODE - - assert_prism_eval(<<-CODE) - def self.prism_test_method_parameters(&g) - end - - method(:prism_test_method_parameters).parameters - CODE - end - - def test_LambdaNode - assert_prism_eval("-> { to_s }.call") - end - - def test_ModuleNode - assert_prism_eval("module M; end") - assert_prism_eval("module M::N; end") - assert_prism_eval("module ::O; end") - end - - def test_ParenthesesNode - assert_prism_eval("()") - assert_prism_eval("(1)") - end - - def test_PreExecutionNode - # BEGIN {} must be defined at the top level, so we need to manually - # call the evals here instead of calling `assert_prism_eval` - ruby_eval = RubyVM::InstructionSequence.compile("BEGIN { a = 1 }; 2").eval - prism_eval = RubyVM::InstructionSequence.compile_prism("BEGIN { a = 1 }; 2").eval - assert_equal ruby_eval, prism_eval - - ruby_eval = RubyVM::InstructionSequence.compile("b = 2; BEGIN { a = 1 }; a + b").eval - prism_eval = RubyVM::InstructionSequence.compile_prism("b = 2; BEGIN { a = 1 }; a + b").eval - assert_equal ruby_eval, prism_eval - end - - def test_PostExecutionNode - assert_prism_eval("END { 1 }") - assert_prism_eval("END { @b }; @b = 1") - assert_prism_eval("END { @b; 0 }; @b = 1") - assert_prism_eval("foo = 1; END { foo.nil? }") - assert_prism_eval("foo = 1; END { END { foo.nil? }}") - end - - def test_ProgramNode - assert_prism_eval("") - assert_prism_eval("1") - end - - def test_SingletonClassNode - assert_prism_eval("class << self; end") - end - - def test_StatementsNode - assert_prism_eval("1") - end - - def test_YieldNode - assert_prism_eval("def prism_test_yield_node; yield; end") - assert_prism_eval("def prism_test_yield_node; yield 1, 2; end") - assert_prism_eval("def prism_test_yield_node; yield **kw if condition; end") - - # Test case where there's a call directly after the yield call - assert_prism_eval("def prism_test_yield_node; yield; 1; end") - assert_prism_eval("def prism_test_yield_node; yield 1, 2; 1; end") - end - - ############################################################################ - # Calls / arguments # - ############################################################################ - - def test_ArgumentsNode - # assert_prism_eval("[].push 1") - end - - def test_BlockArgumentNode - assert_prism_eval("1.then(&:to_s)") - end - - def test_BlockLocalVariableNode - assert_prism_eval(<<-CODE - pm_var = "outer scope variable" - - 1.times { |;pm_var| pm_var = "inner scope variable"; pm_var } - CODE - ) - - assert_prism_eval(<<-CODE - pm_var = "outer scope variable" - - 1.times { |;pm_var| pm_var = "inner scope variable"; pm_var } - pm_var - CODE - ) - end - - def test_CallNode - assert_prism_eval("to_s") - - # with arguments - assert_prism_eval("eval '1'") - - # with arguments and popped - assert_prism_eval("eval '1'; 1") - - # With different types of calling arguments - assert_prism_eval(<<-CODE) - def self.prism_test_call_node_double_splat(**); end - prism_test_call_node_double_splat(b: 1, **{}) - CODE - assert_prism_eval(<<-CODE) - prism_test_call_node_double_splat(:b => 1) - CODE - - assert_prism_eval(<<-CODE) - def self.prism_test_call_node_splat(*); end - prism_test_call_node_splat(*[], 1) - CODE - - assert_prism_eval("prism_test_call_node_splat(*[], 1, 2)") - - assert_prism_eval(<<-CODE) - class Foo - def []=(a, b) - 1234 - end - end - - def self.foo(i, j) - tbl = Foo.new - tbl[i] = j - end - foo(1, 2) - CODE - - assert_prism_eval(<<-CODE) - class Foo - def i=(a) - 1234 - end - end - - def self.foo(j) - tbl = Foo.new - tbl.i = j - end - foo(1) - CODE - - assert_prism_eval(<<-CODE) - foo = Object.new - def foo.[]=(k,v); 42; end - foo.[]=(1,2) - CODE - - assert_prism_eval(<<-CODE) - def self.prism_opt_var_trail_hash(a = nil, *b, c, **d); end - prism_opt_var_trail_hash("a") - prism_opt_var_trail_hash("a", c: 1) - prism_opt_var_trail_hash("a", "b") - prism_opt_var_trail_hash("a", "b", "c") - prism_opt_var_trail_hash("a", "b", "c", c: 1) - prism_opt_var_trail_hash("a", "b", "c", "c" => 0, c: 1) - CODE - - assert_prism_eval(<<-CODE) - def self.foo(*args, **kwargs) = [args, kwargs] - - [ - foo(2 => 3), - foo([] => 42), - foo(a: 42, b: 61), - foo(1, 2, 3, a: 42, "b" => 61), - foo(:a => 42, :b => 61), - ] - CODE - - assert_prism_eval(<<-CODE) - class PrivateMethod - def initialize - self.instance_var - end - private - attr_accessor :instance_var - end - pm = PrivateMethod.new - pm.send(:instance_var) - CODE - - # Testing safe navigation operator - assert_prism_eval(<<-CODE) - def self.test_prism_call_node - if [][0]&.first - 1 - end - end - test_prism_call_node - CODE - end - - def test_CallAndWriteNode - assert_prism_eval(<<-CODE - class PrismTestSubclass; end - def PrismTestSubclass.test_call_and_write_node; end; - PrismTestSubclass.test_call_and_write_node &&= 1 - CODE - ) - - assert_prism_eval(<<-CODE - def PrismTestSubclass.test_call_and_write_node - "str" - end - def PrismTestSubclass.test_call_and_write_node=(val) - val - end - PrismTestSubclass.test_call_and_write_node &&= 1 - CODE - ) - - assert_prism_eval(<<-CODE - def self.test_call_and_write_node; end; - self.test_call_and_write_node &&= 1 - CODE - ) - - assert_prism_eval(<<-CODE - def self.test_call_and_write_node - "str" - end - def self.test_call_and_write_node=(val) - val - end - self.test_call_and_write_node &&= 1 - CODE - ) - - assert_prism_eval(<<-CODE) - def self.test_prism_call_node; end - def self.test_prism_call_node=(val) - val - end - self&.test_prism_call_node &&= 1 - CODE - - assert_prism_eval(<<-CODE) - def self.test_prism_call_node - 2 - end - def self.test_prism_call_node=(val) - val - end - self&.test_prism_call_node &&= 1 - CODE - end - - def test_CallOrWriteNode - assert_prism_eval(<<-CODE - class PrismTestSubclass; end - def PrismTestSubclass.test_call_or_write_node; end; - def PrismTestSubclass.test_call_or_write_node=(val) - val - end - PrismTestSubclass.test_call_or_write_node ||= 1 - CODE - ) - - assert_prism_eval(<<-CODE - def PrismTestSubclass.test_call_or_write_node - "str" - end - PrismTestSubclass.test_call_or_write_node ||= 1 - CODE - ) - - assert_prism_eval(<<-CODE - def self.test_call_or_write_node; end; - def self.test_call_or_write_node=(val) - val - end - self.test_call_or_write_node ||= 1 - CODE - ) - - assert_prism_eval(<<-CODE - def self.test_call_or_write_node - "str" - end - self.test_call_or_write_node ||= 1 - CODE - ) - - assert_prism_eval(<<-CODE) - def self.test_prism_call_node - 2 - end - def self.test_prism_call_node=(val) - val - end - self&.test_prism_call_node ||= 1 - CODE - - assert_prism_eval(<<-CODE) - def self.test_prism_call_node; end - def self.test_prism_call_node=(val) - val - end - self&.test_prism_call_node ||= 1 - CODE - end - - def test_CallOperatorWriteNode - assert_prism_eval(<<-CODE - class PrismTestSubclass; end - def PrismTestSubclass.test_call_operator_write_node - 2 - end - def PrismTestSubclass.test_call_operator_write_node=(val) - val - end - PrismTestSubclass.test_call_operator_write_node += 1 - CODE - ) - end - - def test_ForwardingArgumentsNode - # http://ci.rvm.jp/results/trunk-iseq_binary@ruby-sp2-docker/4779277 - # - # expected: - # == disasm: #<ISeq:prism_test_forwarding_arguments_node1@<compiled>:2 (2,8)-(4,11)> - # local table (size: 1, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: 1]) - # [ 1] "..."@0 - # 0000 putself ( 3) - # 0001 getlocal_WC_0 ?@-2 - # 0003 splatarray false - # 0005 getblockparamproxy ?@-1, 0 - # 0008 send <calldata!mid:prism_test_forwarding_arguments_node, argc:1, ARGS_SPLAT|ARGS_BLOCKARG|FCALL>, nil - # 0011 leave ( 2) - # actual: - # == disasm: #<ISeq:prism_test_forwarding_arguments_node1@<compiled>:2 (2,8)-(4,11)> - # local table (size: 1, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: 1]) - # [ 1] "..."@0 - # 0000 putself ( 3) - # 0001 getlocal_WC_0 ?@-2 - # 0003 splatarray false - # 0005 getblockparamproxy "!"@-1, 0 - # 0008 send <calldata!mid:prism_test_forwarding_arguments_node, argc:1, ARGS_SPLAT|ARGS_BLOCKARG|FCALL>, nil - # 0011 leave ( 2) - - omit "fails on trunk-iseq_binary" - - assert_prism_eval(<<-CODE) - def prism_test_forwarding_arguments_node(...); end; - def prism_test_forwarding_arguments_node1(...) - prism_test_forwarding_arguments_node(...) - end - CODE - - assert_prism_eval(<<-CODE) - def prism_test_forwarding_arguments_node(...); end; - def prism_test_forwarding_arguments_node1(a, ...) - prism_test_forwarding_arguments_node(1,2, 3, ...) - end - CODE - end - - def test_ForwardingSuperNode - assert_prism_eval("class Forwarding; def to_s; super; end; end") - assert_prism_eval("class Forwarding; def eval(code); super { code }; end; end") - assert_prism_eval(<<-CODE) - class A - def initialize(a, b) - end - end - - class B < A - attr_reader :res - def initialize(a, b, *) - super - @res = [a, b] - end - end - - B.new(1, 2).res - CODE - end - - def test_KeywordHashNode - assert_prism_eval("[a: [:b, :c]]") - end - - def test_SuperNode - assert_prism_eval("def to_s; super 1; end") - assert_prism_eval("def to_s; super(); end") - assert_prism_eval("def to_s; super('a', :b, [1,2,3]); end") - assert_prism_eval("def to_s; super(1, 2, 3, &:foo); end") - end - - ############################################################################ - # Methods / parameters # - ############################################################################ - - def test_AliasGlobalVariableNode - assert_prism_eval("alias $prism_foo $prism_bar") - end - - def test_AliasMethodNode - assert_prism_eval("alias :prism_a :to_s") - end - - def test_BlockParameterNode - assert_prism_eval("def prism_test_block_parameter_node(&bar) end") - assert_prism_eval("->(b, c=1, *d, e, &f){}") - end - - def test_BlockParametersNode - assert_prism_eval("Object.tap { || }") - assert_prism_eval("[1].map { |num| num }") - assert_prism_eval("[1].map { |a; b| b = 2; a + b}") - end - - def test_FowardingParameterNode - assert_prism_eval("def prism_test_forwarding_parameter_node(...); end") - end - - def test_KeywordRestParameterNode - assert_prism_eval("def prism_test_keyword_rest_parameter_node(a, **b); end") - assert_prism_eval("Object.tap { |**| }") - end - - def test_NoKeywordsParameterNode - assert_prism_eval("def prism_test_no_keywords(**nil); end") - assert_prism_eval("def prism_test_no_keywords(a, b = 2, **nil); end") - end - - def test_OptionalParameterNode - assert_prism_eval("def prism_test_optional_param_node(bar = nil); end") - end - - def test_OptionalKeywordParameterNode - assert_prism_eval("def prism_test_optional_keyword_param_node(bar: nil); end") - end - - def test_ParametersNode - assert_prism_eval("def prism_test_parameters_node(bar, baz); end") - assert_prism_eval("def prism_test_parameters_node(a, b = 2); end") - end - - def test_RequiredParameterNode - assert_prism_eval("def prism_test_required_param_node(bar); end") - assert_prism_eval("def prism_test_required_param_node(foo, bar); end") - end - - def test_RequiredKeywordParameterNode - assert_prism_eval("def prism_test_required_param_node(bar:); end") - assert_prism_eval("def prism_test_required_param_node(foo:, bar:); end") - assert_prism_eval("-> a, b = 1, c:, d:, &e { a }") - end - - def test_RestParameterNode - assert_prism_eval("def prism_test_rest_parameter_node(*a); end") - end - - def test_UndefNode - assert_prism_eval("def prism_undef_node_1; end; undef prism_undef_node_1") - assert_prism_eval(<<-HERE - def prism_undef_node_2 - end - def prism_undef_node_3 - end - undef prism_undef_node_2, prism_undef_node_3 - HERE - ) - assert_prism_eval(<<-HERE - def prism_undef_node_4 - end - undef :'prism_undef_node_#{4}' - HERE - ) - end - - ############################################################################ - # Pattern matching # - ############################################################################ - - def test_AlternationPatternNode - assert_prism_eval("1 in 1 | 2") - assert_prism_eval("1 in 2 | 1") - assert_prism_eval("1 in 2 | 3 | 4 | 1") - assert_prism_eval("1 in 2 | 3") - end - - def test_ArrayPatternNode - assert_prism_eval("[] => []") - - ["in", "=>"].each do |operator| - ["", "Array"].each do |constant| - assert_prism_eval("[1, 2, 3] #{operator} #{constant}[1, 2, 3]") - - assert_prism_eval("[1, 2, 3] #{operator} #{constant}[*]") - assert_prism_eval("[1, 2, 3] #{operator} #{constant}[1, *]") - assert_prism_eval("[1, 2, 3] #{operator} #{constant}[1, 2, *]") - assert_prism_eval("[1, 2, 3] #{operator} #{constant}[1, 2, 3, *]") - - assert_prism_eval("[1, 2, 3] #{operator} #{constant}[*foo]") - assert_prism_eval("[1, 2, 3] #{operator} #{constant}[1, *foo]") - assert_prism_eval("[1, 2, 3] #{operator} #{constant}[1, 2, *foo]") - assert_prism_eval("[1, 2, 3] #{operator} #{constant}[1, 2, 3, *foo]") - - assert_prism_eval("[1, 2, 3] #{operator} #{constant}[*, 3]") - assert_prism_eval("[1, 2, 3] #{operator} #{constant}[*, 2, 3]") - assert_prism_eval("[1, 2, 3] #{operator} #{constant}[*, 1, 2, 3]") - - assert_prism_eval("[1, 2, 3] #{operator} #{constant}[*foo, 3]") - assert_prism_eval("[1, 2, 3] #{operator} #{constant}[*foo, 2, 3]") - assert_prism_eval("[1, 2, 3] #{operator} #{constant}[*foo, 1, 2, 3]") - end - end - - assert_prism_eval("begin; Object.new => [1, 2, 3]; rescue NoMatchingPatternError; true; end") - assert_prism_eval("begin; [1, 2, 3] => Object[1, 2, 3]; rescue NoMatchingPatternError; true; end") - end - - def test_CapturePatternNode - assert_prism_eval("[1] => [Integer => foo]") - end - - def test_CaseMatchNode - assert_prism_eval(<<~RUBY) - case [1, 2, 3] - in [1, 2, 3] - 4 - end - RUBY - - assert_prism_eval(<<~RUBY) - case { a: 5, b: 6 } - in [1, 2, 3] - 4 - in { a: 5, b: 6 } - 7 - end - RUBY - - assert_prism_eval(<<~RUBY) - case [1, 2, 3, 4] - in [1, 2, 3] - 4 - in { a: 5, b: 6 } - 7 - else - end - RUBY - - assert_prism_eval(<<~RUBY) - case [1, 2, 3, 4] - in [1, 2, 3] - 4 - in { a: 5, b: 6 } - 7 - else - 8 - end - RUBY - - assert_prism_eval(<<~RUBY) - case [1, 2, 3] - in [1, 2, 3] unless to_s - in [1, 2, 3] if to_s.nil? - in [1, 2, 3] - true - end - RUBY - end - - def test_FindPatternNode - ["in", "=>"].each do |operator| - ["", "Array"].each do |constant| - assert_prism_eval("[1, 2, 3, 4, 5] #{operator} #{constant}[*, 1, 2, 3, 4, 5, *]") - - assert_prism_eval("[1, 2, 3, 4, 5] #{operator} #{constant}[*, 1, *]") - assert_prism_eval("[1, 2, 3, 4, 5] #{operator} #{constant}[*, 3, *]") - assert_prism_eval("[1, 2, 3, 4, 5] #{operator} #{constant}[*, 5, *]") - - assert_prism_eval("[1, 2, 3, 4, 5] #{operator} #{constant}[*, 1, 2, *]") - assert_prism_eval("[1, 2, 3, 4, 5] #{operator} #{constant}[*, 2, 3, *]") - assert_prism_eval("[1, 2, 3, 4, 5] #{operator} #{constant}[*, 3, 4, *]") - assert_prism_eval("[1, 2, 3, 4, 5] #{operator} #{constant}[*, 4, 5, *]") - - assert_prism_eval("[1, 2, 3, 4, 5] #{operator} #{constant}[*, 1, 2, 3, *]") - assert_prism_eval("[1, 2, 3, 4, 5] #{operator} #{constant}[*, 2, 3, 4, *]") - assert_prism_eval("[1, 2, 3, 4, 5] #{operator} #{constant}[*, 3, 4, 5, *]") - - assert_prism_eval("[1, 2, 3, 4, 5] #{operator} #{constant}[*, 1, 2, 3, 4, *]") - assert_prism_eval("[1, 2, 3, 4, 5] #{operator} #{constant}[*, 2, 3, 4, 5, *]") - - assert_prism_eval("[1, 2, 3, 4, 5] #{operator} #{constant}[*foo, 3, *]") - assert_prism_eval("[1, 2, 3, 4, 5] #{operator} #{constant}[*foo, 3, 4, *]") - assert_prism_eval("[1, 2, 3, 4, 5] #{operator} #{constant}[*foo, 3, 4, 5, *]") - assert_prism_eval("[1, 2, 3, 4, 5] #{operator} #{constant}[*foo, 1, 2, 3, 4, *]") - - assert_prism_eval("[1, 2, 3, 4, 5] #{operator} #{constant}[*, 3, *foo]") - assert_prism_eval("[1, 2, 3, 4, 5] #{operator} #{constant}[*, 3, 4, *foo]") - assert_prism_eval("[1, 2, 3, 4, 5] #{operator} #{constant}[*, 3, 4, 5, *foo]") - assert_prism_eval("[1, 2, 3, 4, 5] #{operator} #{constant}[*, 1, 2, 3, 4, *foo]") - - assert_prism_eval("[1, 2, 3, 4, 5] #{operator} #{constant}[*foo, 3, *bar]") - assert_prism_eval("[1, 2, 3, 4, 5] #{operator} #{constant}[*foo, 3, 4, *bar]") - assert_prism_eval("[1, 2, 3, 4, 5] #{operator} #{constant}[*foo, 3, 4, 5, *bar]") - assert_prism_eval("[1, 2, 3, 4, 5] #{operator} #{constant}[*foo, 1, 2, 3, 4, *bar]") - end - end - - assert_prism_eval("[1, [2, [3, [4, [5]]]]] => [*, [*, [*, [*, [*]]]]]") - assert_prism_eval("[1, [2, [3, [4, [5]]]]] => [1, [2, [3, [4, [5]]]]]") - - assert_prism_eval("begin; Object.new => [*, 2, *]; rescue NoMatchingPatternError; true; end") - assert_prism_eval("begin; [1, 2, 3] => Object[*, 2, *]; rescue NoMatchingPatternError; true; end") - end - - def test_HashPatternNode - assert_prism_eval("{} => {}") - - [["{ ", " }"], ["Hash[", "]"]].each do |(prefix, suffix)| - assert_prism_eval("{} => #{prefix} **nil #{suffix}") - - assert_prism_eval("{ a: 1, b: 2, c: 3 } => #{prefix} a: 1 #{suffix}") - assert_prism_eval("{ a: 1, b: 2, c: 3 } => #{prefix} a: 1, b: 2 #{suffix}") - assert_prism_eval("{ a: 1, b: 2, c: 3 } => #{prefix} b: 2, c: 3 #{suffix}") - assert_prism_eval("{ a: 1, b: 2, c: 3 } => #{prefix} a: 1, b: 2, c: 3 #{suffix}") - - assert_prism_eval("{ a: 1, b: 2, c: 3 } => #{prefix} ** #{suffix}") - assert_prism_eval("{ a: 1, b: 2, c: 3 } => #{prefix} a: 1, ** #{suffix}") - assert_prism_eval("{ a: 1, b: 2, c: 3 } => #{prefix} a: 1, b: 2, ** #{suffix}") - assert_prism_eval("{ a: 1, b: 2, c: 3 } => #{prefix} b: 2, c: 3, ** #{suffix}") - assert_prism_eval("{ a: 1, b: 2, c: 3 } => #{prefix} a: 1, b: 2, c: 3, ** #{suffix}") - - assert_prism_eval("{ a: 1, b: 2, c: 3 } => #{prefix} **foo #{suffix}") - assert_prism_eval("{ a: 1, b: 2, c: 3 } => #{prefix} a: 1, **foo #{suffix}") - assert_prism_eval("{ a: 1, b: 2, c: 3 } => #{prefix} a: 1, b: 2, **foo #{suffix}") - assert_prism_eval("{ a: 1, b: 2, c: 3 } => #{prefix} b: 2, c: 3, **foo #{suffix}") - assert_prism_eval("{ a: 1, b: 2, c: 3 } => #{prefix} a: 1, b: 2, c: 3, **foo #{suffix}") - - assert_prism_eval("{ a: 1 } => #{prefix} a: 1, **nil #{suffix}") - assert_prism_eval("{ a: 1, b: 2, c: 3 } => #{prefix} a: 1, b: 2, c: 3, **nil #{suffix}") - end - - assert_prism_eval("{ a: { b: { c: 1 } } } => { a: { b: { c: 1 } } }") - end - - def test_MatchPredicateNode - assert_prism_eval("1 in 1") - assert_prism_eval("1.0 in 1.0") - assert_prism_eval("1i in 1i") - assert_prism_eval("1r in 1r") - - assert_prism_eval("\"foo\" in \"foo\"") - assert_prism_eval("\"foo \#{1}\" in \"foo \#{1}\"") - - assert_prism_eval("false in false") - assert_prism_eval("nil in nil") - assert_prism_eval("self in self") - assert_prism_eval("true in true") - - assert_prism_eval("5 in 0..10") - assert_prism_eval("5 in 0...10") - - assert_prism_eval("[\"5\"] in %w[5]") - - assert_prism_eval("Prism in Prism") - assert_prism_eval("Prism in ::Prism") - - assert_prism_eval(":prism in :prism") - assert_prism_eval("%s[prism\#{1}] in %s[prism\#{1}]") - assert_prism_eval("\"foo\" in /.../") - assert_prism_eval("\"foo1\" in /...\#{1}/") - assert_prism_eval("4 in ->(v) { v.even? }") - - assert_prism_eval("5 in foo") - - assert_prism_eval("1 in 2") - end - - def test_MatchRequiredNode - assert_prism_eval("1 => 1") - assert_prism_eval("1.0 => 1.0") - assert_prism_eval("1i => 1i") - assert_prism_eval("1r => 1r") - - assert_prism_eval("\"foo\" => \"foo\"") - assert_prism_eval("\"foo \#{1}\" => \"foo \#{1}\"") - - assert_prism_eval("false => false") - assert_prism_eval("nil => nil") - assert_prism_eval("true => true") - - assert_prism_eval("5 => 0..10") - assert_prism_eval("5 => 0...10") - - assert_prism_eval("[\"5\"] => %w[5]") - - assert_prism_eval(":prism => :prism") - assert_prism_eval("%s[prism\#{1}] => %s[prism\#{1}]") - assert_prism_eval("\"foo\" => /.../") - assert_prism_eval("\"foo1\" => /...\#{1}/") - assert_prism_eval("4 => ->(v) { v.even? }") - - assert_prism_eval("5 => foo") - end - - def test_PinnedExpressionNode - assert_prism_eval("4 in ^(4)") - end - - def test_PinnedVariableNode - assert_prism_eval("module Prism; @@prism = 1; 1 in ^@@prism; end") - assert_prism_eval("module Prism; @prism = 1; 1 in ^@prism; end") - assert_prism_eval("$prism = 1; 1 in ^$prism") - assert_prism_eval("prism = 1; 1 in ^prism") - end - - ############################################################################ - # Miscellaneous # - ############################################################################ - - def test_ScopeNode - assert_separately(%w[], "#{<<-'begin;'}\n#{<<-'end;'}") - begin; - def compare_eval(source) - ruby_eval = RubyVM::InstructionSequence.compile("module A; " + source + "; end").eval - prism_eval = RubyVM::InstructionSequence.compile_prism("module B; " + source + "; end").eval - - assert_equal ruby_eval, prism_eval - end - - def assert_prism_eval(source) - $VERBOSE, verbose_bak = nil, $VERBOSE - - begin - compare_eval(source) - - # Test "popped" functionality - compare_eval("#{source}; 1") - ensure - $VERBOSE = verbose_bak - end - end - assert_prism_eval("a = 1; 1.times do; { a: }; end") - assert_prism_eval("a = 1; def foo(a); a; end") - end; - end - - ############################################################################ - # Errors # - ############################################################################ - - def test_MissingNode - # TODO - end - - ############################################################################ - # Encoding # - ############################################################################ - - def test_encoding - assert_prism_eval('"però"') - assert_prism_eval(":però") - end - - private - - def compare_eval(source) - source = "class Prism::TestCompilePrism\n#{source}\nend" - - ruby_eval = RubyVM::InstructionSequence.compile(source).eval - prism_eval = RubyVM::InstructionSequence.compile_prism(source).eval - - if ruby_eval.is_a? Proc - assert_equal ruby_eval.class, prism_eval.class - else - assert_equal ruby_eval, prism_eval - end - end - - def assert_prism_eval(source) - $VERBOSE, verbose_bak = nil, $VERBOSE - - begin - compare_eval(source) - - # Test "popped" functionality - compare_eval("#{source}; 1") - ensure - $VERBOSE = verbose_bak - end - end - end -end diff --git a/test/ruby/test_complex.rb b/test/ruby/test_complex.rb index 5cd17d9205..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 @@ -526,71 +520,6 @@ class Complex_Test < Test::Unit::TestCase r = c ** Rational(-2,3) assert_in_delta(0.432, r.real, 0.001) assert_in_delta(-0.393, r.imag, 0.001) - end - - def test_expt_for_special_angle - c = Complex(1, 0) ** 100000000000000000000000000000000 - assert_equal(Complex(1, 0), c) - - c = Complex(-1, 0) ** 10000000000000000000000000000000 - assert_equal(Complex(1, 0), c) - - c = Complex(-1, 0) ** 10000000000000000000000000000001 - assert_equal(Complex(-1, 0), c) - - c = Complex(0, 1) ** 100000000000000000000000000000000 - assert_equal(Complex(1, 0), c) - - c = Complex(0, 1) ** 100000000000000000000000000000001 - assert_equal(Complex(0, 1), c) - - c = Complex(0, 1) ** 100000000000000000000000000000002 - assert_equal(Complex(-1, 0), c) - - c = Complex(0, 1) ** 100000000000000000000000000000003 - assert_equal(Complex(0, -1), c) - - c = Complex(0, -1) ** 100000000000000000000000000000000 - assert_equal(Complex(1, 0), c) - - c = Complex(0, -1) ** 100000000000000000000000000000001 - assert_equal(Complex(0, -1), c) - - c = Complex(0, -1) ** 100000000000000000000000000000002 - assert_equal(Complex(-1, 0), c) - - c = Complex(0, -1) ** 100000000000000000000000000000003 - assert_equal(Complex(0, 1), c) - - c = Complex(1, 1) ** 1 - assert_equal(Complex(1, 1), c) - - c = Complex(1, 1) ** 2 - assert_equal(Complex(0, 2), c) - - c = Complex(1, 1) ** 3 - assert_equal(Complex(-2, 2), c) - - c = Complex(1, 1) ** 4 - assert_equal(Complex(-4, 0), c) - - c = Complex(1, 1) ** 5 - assert_equal(Complex(-4, -4), c) - - c = Complex(1, 1) ** 6 - assert_equal(Complex(0, -8), c) - - c = Complex(1, 1) ** 7 - assert_equal(Complex(8, -8), c) - - c = Complex(-2, -2) ** 3 - assert_equal(Complex(16, -16), c) - - c = Complex(2, -2) ** 3 - assert_equal(Complex(-16, -16), c) - - c = Complex(-2, 2) ** 3 - assert_equal(Complex(16, 16), c) c = Complex(0.0, -888888888888888.0)**8888 assert_not_predicate(c.real, :nan?) @@ -638,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 @@ -918,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) @@ -1232,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 bb38f8ec91..0000000000 --- a/test/ruby/test_data.rb +++ /dev/null @@ -1,283 +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([1, 2], test.deconstruct) - 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_equal({}, test.deconstruct_keys(%i[foo bar baz])) - assert_raise(TypeError) { test.deconstruct_keys(0) } - - assert_kind_of(Integer, test.hash) - end - - def test_hash - measure = Data.define(:amount, :unit) - - assert_equal(measure[1, 'km'].hash, measure[1, 'km'].hash) - assert_not_equal(measure[1, 'km'].hash, measure[10, 'km'].hash) - assert_not_equal(measure[1, 'km'].hash, measure[1, 'm'].hash) - assert_not_equal(measure[1, 'km'].hash, measure[1.0, 'km'].hash) - - # Structurally similar data class, but shouldn't be considered - # the same hash key - measurement = Data.define(:amount, :unit) - - assert_not_equal(measure[1, 'km'].hash, measurement[1, 'km'].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 026338f567..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,51 +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 - ret = root_dir.chdir do |*a| - assert_empty(a) - - 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) - - 42 - end - - assert_equal(42, ret) - ensure - begin - assert_equal(0, 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 @@ -202,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 @@ -554,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) @@ -566,62 +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 - - def test_home_at_startup_windows - env = {'HOME' => "C:\\ruby\\home"} - args = [env] - assert_separately(args, "#{<<~"begin;"}\n#{<<~'end;'}") - begin; - assert_equal("C:/ruby/home", Dir.home) - end; - - env['USERPROFILE'] = "C:\\ruby\\userprofile" - assert_separately(args, "#{<<~"begin;"}\n#{<<~'end;'}") - begin; - assert_equal("C:/ruby/home", Dir.home) - end; - - env['HOME'] = nil - assert_separately(args, "#{<<~"begin;"}\n#{<<~'end;'}") - begin; - assert_equal("C:/ruby/userprofile", Dir.home) - end; - - env['HOMEDRIVE'] = "C:" - env['HOMEPATH'] = "\\ruby\\homepath" - assert_separately(args, "#{<<~"begin;"}\n#{<<~'end;'}") - begin; - assert_equal("C:/ruby/userprofile", Dir.home) - end; - - env['USERPROFILE'] = nil - assert_separately(args, "#{<<~"begin;"}\n#{<<~'end;'}") - begin; - assert_equal("C:/ruby/homepath", Dir.home) - end; - 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 @@ -639,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 @@ -679,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 11cfe69864..c823b79c6d 100644 --- a/test/ruby/test_enumerator.rb +++ b/test/ruby/test_enumerator.rb @@ -127,16 +127,6 @@ class TestEnumerator < Test::Unit::TestCase assert_equal([[1,5],[2,6],[3,7]], @obj.to_enum(:foo, 1, 2, 3).with_index(5).to_a) end - def test_with_index_under_gc_compact_stress - EnvUtil.under_gc_compact_stress do - assert_equal([[1, 0], [2, 1], [3, 2]], @obj.to_enum(:foo, 1, 2, 3).with_index.to_a) - assert_equal([[1, 5], [2, 6], [3, 7]], @obj.to_enum(:foo, 1, 2, 3).with_index(5).to_a) - - s = 1 << (8 * 1.size - 2) - assert_equal([[1, s], [2, s + 1], [3, s + 2]], @obj.to_enum(:foo, 1, 2, 3).with_index(s).to_a) - end - end - def test_with_index_large_offset bug8010 = '[ruby-dev:47131] [Bug #8010]' s = 1 << (8*1.size-2) @@ -254,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 @@ -862,20 +832,6 @@ class TestEnumerator < Test::Unit::TestCase assert_equal(33, chain.next) end - def test_lazy_chain_under_gc_compact_stress - EnvUtil.under_gc_compact_stress do - ea = (10..).lazy.select(&:even?).take(10) - ed = (20..).lazy.select(&:odd?) - chain = (ea + ed).select{|x| x % 3 == 0} - assert_equal(12, chain.next) - assert_equal(18, chain.next) - assert_equal(24, chain.next) - assert_equal(21, chain.next) - assert_equal(27, chain.next) - assert_equal(33, chain.next) - end - end - def test_chain_undef_methods chain = [1].to_enum + [2].to_enum meths = (chain.methods & [:feed, :next, :next_values, :peek, :peek_values]) @@ -950,96 +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 - - def test_freeze - e = 3.times.freeze - assert_raise(FrozenError) { e.next } - assert_raise(FrozenError) { e.next_values } - assert_raise(FrozenError) { e.peek } - assert_raise(FrozenError) { e.peek_values } - assert_raise(FrozenError) { e.feed 1 } - assert_raise(FrozenError) { e.rewind } - 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 39b001c3d0..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,122 +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| - begin - reenable_gc = !GC.disable - GC.stat_heap(i, stat_heap) - GC.stat(stat) - ensure - GC.enable if reenable_gc - end - - 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 - omit "flaky with RJIT, which allocates objects itself" if defined?(RubyVM::RJIT) && RubyVM::RJIT.enabled? - 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_measure_total_time - assert_separately([], __FILE__, __LINE__, <<~RUBY) - GC.measure_total_time = false - - time_before = GC.stat(:time) - - # Generate some garbage - Random.new.bytes(100 * 1024 * 1024) - GC.start - - time_after = GC.stat(:time) - - # If time measurement is disabled, the time stat should not change - assert_equal time_before, time_after - RUBY - 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 @@ -267,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] @@ -285,82 +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 - - # Sometimes the WeakMap has one element, which might be held on by registers. - assert_operator(wmap.size, :<=, 1) - - 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)") @@ -370,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 @@ -382,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) @@ -400,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", @@ -424,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", @@ -453,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 @@ -586,28 +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 - - 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 - end - - def test_profiler_raw_data + skip "for now" + assert_separately %w[--disable-gem], __FILE__, __LINE__, <<-'eom', timeout: 30 GC::Profiler.enable + GC.start - assert GC::Profiler.raw_data - ensure - GC::Profiler.disable + 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) + eom end def test_profiler_total_time @@ -621,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 @@ -738,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 @@ -827,15 +484,6 @@ class TestGc < Test::Unit::TestCase obj = nil end end; - - assert_normal_exit "#{<<~"begin;"}\n#{<<~'end;'}", '[Bug #20042]' - begin; - def (f = Object.new).call = nil # missing ID - o = Object.new - ObjectSpace.define_finalizer(o, f) - o = nil - GC.start - end; end def test_object_ids_never_repeat @@ -851,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 f8ebba84b8..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,290 +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 = 50000 - - GC.verify_compaction_references(expand_heap: true, toward: :empty) - - Fiber.new { - $arys = ARY_COUNT.times.map do - ary = "abbbbbbbbbb".chars - ary.uniq! - end - }.resume - - stats = GC.verify_compaction_references(expand_heap: true, toward: :empty) - assert_operator(stats.dig(:moved_down, :T_ARRAY) || 0, :>=, ARY_COUNT - 10) - 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 = 50000 - - GC.verify_compaction_references(expand_heap: true, toward: :empty) - - Fiber.new { - ary = "hello".chars - $arys = ARY_COUNT.times.map do - x = [] - ary.each { |e| x << e } - x - end - }.resume - - stats = GC.verify_compaction_references(expand_heap: true, toward: :empty) - assert_operator(stats.dig(:moved_up, :T_ARRAY) || 0, :>=, ARY_COUNT - 10) - 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 - - 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 = 50000 - - GC.verify_compaction_references(expand_heap: true, toward: :empty) - - Fiber.new { - $ary = OBJ_COUNT.times.map { Foo.new } - $ary.each(&:add_ivars) - - GC.start - Foo.new.add_ivars - }.resume - - stats = GC.verify_compaction_references(expand_heap: true, toward: :empty) - - assert_operator(stats.dig(:moved_up, :T_OBJECT) || 0, :>=, OBJ_COUNT - 10) - 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: 30, signal: :SEGV) - begin; - STR_COUNT = 50000 - - GC.verify_compaction_references(expand_heap: true, toward: :empty) - - Fiber.new { - str = "a" * GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE] * 4 - $ary = STR_COUNT.times.map { "" << str } - }.resume - - stats = GC.verify_compaction_references(expand_heap: true, toward: :empty) - - assert_operator(stats[:moved_up][:T_STRING], :>=, STR_COUNT - 10) - 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: 30, signal: :SEGV) - begin; - STR_COUNT = 50000 - - GC.verify_compaction_references(expand_heap: true, toward: :empty) - - Fiber.new { - $ary = STR_COUNT.times.map { ("a" * GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE] * 4).squeeze! } - }.resume - - stats = GC.verify_compaction_references(expand_heap: true, toward: :empty) - - assert_operator(stats[:moved_down][:T_STRING], :>=, STR_COUNT - 10) - 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*"] - - assert_separately(%w[-robjspace], "#{<<~"begin;"}\n#{<<~"end;"}", timeout: 30, signal: :SEGV) - begin; - HASH_COUNT = 50000 - - GC.verify_compaction_references(expand_heap: true, toward: :empty) - - Fiber.new { - 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_with_index { |h, i| h[:i] = 9 } - }.resume - - stats = GC.verify_compaction_references(expand_heap: true, toward: :empty) - - assert_operator(stats[:moved_down][:T_HASH], :>=, HASH_COUNT - 10) - 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 c72b256bab..683ec3855d 100644 --- a/test/ruby/test_hash.rb +++ b/test/ruby/test_hash.rb @@ -4,6 +4,7 @@ require 'test/unit' EnvUtil.suppress_warning {require 'continuation'} class TestHash < Test::Unit::TestCase + def test_hash x = @cls[1=>2, 2=>4, 3=>6] y = @cls[1=>2, 2=>4, 3=>6] # y = {1, 2, 2, 4, 3, 6} # 1.9 doesn't support @@ -84,9 +85,20 @@ class TestHash < Test::Unit::TestCase self => 'self', true => 'true', nil => 'nil', 'nil' => nil ] + @verbose = $VERBOSE end def teardown + $VERBOSE = @verbose + end + + def test_bad_initialize_copy + h = Class.new(Hash) { + def initialize_copy(h) + super(Object.new) + end + }.new + assert_raise(TypeError) { h.dup } end def test_clear_initialize_copy @@ -101,6 +113,35 @@ class TestHash < Test::Unit::TestCase assert_equal(2, h[1]) end + def test_dup_will_not_rehash + assert_hash_does_not_rehash(&:dup) + end + + def assert_hash_does_not_rehash + obj = Object.new + class << obj + attr_accessor :hash_calls + def hash + @hash_calls += 1 + super + end + end + obj.hash_calls = 0 + hash = {obj => 42} + assert_equal(1, obj.hash_calls) + yield hash + assert_equal(1, obj.hash_calls) + end + + def test_select_reject_will_not_rehash + assert_hash_does_not_rehash do |hash| + hash.select { true } + end + assert_hash_does_not_rehash do |hash| + hash.reject { false } + end + end + def test_s_AREF_from_hash h = @cls["a" => 100, "b" => 200] assert_equal(100, h['a']) @@ -178,16 +219,6 @@ class TestHash < Test::Unit::TestCase assert_equal('default', h['spurious']) end - def test_st_literal_memory_leak - assert_no_memory_leak([], "", "#{<<~"begin;"}\n#{<<~'end;'}", rss: true) - begin; - 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")) @@ -263,6 +294,64 @@ class TestHash < Test::Unit::TestCase assert_equal(256, h[z]) end + def test_AREF_fstring_key + # warmup ObjectSpace.count_objects + ObjectSpace.count_objects + + h = {"abc" => 1} + before = ObjectSpace.count_objects[:T_STRING] + 5.times{ h["abc"] } + assert_equal before, ObjectSpace.count_objects[:T_STRING] + end + + def test_ASET_fstring_key + a, b = {}, {} + assert_equal 1, a["abc"] = 1 + assert_equal 1, b["abc"] = 1 + assert_same a.keys[0], b.keys[0] + end + + def test_ASET_fstring_non_literal_key + underscore = "_" + non_literal_strings = Proc.new{ ["abc#{underscore}def", "abc" * 5, "abc" + "def", "" << "ghi" << "jkl"] } + + a, b = {}, {} + non_literal_strings.call.each do |string| + assert_equal 1, a[string] = 1 + end + + non_literal_strings.call.each do |string| + assert_equal 1, b[string] = 1 + end + + [a.keys, b.keys].transpose.each do |key_a, key_b| + assert_same key_a, key_b + end + end + + def test_hash_aset_fstring_identity + h = {}.compare_by_identity + h['abc'] = 1 + h['abc'] = 2 + assert_equal 2, h.size, '[ruby-core:78783] [Bug #12855]' + end + + def test_hash_aref_fstring_identity + h = {}.compare_by_identity + h['abc'] = 1 + assert_nil h['abc'], '[ruby-core:78783] [Bug #12855]' + end + + def test_NEWHASH_fstring_key + a = {"ABC" => :t} + b = {"ABC" => :t} + assert_same a.keys[0], b.keys[0] + assert_same "ABC".freeze, a.keys[0] + var = +'ABC' + c = { var => :t } + assert_same "ABC".freeze, c.keys[0] + end + def test_EQUAL # '==' h1 = @cls[ "a" => 1, "c" => 2 ] h2 = @cls[ "a" => 1, "c" => 2, 7 => 35 ] @@ -369,10 +458,6 @@ class TestHash < Test::Unit::TestCase end end assert_equal(base.dup, h) - - h = base.dup - assert_same h, h.delete_if {h.assoc(nil); true} - assert_empty h end def test_keep_if @@ -743,6 +828,14 @@ class TestHash < Test::Unit::TestCase assert_predicate(h, :compare_by_identity?) end + def test_replace_bug15358 + h1 = {} + h2 = {a:1,b:2,c:3,d:4,e:5} + h2.replace(h1) + GC.start + assert(true) + end + def test_shift h = @h.dup @@ -858,6 +951,13 @@ class TestHash < Test::Unit::TestCase assert_instance_of(Hash, h) end + def test_nil_to_h + h = nil.to_h + assert_equal({}, h) + assert_nil(h.default) + assert_nil(h.default_proc) + end + def test_to_s h = @cls[ 1 => 2, "cat" => "dog", 1.5 => :fred ] assert_equal(h.inspect, h.to_s) @@ -904,6 +1004,12 @@ class TestHash < Test::Unit::TestCase assert_equal([], expected - vals) end + def test_initialize_wrong_arguments + assert_raise(ArgumentError) do + Hash.new(0) { } + end + end + def test_create assert_equal({1=>2, 3=>4}, @cls[[[1,2],[3,4]]]) assert_raise(ArgumentError) { @cls[0, 1, 2] } @@ -942,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) } @@ -960,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 @@ -1185,6 +1291,15 @@ class TestHash < Test::Unit::TestCase assert_raise(FrozenError) { h2.replace(42) } end + def test_replace_memory_leak + assert_no_memory_leak([], "#{<<-"begin;"}", "#{<<-'end;'}") + h = ("aa".."zz").each_with_index.to_h + 10_000.times {h.dup} + begin; + 500_000.times {h.dup.replace(h)} + end; + end + def test_size2 assert_equal(0, @cls[].size) end @@ -1458,16 +1573,6 @@ class TestHash < Test::Unit::TestCase assert_predicate(h.dup, :compare_by_identity?, bug8703) end - def test_compare_by_identy_memory_leak - assert_no_memory_leak([], "", "#{<<~"begin;"}\n#{<<~'end;'}", "[Bug #20145]", rss: true) - begin; - h = { 1 => 2 }.compare_by_identity - 1_000_000.times do - h.select { false } - end - end; - end - def test_same_key bug9646 = '[ruby-dev:48047] [Bug #9646] Infinite loop at Hash#each' h = @cls[a=[], 1] @@ -1598,6 +1703,124 @@ class TestHash < Test::Unit::TestCase end end + def test_exception_in_rehash_memory_leak + return unless @cls == Hash + + bug9187 = '[ruby-core:58728] [Bug #9187]' + + prepare = <<-EOS + class Foo + def initialize + @raise = false + end + + def hash + raise if @raise + @raise = true + return 0 + end + end + h = {Foo.new => true} + EOS + + code = <<-EOS + 10_0000.times do + h.rehash rescue nil + end + GC.start + EOS + + 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]' + + wrapper = Class.new do + def initialize(obj) + @obj = obj + end + + def hash + @obj.hash + end + + def eql?(other) + @obj.eql?(other) + end + end + + bad = [ + 5, true, false, nil, + 0.0, 1.72723e-77, + :foo, "dsym_#{self.object_id.to_s(16)}_#{Time.now.to_i.to_s(16)}".to_sym, + "str", + ].select do |x| + hash = {x => bug9381} + hash[wrapper.new(x)] != bug9381 + end + assert_empty(bad, bug9381) + end + + def assert_hash_random(obj, dump = obj.inspect) + a = [obj.hash.to_s] + 3.times { + assert_in_out_err(["-e", "print (#{dump}).hash"], "") do |r, e| + a += r + assert_equal([], e) + end + } + assert_not_equal([obj.hash.to_s], a.uniq) + assert_operator(a.uniq.size, :>, 2, proc {a.inspect}) + end + + def test_string_hash_random + assert_hash_random('abc') + end + + def test_symbol_hash_random + assert_hash_random(:-) + assert_hash_random(:foo) + assert_hash_random("dsym_#{self.object_id.to_s(16)}_#{Time.now.to_i.to_s(16)}".to_sym) + end + + def test_integer_hash_random + assert_hash_random(0) + assert_hash_random(+1) + assert_hash_random(-1) + assert_hash_random(+(1<<100)) + assert_hash_random(-(1<<100)) + end + + def test_float_hash_random + assert_hash_random(0.0) + assert_hash_random(+1.0) + assert_hash_random(-1.0) + assert_hash_random(1.72723e-77) + assert_hash_random(Float::INFINITY, "Float::INFINITY") + end + + def test_label_syntax + return unless @cls == Hash + + feature4935 = '[ruby-core:37553] [Feature #4935]' + x = 'world' + hash = assert_nothing_raised(SyntaxError, feature4935) do + break eval(%q({foo: 1, "foo-bar": 2, "hello-#{x}": 3, 'hello-#{x}': 4, 'bar': {}})) + end + assert_equal({:foo => 1, :'foo-bar' => 2, :'hello-world' => 3, :'hello-#{x}' => 4, :bar => {}}, hash, feature4935) + x = x + end + def test_dig h = @cls[a: @cls[b: [1, 2, 3]], c: 4] assert_equal(1, h.dig(:a, :b, 0)) @@ -1617,12 +1840,12 @@ class TestHash < Test::Unit::TestCase def o.respond_to?(*args) super end - assert_raise(TypeError, bug12030) {@cls[foo: o].dig(:foo, :foo)} + assert_raise(TypeError, bug12030) {{foo: o}.dig(:foo, :foo)} end def test_cmp - h1 = @cls[a:1, b:2] - h2 = @cls[a:1, b:2, c:3] + h1 = {a:1, b:2} + h2 = {a:1, b:2, c:3} assert_operator(h1, :<=, h1) assert_operator(h1, :<=, h2) @@ -1646,8 +1869,8 @@ class TestHash < Test::Unit::TestCase end def test_cmp_samekeys - h1 = @cls[a:1] - h2 = @cls[a:2] + h1 = {a:1} + h2 = {a:2} assert_operator(h1, :<=, h1) assert_not_operator(h1, :<=, h2) @@ -1671,15 +1894,15 @@ class TestHash < Test::Unit::TestCase end def test_to_proc - h = @cls[ + h = { 1 => 10, 2 => 20, 3 => 30, - ] + } assert_equal([10, 20, 30], [1, 2, 3].map(&h)) - assert_predicate(h.to_proc, :lambda?) + assert_equal(true, h.to_proc.lambda?) end def test_transform_keys @@ -1809,6 +2032,22 @@ class TestHash < Test::Unit::TestCase assert_equal(@cls[a: 2, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8, i: 9, j: 10], x) end + def test_broken_hash_value + bug14218 = '[ruby-core:84395] [Bug #14218]' + + assert_equal(0, 1_000_000.times.count{a=Object.new.hash; b=Object.new.hash; a < 0 && b < 0 && a + b > 0}, bug14218) + assert_equal(0, 1_000_000.times.count{a=Object.new.hash; b=Object.new.hash; 0 + a + b != 0 + b + a}, bug14218) + end + + def test_reserved_hash_val + s = Struct.new(:hash) + h = {} + keys = [*0..8] + keys.each {|i| h[s.new(i)]=true} + msg = proc {h.inspect} + assert_equal(keys, h.keys.map(&:hash), msg) + end + def hrec h, n, &b if n > 0 h.each{hrec(h, n-1, &b)} @@ -1838,27 +2077,6 @@ class TestHash < Test::Unit::TestCase # ignore 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 - class TestSubHash < TestHash class SubHash < Hash end @@ -1868,341 +2086,6 @@ class TestHash < Test::Unit::TestCase super end end -end - -class TestHashOnly < Test::Unit::TestCase - def test_bad_initialize_copy - h = Class.new(Hash) { - def initialize_copy(h) - super(Object.new) - end - }.new - assert_raise(TypeError) { h.dup } - end - - def test_dup_will_not_rehash - assert_hash_does_not_rehash(&:dup) - end - - def assert_hash_does_not_rehash - obj = Object.new - class << obj - attr_accessor :hash_calls - def hash - @hash_calls += 1 - super - end - end - obj.hash_calls = 0 - hash = {obj => 42} - assert_equal(1, obj.hash_calls) - yield hash - assert_equal(1, obj.hash_calls) - end - - def test_select_reject_will_not_rehash - assert_hash_does_not_rehash do |hash| - hash.select { true } - end - assert_hash_does_not_rehash do |hash| - hash.reject { false } - end - end - - def test_st_literal_memory_leak - assert_no_memory_leak([], "", "#{<<~"begin;"}\n#{<<~'end;'}", rss: true) - begin; - 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_compare_by_id_memory_leak - assert_no_memory_leak([], "", <<~RUBY, rss: true) - 1_000_000.times do - {a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8}.compare_by_identity - end - RUBY - end - - def test_try_convert - assert_equal({1=>2}, Hash.try_convert({1=>2})) - assert_equal(nil, Hash.try_convert("1=>2")) - o = Object.new - def o.to_hash; {3=>4} end - assert_equal({3=>4}, Hash.try_convert(o)) - end - - def test_AREF_fstring_key - # warmup ObjectSpace.count_objects - ObjectSpace.count_objects - - h = {"abc" => 1} - before = ObjectSpace.count_objects[:T_STRING] - 5.times{ h["abc"] } - 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 - assert_equal 1, b["abc"] = 1 - assert_same a.keys[0], b.keys[0] - end - - def test_ASET_fstring_non_literal_key - underscore = "_" - non_literal_strings = Proc.new{ ["abc#{underscore}def", "abc" * 5, "abc" + "def", "" << "ghi" << "jkl"] } - - a, b = {}, {} - non_literal_strings.call.each do |string| - assert_equal 1, a[string] = 1 - end - - non_literal_strings.call.each do |string| - assert_equal 1, b[string] = 1 - end - - [a.keys, b.keys].transpose.each do |key_a, key_b| - assert_same key_a, key_b - end - end - - def test_hash_aset_fstring_identity - h = {}.compare_by_identity - h['abc'] = 1 - h['abc'] = 2 - assert_equal 2, h.size, '[ruby-core:78783] [Bug #12855]' - end - - def test_hash_aref_fstring_identity - h = {}.compare_by_identity - h['abc'] = 1 - assert_nil h['abc'], '[ruby-core:78783] [Bug #12855]' - end - - def test_NEWHASH_fstring_key - a = {"ABC" => :t} - b = {"ABC" => :t} - assert_same a.keys[0], b.keys[0] - assert_same "ABC".freeze, a.keys[0] - var = +'ABC' - c = { var => :t } - assert_same "ABC".freeze, c.keys[0] - end - - def test_rehash_memory_leak - assert_no_memory_leak([], <<~PREP, <<~CODE, rss: true) - ar_hash = 1.times.map { |i| [i, i] }.to_h - st_hash = 10.times.map { |i| [i, i] }.to_h - - code = proc do - ar_hash.rehash - st_hash.rehash - end - 1_000.times(&code) - PREP - 1_000_000.times(&code) - CODE - end - - def test_replace_bug15358 - h1 = {} - h2 = {a:1,b:2,c:3,d:4,e:5} - h2.replace(h1) - GC.start - 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_nil_to_h - h = nil.to_h - assert_equal({}, h) - assert_nil(h.default) - assert_nil(h.default_proc) - end - - def test_initialize_wrong_arguments - assert_raise(ArgumentError) do - Hash.new(0) { } - end - end - - def test_replace_memory_leak - assert_no_memory_leak([], "#{<<-"begin;"}", "#{<<-'end;'}", rss: true) - h = ("aa".."zz").each_with_index.to_h - 10_000.times {h.dup} - begin; - 500_000.times {h.dup.replace(h)} - 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) - assert true - end - - def test_exception_in_rehash_memory_leak - bug9187 = '[ruby-core:58728] [Bug #9187]' - - prepare = <<-EOS - class Foo - def initialize - @raise = false - end - - def hash - raise if @raise - @raise = true - return 0 - end - end - h = {Foo.new => true} - EOS - - code = <<-EOS - 10_0000.times do - h.rehash rescue nil - end - GC.start - EOS - - 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]' - - wrapper = Class.new do - def initialize(obj) - @obj = obj - end - - def hash - @obj.hash - end - - def eql?(other) - @obj.eql?(other) - end - end - - bad = [ - 5, true, false, nil, - 0.0, 1.72723e-77, - :foo, "dsym_#{self.object_id.to_s(16)}_#{Time.now.to_i.to_s(16)}".to_sym, - "str", - ].select do |x| - hash = {x => bug9381} - hash[wrapper.new(x)] != bug9381 - end - assert_empty(bad, bug9381) - end - - def assert_hash_random(obj, dump = obj.inspect) - a = [obj.hash.to_s] - 3.times { - assert_in_out_err(["-e", "print (#{dump}).hash"], "") do |r, e| - a += r - assert_equal([], e) - end - } - assert_not_equal([obj.hash.to_s], a.uniq) - assert_operator(a.uniq.size, :>, 2, proc {a.inspect}) - end - - def test_string_hash_random - assert_hash_random('abc') - end - - def test_symbol_hash_random - assert_hash_random(:-) - assert_hash_random(:foo) - assert_hash_random("dsym_#{self.object_id.to_s(16)}_#{Time.now.to_i.to_s(16)}".to_sym) - end - - def test_integer_hash_random - assert_hash_random(0) - assert_hash_random(+1) - assert_hash_random(-1) - assert_hash_random(+(1<<100)) - assert_hash_random(-(1<<100)) - end - - def test_float_hash_random - assert_hash_random(0.0) - assert_hash_random(+1.0) - assert_hash_random(-1.0) - assert_hash_random(1.72723e-77) - assert_hash_random(Float::INFINITY, "Float::INFINITY") - end - - def test_label_syntax - feature4935 = '[ruby-core:37553] [Feature #4935]' - x = 'world' - hash = assert_nothing_raised(SyntaxError, feature4935) do - break eval(%q({foo: 1, "foo-bar": 2, "hello-#{x}": 3, 'hello-#{x}': 4, 'bar': {}})) - end - assert_equal({:foo => 1, :'foo-bar' => 2, :'hello-world' => 3, :'hello-#{x}' => 4, :bar => {}}, hash, feature4935) - x = x - end - - def test_broken_hash_value - bug14218 = '[ruby-core:84395] [Bug #14218]' - - assert_equal(0, 1_000_000.times.count{a=Object.new.hash; b=Object.new.hash; a < 0 && b < 0 && a + b > 0}, bug14218) - assert_equal(0, 1_000_000.times.count{a=Object.new.hash; b=Object.new.hash; 0 + a + b != 0 + b + a}, bug14218) - end - - def test_reserved_hash_val - s = Struct.new(:hash) - h = {} - keys = [*0..8] - keys.each {|i| h[s.new(i)]=true} - msg = proc {h.inspect} - assert_equal(keys, h.keys.map(&:hash), msg) - end ruby2_keywords def get_flagged_hash(*args) args.last @@ -2228,11 +2111,23 @@ class TestHashOnly < Test::Unit::TestCase assert_raise(TypeError) { Hash.ruby2_keywords_hash(1) } end - def ar2st_object - class << (obj = Object.new) - attr_reader :h + def test_ar2st + # insert + obj = Object.new + obj.instance_variable_set(:@h, h = {}) + def obj.hash + 10.times{|i| @h[i] = i} + 0 end - obj.instance_variable_set(:@h, {}) + def obj.inspect + 'test' + end + h[obj] = true + assert_equal '{0=>0, 1=>1, 2=>2, 3=>3, 4=>4, 5=>5, 6=>6, 7=>7, 8=>8, 9=>9, test=>true}', h.inspect + + # delete + obj = Object.new + obj.instance_variable_set(:@h, h = {}) def obj.hash 10.times{|i| @h[i] = i} 0 @@ -2243,21 +2138,6 @@ class TestHashOnly < Test::Unit::TestCase def obj.eql? other other.class == Object end - obj - end - - def test_ar2st_insert - obj = ar2st_object - h = obj.h - - h[obj] = true - assert_equal '{0=>0, 1=>1, 2=>2, 3=>3, 4=>4, 5=>5, 6=>6, 7=>7, 8=>8, 9=>9, test=>true}', h.inspect - end - - def test_ar2st_delete - obj = ar2st_object - h = obj.h - obj2 = Object.new def obj2.hash 0 @@ -2266,12 +2146,20 @@ class TestHashOnly < Test::Unit::TestCase h[obj2] = true h.delete obj assert_equal '{0=>0, 1=>1, 2=>2, 3=>3, 4=>4, 5=>5, 6=>6, 7=>7, 8=>8, 9=>9}', h.inspect - end - - def test_ar2st_lookup - obj = ar2st_object - h = obj.h + # lookup + obj = Object.new + obj.instance_variable_set(:@h, h = {}) + def obj.hash + 10.times{|i| @h[i] = i} + 0 + end + def obj.inspect + 'test' + end + def obj.eql? other + other.class == Object + end obj2 = Object.new def obj2.hash 0 @@ -2312,35 +2200,4 @@ class TestHashOnly < Test::Unit::TestCase end; end end - - def test_compare_by_identity_during_iteration - h = { 1 => 1 } - h.each do - assert_raise(RuntimeError, "compare_by_identity during iteration") do - h.compare_by_identity - end - end - end - - def test_ar_hash_to_st_hash - assert_normal_exit("#{<<~"begin;"}\n#{<<~'end;'}", 'https://bugs.ruby-lang.org/issues/20050#note-5') - begin; - srand(0) - class Foo - def to_a - [] - end - - def hash - $h.delete($h.keys.sample) if rand < 0.1 - to_a.hash - end - end - - 1000.times do - $h = {} - (0..10).each {|i| $h[Foo.new] ||= {} } - end - end; - end end diff --git a/test/ruby/test_integer.rb b/test/ruby/test_integer.rb index 3349a1c493..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 @@ -704,14 +674,6 @@ class TestInteger < Test::Unit::TestCase def test_fdiv assert_equal(1.0, 1.fdiv(1)) assert_equal(0.5, 1.fdiv(2)) - - m = 50 << Float::MANT_DIG - prev = 1.0 - (1..100).each do |i| - val = (m + i).fdiv(m) - assert_operator val, :>=, prev, "1+epsilon*(#{i}/100)" - prev = val - end end def test_obj_fdiv @@ -740,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 476d9f882f..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!" @@ -1898,110 +1850,6 @@ class TestIO < Test::Unit::TestCase end) end - def test_readline_bad_param_raises - File.open(__FILE__) do |f| - assert_raise(TypeError) do - f.readline Object.new - end - end - - File.open(__FILE__) do |f| - assert_raise(TypeError) do - f.readline 1, 2 - end - end - end - - def test_readline_raises - File.open(__FILE__) do |f| - assert_equal File.read(__FILE__), f.readline(nil) - assert_raise(EOFError) do - f.readline - end - end - end - - def test_readline_separators - File.open(__FILE__) do |f| - line = f.readline("def") - assert_equal File.read(__FILE__)[/\A.*?def/m], line - end - - File.open(__FILE__) do |f| - line = f.readline("def", chomp: true) - assert_equal File.read(__FILE__)[/\A.*?(?=def)/m], line - end - end - - def test_readline_separators_limits - t = Tempfile.open("readline_limit") - str = "#" * 50 - sep = "def" - - t.write str - t.write sep - t.write str - t.flush - - # over limit - File.open(t.path) do |f| - line = f.readline sep, str.bytesize - assert_equal(str, line) - end - - # under limit - File.open(t.path) do |f| - line = f.readline(sep, str.bytesize + 5) - assert_equal(str + sep, line) - end - - # under limit + chomp - File.open(t.path) do |f| - line = f.readline(sep, str.bytesize + 5, chomp: true) - assert_equal(str, line) - end - ensure - t&.close! - end - - def test_readline_limit_without_separator - t = Tempfile.open("readline_limit") - str = "#" * 50 - sep = "\n" - - t.write str - t.write sep - t.write str - t.flush - - # over limit - File.open(t.path) do |f| - line = f.readline str.bytesize - assert_equal(str, line) - end - - # under limit - File.open(t.path) do |f| - line = f.readline(str.bytesize + 5) - assert_equal(str + sep, line) - end - - # under limit + chomp - File.open(t.path) do |f| - line = f.readline(str.bytesize + 5, chomp: true) - assert_equal(str, line) - end - ensure - t&.close! - end - - def test_readline_chomp_true - File.open(__FILE__) do |f| - line = f.readline(chomp: true) - assert_equal File.readlines(__FILE__).first.chomp, line - end - end - def test_set_lineno_readline pipe(proc do |w| w.puts "foo" @@ -2046,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 @@ -2365,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 @@ -2451,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' @@ -2465,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 @@ -2481,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 @@ -2516,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 @@ -2542,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 @@ -2729,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| @@ -2773,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) @@ -2783,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 @@ -2794,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 @@ -2860,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 @@ -2981,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 @@ -3290,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) @@ -3499,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="" @@ -3625,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 @@ -3768,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 @@ -3929,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; @@ -3960,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]' @@ -4056,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 @@ -4091,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| @@ -4100,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' @@ -4126,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 7a58ec0c5a..c1034efe34 100644 --- a/test/ruby/test_io_buffer.rb +++ b/test/ruby/test_io_buffer.rb @@ -80,7 +80,7 @@ class TestIOBuffer < Test::Unit::TestCase end def test_file_mapped_invalid - assert_raise TypeError do + assert_raise NoMethodError do IO::Buffer.map("foobar") end end @@ -102,6 +102,11 @@ class TestIOBuffer < Test::Unit::TestCase IO::Buffer.for(string) do |buffer| refute buffer.readonly? + # Cannot modify string as it's locked by the buffer: + assert_raise RuntimeError do + string[0] = "h" + end + buffer.set_value(:U8, 0, "h".ord) # Buffer releases it's ownership of the string: @@ -111,16 +116,6 @@ class TestIOBuffer < Test::Unit::TestCase end end - def test_string_mapped_buffer_locked - string = "Hello World" - IO::Buffer.for(string) do |buffer| - # Cannot modify string as it's locked by the buffer: - assert_raise RuntimeError do - string[0] = "h" - end - end - end - def test_non_string not_string = Object.new @@ -129,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 @@ -199,14 +180,6 @@ class TestIOBuffer < Test::Unit::TestCase assert_positive buffer2 <=> buffer1 end - def test_compare_zero_length - buffer1 = IO::Buffer.new(0) - buffer2 = IO::Buffer.new(1) - - assert_negative buffer1 <=> buffer2 - assert_positive buffer2 <=> buffer1 - end - def test_slice buffer = IO::Buffer.new(128) slice = buffer.slice(8, 32) @@ -214,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 @@ -265,25 +228,13 @@ class TestIOBuffer < Test::Unit::TestCase chunk = buffer.get_string(0, message.bytesize, Encoding::BINARY) assert_equal Encoding::BINARY, chunk.encoding - assert_raise_with_message(ArgumentError, /bigger than the buffer size/) do + assert_raise_with_message(ArgumentError, /exceeds buffer size/) do buffer.get_string(0, 129) end - assert_raise_with_message(ArgumentError, /bigger than the buffer size/) do + assert_raise_with_message(ArgumentError, /exceeds buffer size/) do buffer.get_string(129) end - - assert_raise_with_message(ArgumentError, /Offset can't be negative/) do - buffer.get_string(-1) - end - end - - def test_zero_length_get_string - buffer = IO::Buffer.new.slice(0, 0) - assert_equal "", buffer.get_string - - buffer = IO::Buffer.new(0) - assert_equal "", buffer.get_string end # We check that values are correctly round tripped. @@ -310,78 +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_zero_length_get_set_values - buffer = IO::Buffer.new(0) - - assert_equal [], buffer.get_values([], 0) - assert_equal 0, buffer.set_values([], 0, []) - 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_zero_length_each - buffer = IO::Buffer.new(0) - - assert_equal [], buffer.each(:U8).to_a - 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_zero_length_each_byte - buffer = IO::Buffer.new(0) - - assert_equal [], buffer.each_byte.to_a - end - def test_clear buffer = IO::Buffer.new(16) buffer.set_string("Hello World!") @@ -413,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 @@ -452,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) @@ -466,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 @@ -474,26 +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) + buffer.pwrite(io, 5, 6) assert_equal 0, io.tell @@ -502,74 +357,4 @@ class TestIOBuffer < Test::Unit::TestCase 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) - - assert_equal 0, io.tell - - io.seek(6) - assert_equal "World", io.read(5) - 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 - - def test_private - Tempfile.create(%w"buffer .txt") do |file| - file.write("Hello World") - - buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::PRIVATE) - begin - assert buffer.private? - refute buffer.readonly? - - buffer.set_string("J") - - # It was not changed because the mapping was private: - file.seek(0) - assert_equal "Hello World", file.read - ensure - buffer&.free - end - end - 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 b0896511d8..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,53 +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 - - def test_loading_kwargs_memory_leak - assert_no_memory_leak([], "#{<<~"begin;"}", "#{<<~'end;'}", rss: true) - a = RubyVM::InstructionSequence.compile("foo(bar: :baz)").to_binary - begin; - 1_000_000.times do - RubyVM::InstructionSequence.load_from_binary(a) - end - end; - end - - def test_ibf_bignum - iseq = RubyVM::InstructionSequence.compile("0x0"+"_0123_4567_89ab_cdef"*5) - expected = iseq.eval - result = RubyVM::InstructionSequence.load_from_binary(iseq.to_binary).eval - assert_equal expected, result, proc {sprintf("expected: %x, result: %x", expected, result)} - end - - def test_compile_prism_with_file - Tempfile.create(%w"test_iseq .rb") do |f| - f.puts "name = 'Prism'; puts 'hello" - f.close - - assert_nothing_raised(SyntaxError) { - RubyVM::InstructionSequence.compile_prism(f.path) - } - 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 9aca787dff..9094259bc2 100644 --- a/test/ruby/test_keyword.rb +++ b/test/ruby/test_keyword.rb @@ -190,74 +190,27 @@ 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 assert_equal_not_same(kw, res) - assert_instance_of(Hash, res) - assert_equal(kw, res) - assert_not_same(kw, res) - end - def test_keyword_splat_new kw = {} h = {a: 1} - 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.assert_equal_not_same(kw, res) + assert_instance_of(Hash, res) + assert_equal(kw, res) + assert_not_same(kw, res) + end + + 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,41 +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) - end - - def test_keyword_splat_to_non_keyword_method - h = {a: 1}.freeze - - def self.yo(kw) kw end - assert_equal_not_same(h, yo(**h)) - assert_equal_not_same(h, method(:yo).(**h)) - assert_equal_not_same(h, :yo.to_proc.(self, **h)) - - def self.yoa(*kw) kw[0] end - assert_equal_not_same(h, yoa(**h)) - assert_equal_not_same(h, method(:yoa).(**h)) - assert_equal_not_same(h, :yoa.to_proc.(self, **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 @@ -3609,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 90635bc5e5..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) { @@ -450,17 +439,6 @@ class TestMethod < Test::Unit::TestCase assert_equal(:bar, m.clone.bar) end - def test_clone_under_gc_compact_stress - EnvUtil.under_gc_compact_stress do - o = Object.new - def o.foo; :foo; end - m = o.method(:foo) - def m.bar; :bar; end - assert_equal(:foo, m.clone.call) - assert_equal(:bar, m.clone.bar) - end - end - def test_inspect o = Object.new def o.foo; end; line_no = __LINE__ @@ -588,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) @@ -614,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) @@ -641,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) @@ -665,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) @@ -782,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)) @@ -1226,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 } @@ -1255,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 @@ -1300,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 @@ -1308,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 @@ -1333,7 +1322,6 @@ class TestMethod < Test::Unit::TestCase m2 = c2.instance_method(:foo) c1.class_exec do - remove_method :foo def foo [:bar2] end @@ -1374,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]' @@ -1442,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 @@ -1469,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 @@ -1490,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) @@ -1576,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 @@ -1614,12 +1602,4 @@ class TestMethod < Test::Unit::TestCase def test_invalidating_CC_ASAN assert_ruby_status(['-e', 'using Module.new']) end - - def test_kwarg_eval_memory_leak - assert_no_memory_leak([], "", <<~RUBY, rss: true, limit: 1.2) - 100_000.times do - eval("Hash.new(foo: 123)") - end - RUBY - end end diff --git a/test/ruby/test_module.rb b/test/ruby/test_module.rb index 4722fa22e0..b5414d139e 100644 --- a/test/ruby/test_module.rb +++ b/test/ruby/test_module.rb @@ -253,14 +253,6 @@ class TestModule < Test::Unit::TestCase assert_operator(Math, :const_defined?, "PI") assert_not_operator(Math, :const_defined?, :IP) assert_not_operator(Math, :const_defined?, "IP") - - # Test invalid symbol name - # [Bug #20245] - EnvUtil.under_gc_stress do - assert_raise(EncodingError) do - Math.const_defined?("\xC3") - end - end end def each_bad_constants(m, &b) @@ -543,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 @@ -580,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| @@ -784,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) @@ -1002,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} @@ -1336,6 +1280,8 @@ class TestModule < Test::Unit::TestCase end end include LangModuleSpecInObject + module LangModuleTop + end puts "ok" if LangModuleSpecInObject::LangModuleTop == LangModuleTop INPUT @@ -1736,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 @@ -2360,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") @@ -2878,7 +2771,6 @@ class TestModule < Test::Unit::TestCase def test_invalid_attr %W[ - foo= foo? @foo @@foo @@ -3183,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/) { @@ -3301,7 +3192,7 @@ class TestModule < Test::Unit::TestCase end def test_complemented_method_entry_memory_leak - # [Bug #19894] [Bug #19896] + # [Bug #19894] assert_no_memory_leak([], <<~PREP, <<~CODE, rss: true) code = proc do $c = Class.new do @@ -3325,19 +3216,7 @@ class TestModule < Test::Unit::TestCase end 1_000.times(&code) PREP - 300_000.times(&code) - CODE - end - - def test_module_clone_memory_leak - # [Bug #19901] - assert_no_memory_leak([], <<~PREP, <<~CODE, rss: true) - code = proc do - Module.new.clone - end - 1_000.times(&code) - PREP - 1_000_000.times(&code) + 100_000.times(&code) CODE end @@ -3348,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 0bb9e633a1..83208bbcdb 100644 --- a/test/ruby/test_object.rb +++ b/test/ruby/test_object.rb @@ -355,41 +355,6 @@ class TestObject < Test::Unit::TestCase end end - def test_remove_instance_variable_re_embed - require "objspace" - - c = Class.new do - def a = @a - - def b = @b - - def c = @c - end - - o1 = c.new - o2 = c.new - - o1.instance_variable_set(:@foo, 5) - o1.instance_variable_set(:@a, 0) - o1.instance_variable_set(:@b, 1) - o1.instance_variable_set(:@c, 2) - refute_includes ObjectSpace.dump(o1), '"embedded":true' - o1.remove_instance_variable(:@foo) - assert_includes ObjectSpace.dump(o1), '"embedded":true' - - o2.instance_variable_set(:@a, 0) - o2.instance_variable_set(:@b, 1) - o2.instance_variable_set(:@c, 2) - assert_includes ObjectSpace.dump(o2), '"embedded":true' - - assert_equal(0, o1.a) - assert_equal(1, o1.b) - assert_equal(2, o1.c) - assert_equal(0, o2.a) - assert_equal(1, o2.b) - assert_equal(2, o2.c) - end - def test_convert_string o = Object.new def o.to_s; 1; end @@ -457,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(), /The class Foo reached 8 shape variations, instance variables accesses will be slower and memory usage increased/) - $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 @@ -900,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 @@ -981,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| @@ -1062,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 70b6bde6ed..43795d150c 100644 --- a/test/ruby/test_optimization.rb +++ b/test/ruby/test_optimization.rb @@ -437,31 +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_and_post_arg - tailcall(<<~RUBY) - def ret_const = :ok - - def post_arg(_a = 1, _b) = ret_const - RUBY - - # YJIT probably uses a fallback on the call to post_arg - assert_equal(:ok, post_arg(0)) - end - def test_tailcall_interrupted_by_sigint bug12576 = 'ruby-core:76327' script = "#{<<-"begin;"}\n#{<<~'end;'}" @@ -535,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 1ce46e8916..9738f82b7e 100644 --- a/test/ruby/test_pack.rb +++ b/test/ruby/test_pack.rb @@ -1,44 +1,25 @@ # coding: US-ASCII # frozen_string_literal: false require 'test/unit' -require 'rbconfig' -require 'rbconfig/sizeof' class TestPack < Test::Unit::TestCase - # Note: the size of intptr_t and uintptr_t should be equal. - J_SIZE = RbConfig::SIZEOF['uintptr_t'] - 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) - - 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_match(/def/, $x) - assert_raise(Encoding::CompatibilityError) do - "foo".unpack("C".encode("UTF-32BE")) - end + $x = [-1073741825] + assert_equal($x, $x.pack("q").unpack("q")) - 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 @@ -98,11 +79,11 @@ class TestPack < Test::Unit::TestCase assert_equal("\x01\x02\x03\x04", [0x01020304].pack("L"+mod)) assert_equal("\x01\x02\x03\x04\x05\x06\x07\x08", [0x0102030405060708].pack("q"+mod)) assert_equal("\x01\x02\x03\x04\x05\x06\x07\x08", [0x0102030405060708].pack("Q"+mod)) - case J_SIZE - when 4 + psize = [nil].pack('p').bytesize + if psize == 4 assert_equal("\x01\x02\x03\x04", [0x01020304].pack("j"+mod)) assert_equal("\x01\x02\x03\x04", [0x01020304].pack("J"+mod)) - when 8 + elsif psize == 8 assert_equal("\x01\x02\x03\x04\x05\x06\x07\x08", [0x0102030405060708].pack("j"+mod)) assert_equal("\x01\x02\x03\x04\x05\x06\x07\x08", [0x0102030405060708].pack("J"+mod)) end @@ -114,11 +95,10 @@ class TestPack < Test::Unit::TestCase assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("I!"+mod)) assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("l!"+mod)) assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("L!"+mod)) - case J_SIZE - when 4 + if psize == 4 assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("j!"+mod)) assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("J!"+mod)) - when 8 + elsif psize == 8 assert_match(/\A\x00*\x01\x02\x03\x04\x05\x06\x07\x08\z/, [0x0102030405060708].pack("j!"+mod)) assert_match(/\A\x00*\x01\x02\x03\x04\x05\x06\x07\x08\z/, [0x0102030405060708].pack("J!"+mod)) end @@ -147,11 +127,11 @@ class TestPack < Test::Unit::TestCase assert_equal("\x04\x03\x02\x01", [0x01020304].pack("L"+mod)) assert_equal("\x08\x07\x06\x05\x04\x03\x02\x01", [0x0102030405060708].pack("q"+mod)) assert_equal("\x08\x07\x06\x05\x04\x03\x02\x01", [0x0102030405060708].pack("Q"+mod)) - case J_SIZE - when 4 + psize = [nil].pack('p').bytesize + if psize == 4 assert_equal("\x04\x03\x02\x01", [0x01020304].pack("j"+mod)) assert_equal("\x04\x03\x02\x01", [0x01020304].pack("J"+mod)) - when 8 + elsif psize == 8 assert_equal("\x08\x07\x06\x05\x04\x03\x02\x01", [0x0102030405060708].pack("j"+mod)) assert_equal("\x08\x07\x06\x05\x04\x03\x02\x01", [0x0102030405060708].pack("J"+mod)) end @@ -163,11 +143,10 @@ class TestPack < Test::Unit::TestCase assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("I!"+mod)) assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("l!"+mod)) assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("L!"+mod)) - case J_SIZE - when 4 + if psize == 4 assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("j!"+mod)) assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("J!"+mod)) - when 8 + elsif psize == 8 assert_match(/\A\x08\x07\x06\x05\x04\x03\x02\x01\x00*\z/, [0x0102030405060708].pack("j!"+mod)) assert_match(/\A\x08\x07\x06\x05\x04\x03\x02\x01\x00*\z/, [0x0102030405060708].pack("J!"+mod)) end @@ -203,8 +182,8 @@ class TestPack < Test::Unit::TestCase end def test_integer_endian_explicit - _integer_big_endian('>') - _integer_little_endian('<') + _integer_big_endian('>') + _integer_little_endian('<') end def test_pack_U @@ -449,6 +428,7 @@ class TestPack < Test::Unit::TestCase assert_operator(4, :<=, [1].pack("L!").bytesize) end + require 'rbconfig' def test_pack_unpack_qQ s1 = [578437695752307201, -506097522914230529].pack("q*") s2 = [578437695752307201, 17940646550795321087].pack("Q*") @@ -471,8 +451,10 @@ class TestPack < Test::Unit::TestCase end if RbConfig::CONFIG['HAVE_LONG_LONG'] def test_pack_unpack_jJ - case J_SIZE - when 4 + # Note: we assume that the size of intptr_t and uintptr_t equals to the size + # of real pointer. + psize = [nil].pack("p").bytesize + if psize == 4 s1 = [67305985, -50462977].pack("j*") s2 = [67305985, 4244504319].pack("J*") assert_equal(s1, s2) @@ -486,7 +468,7 @@ class TestPack < Test::Unit::TestCase assert_equal(4, [1].pack("j").bytesize) assert_equal(4, [1].pack("J").bytesize) - when 8 + elsif psize == 8 s1 = [578437695752307201, -506097522914230529].pack("j*") s2 = [578437695752307201, 17940646550795321087].pack("J*") assert_equal(s1, s2) @@ -781,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 c2f02ff809..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 @@ -453,44 +452,10 @@ class TestParse < Test::Unit::TestCase end def test_define_singleton_error - msg = /singleton method for literals/ - assert_parse_error(%q[def ("foo").foo; end], msg) - assert_parse_error(%q[def (1).foo; end], msg) - assert_parse_error(%q[def ((1;1)).foo; end], msg) - assert_parse_error(%q[def ((;1)).foo; end], msg) - assert_parse_error(%q[def ((1+1;1)).foo; end], msg) - assert_parse_error(%q[def ((%s();1)).foo; end], msg) - assert_parse_error(%q[def ((%w();1)).foo; end], msg) - assert_parse_error(%q[def ("#{42}").foo; end], msg) - assert_parse_error(%q[def (:"#{42}").foo; end], msg) - end - - def test_flip_flop - all_assertions_foreach(nil, - ['(cond1..cond2)', true], - ['((cond1..cond2))', true], - - # '(;;;cond1..cond2)', # don't care - - '(1; cond1..cond2)', - '(%s(); cond1..cond2)', - '(%w(); cond1..cond2)', - '(1; (2; (3; 4; cond1..cond2)))', - '(1+1; cond1..cond2)', - ) do |code, pass| - code = code.sub("cond1", "n==4").sub("cond2", "n==5") - if pass - assert_equal([4,5], eval("(1..9).select {|n| true if #{code}}")) - else - assert_raise_with_message(ArgumentError, /bad value for range/, code) { - verbose_bak, $VERBOSE = $VERBOSE, nil # disable "warning: possibly useless use of a literal in void context" - begin - eval("[4].each {|n| true if #{code}}") - ensure - $VERBOSE = verbose_bak - end - } - end + assert_syntax_error("#{<<~"begin;"}\n#{<<~'end;'}", /singleton method for literals/) do + begin; + def ("foo").foo; end + end; end end @@ -612,10 +577,6 @@ class TestParse < Test::Unit::TestCase assert_equal(' ^~~~~'"\n", e.message.lines.last) e = assert_syntax_error('"\M-\U0000"', 'Invalid escape character syntax') assert_equal(' ^~~~~'"\n", e.message.lines.last) - - e = assert_syntax_error(%["\\C-\u3042"], 'Invalid escape character syntax') - assert_match(/^\s \^(?# \\ ) ~(?# C ) ~(?# - ) ~+(?# U+3042 )$/x, e.message.lines.last) - assert_not_include(e.message, "invalid multibyte char") end def test_question @@ -646,8 +607,6 @@ class TestParse < Test::Unit::TestCase assert_syntax_error("?\\M-\x01", 'Invalid escape character syntax') assert_syntax_error("?\\M-\\C-\x01", 'Invalid escape character syntax') assert_syntax_error("?\\C-\\M-\x01", 'Invalid escape character syntax') - - assert_equal("\xff", eval("# encoding: ascii-8bit\n""?\\\xFF")) end def test_percent @@ -681,7 +640,6 @@ class TestParse < Test::Unit::TestCase assert_syntax_error(':@@1', /is not allowed/) assert_syntax_error(':@', /is not allowed/) assert_syntax_error(':@1', /is not allowed/) - assert_syntax_error(':$01234', /is not allowed/) end def test_parse_string @@ -722,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 @@ -889,6 +837,7 @@ x = __ENCODING__ def test_void_expr_stmts_value x = 1 useless_use = /useless use/ + unused = /unused/ assert_nil assert_warning(useless_use) {eval("x; nil")} assert_nil assert_warning(useless_use) {eval("1+1; nil")} assert_nil assert_warning('') {eval("1.+(1); nil")} @@ -896,10 +845,10 @@ x = __ENCODING__ assert_nil assert_warning(useless_use) {eval("::TestParse; nil")} assert_nil assert_warning(useless_use) {eval("x..x; nil")} assert_nil assert_warning(useless_use) {eval("x...x; nil")} - assert_nil assert_warning(useless_use) {eval("self; nil")} - assert_nil assert_warning(useless_use) {eval("nil; nil")} - assert_nil assert_warning(useless_use) {eval("true; nil")} - assert_nil assert_warning(useless_use) {eval("false; nil")} + assert_nil assert_warning(unused) {eval("self; nil")} + assert_nil assert_warning(unused) {eval("nil; nil")} + assert_nil assert_warning(unused) {eval("true; nil")} + assert_nil assert_warning(unused) {eval("false; nil")} assert_nil assert_warning(useless_use) {eval("defined?(1); nil")} assert_equal 1, x @@ -907,14 +856,12 @@ x = __ENCODING__ end def test_assign_in_conditional - # multiple assignment assert_warning(/`= literal' in conditional/) do eval <<-END, nil, __FILE__, __LINE__+1 (x, y = 1, 2) ? 1 : 2 END end - # instance variable assignment assert_warning(/`= literal' in conditional/) do eval <<-END, nil, __FILE__, __LINE__+1 if @x = true @@ -924,71 +871,6 @@ x = __ENCODING__ end END end - - # local variable assignment - assert_warning(/`= literal' in conditional/) do - eval <<-END, nil, __FILE__, __LINE__+1 - def m - if x = true - 1 - else - 2 - end - end - END - end - - # global variable assignment - assert_separately([], <<-RUBY) - assert_warning(/`= literal' in conditional/) do - eval <<-END, nil, __FILE__, __LINE__+1 - if $x = true - 1 - else - 2 - end - END - end - RUBY - - # dynamic variable assignment - assert_warning(/`= literal' in conditional/) do - eval <<-END, nil, __FILE__, __LINE__+1 - y = 1 - - 1.times do - if y = true - 1 - else - 2 - end - end - END - end - - # class variable assignment - assert_warning(/`= literal' in conditional/) do - eval <<-END, nil, __FILE__, __LINE__+1 - c = Class.new - class << c - if @@a = 1 - end - end - END - end - - # constant declaration - assert_separately([], <<-RUBY) - assert_warning(/`= literal' in conditional/) do - eval <<-END, nil, __FILE__, __LINE__+1 - if Const = true - 1 - else - 2 - end - END - end - RUBY end def test_literal_in_conditional @@ -1072,30 +954,6 @@ x = __ENCODING__ assert_warning('') {eval("#{a} = 1; /(?<#{a}>)/ =~ ''")} end - def test_named_capture_in_block - all_assertions_foreach(nil, - '(/(?<a>.*)/)', - '(;/(?<a>.*)/)', - '(%s();/(?<a>.*)/)', - '(%w();/(?<a>.*)/)', - '(1; (2; 3; (4; /(?<a>.*)/)))', - '(1+1; /(?<a>.*)/)', - '/#{""}(?<a>.*)/', - ) do |code, pass| - token = Random.bytes(4).unpack1("H*") - if pass - assert_equal(token, eval("#{code} =~ #{token.dump}; a")) - else - verbose_bak, $VERBOSE = $VERBOSE, nil # disable "warning: possibly useless use of a literal in void context" - begin - assert_nil(eval("#{code} =~ #{token.dump}; defined?(a)"), code) - ensure - $VERBOSE = verbose_bak - end - end - end - end - def test_rescue_in_command_assignment bug = '[ruby-core:75621] [Bug #12402]' all_assertions(bug) do |a| @@ -1183,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; @@ -1242,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/) @@ -1285,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 @@ -1528,75 +1359,9 @@ 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 allowed/) - assert_syntax_error('"#$01234"', /not allowed/) - end - =begin def test_past_scope_variable assert_warning(/past scope/) {catch {|tag| eval("BEGIN{throw tag}; tap {a = 1}; a")}} end =end - - def assert_parse(code) - assert_kind_of(RubyVM::AbstractSyntaxTree::Node, RubyVM::AbstractSyntaxTree.parse(code)) - end - - def assert_parse_error(code, message) - assert_raise_with_message(SyntaxError, message) do - $VERBOSE, verbose_bak = nil, $VERBOSE - begin - RubyVM::AbstractSyntaxTree.parse(code) - ensure - $VERBOSE = verbose_bak - end - end - end end diff --git a/test/ruby/test_pattern_matching.rb b/test/ruby/test_pattern_matching.rb index 8e2806581c..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: possibly useless use of a literal in void context\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 8d6ebf5dcb..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,20 +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]' - c1 = Class.new(Proc) {def initialize_dup(*) throw :initialize_dup; end} - assert_throw(:initialize_dup) {c1.new{}.dup} - end - - def test_clone_subclass - c1 = Class.new(Proc) - assert_equal c1, c1.new{}.clone.class, '[Bug #17545]' - c1 = Class.new(Proc) {def initialize_clone(*) throw :initialize_clone; end} - assert_throw(:initialize_clone) {c1.new{}.clone} - end - def test_binding b = proc {|x, y, z| proc {}.binding }.call(1, 2, 3) class << b; attr_accessor :foo; end @@ -427,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} } @@ -839,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() @@ -1303,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 @@ -1383,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 0416b20176..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,25 +704,14 @@ 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) assert_equal("trap\n", io.readpartial(8)) - sleep 0.2 # wait for the child to return to opening "fifo". - # On arm64-darwin22, often deadlocks while the child is - # opening "fifo". Not sure to where "ok" line being written - # at the next has gone. 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 @@ -854,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], @@ -906,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| @@ -935,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 @@ -981,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) @@ -1075,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 @@ -1442,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") @@ -1455,15 +1433,8 @@ class TestProcess < Test::Unit::TestCase assert_equal(s, s) assert_equal(s, s.to_i) - assert_deprecated_warn(/\buse .*Process::Status/) do - assert_equal(s.to_i & 0x55555555, s & 0x55555555) - end - assert_deprecated_warn(/\buse .*Process::Status/) do - assert_equal(s.to_i >> 1, s >> 1) - end - assert_raise(ArgumentError) do - s >> -1 - end + assert_equal(s.to_i & 0x55555555, s & 0x55555555) + assert_equal(s.to_i >> 1, s >> 1) assert_equal(false, s.stopped?) assert_equal(nil, s.stopsig) @@ -1576,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 @@ -1641,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 @@ -1668,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 @@ -1726,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 @@ -1744,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]" @@ -1759,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") @@ -1801,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) @@ -1815,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 @@ -1849,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 @@ -1870,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) @@ -1908,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| @@ -2012,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| @@ -2043,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| @@ -2188,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 @@ -2295,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 @@ -2384,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 @@ -2569,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 } @@ -2623,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]' @@ -2716,69 +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::UTF_16LE) - 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 - end - ary.clear - ary = nil - - # Disable GC so we can make sure GC only runs in Process.warmup - GC.disable - - total_pages_before = GC.stat(:heap_eden_pages) + GC.stat(:heap_allocatable_pages) - - Process.warmup - - # 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)) - assert_operator(GC.stat(:total_freed_pages), :>, 0) - end; - end + 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 + # Wait for us to be blocking in a call to waitpid2 + Thread.pass until t1.stop? + short_wpipe.close # Make short_pid exit + + # The short pid has exited, so -1 should pick that up. + assert_equal short_pid, Process.waitpid(-1) + + # Terminate t1 for the next phase of the test. + t1.kill + t1.join + + 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? + + # 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 f927522d96..a5072099e1 100644 --- a/test/ruby/test_random_formatter.rb +++ b/test/ruby/test_random_formatter.rb @@ -75,47 +75,6 @@ module Random::Formatter assert_match(/\A\h{8}-\h{4}-\h{4}-\h{4}-\h{12}\z/, uuid) end - def assert_uuid_v7(**opts) - t1 = current_uuid7_time(**opts) - uuid = @it.uuid_v7(**opts) - t3 = current_uuid7_time(**opts) - - assert_match(/\A\h{8}-\h{4}-7\h{3}-[89ab]\h{3}-\h{12}\z/, uuid) - - t2 = get_uuid7_time(uuid, **opts) - assert_operator(t1, :<=, t2) - assert_operator(t2, :<=, t3) - end - - def test_uuid_v7 - assert_uuid_v7 - 0.upto(12) do |extra_timestamp_bits| - assert_uuid_v7 extra_timestamp_bits: extra_timestamp_bits - end - end - - # It would be nice to simply use Time#floor here. But that is problematic - # due to the difference between decimal vs binary fractions. - def current_uuid7_time(extra_timestamp_bits: 0) - denominator = (1 << extra_timestamp_bits).to_r - Process.clock_gettime(Process::CLOCK_REALTIME, :nanosecond) - .then {|ns| ((ns / 1_000_000r) * denominator).floor / denominator } - .then {|ms| Time.at(ms / 1000r, in: "+00:00") } - end - - def get_uuid7_time(uuid, extra_timestamp_bits: 0) - denominator = (1 << extra_timestamp_bits) * 1000r - extra_chars = extra_timestamp_bits / 4 - last_char_bits = extra_timestamp_bits % 4 - extra_chars += 1 if last_char_bits != 0 - timestamp_re = /\A(\h{8})-(\h{4})-7(\h{#{extra_chars}})/ - timestamp_chars = uuid.match(timestamp_re).captures.join - timestamp = timestamp_chars.to_i(16) - timestamp >>= 4 - last_char_bits unless last_char_bits == 0 - timestamp /= denominator - Time.at timestamp, in: "+00:00" - end - def test_alphanumeric 65.times do |n| an = @it.alphanumeric(n) @@ -124,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 2aa69dc6a4..dc591b0604 100644 --- a/test/ruby/test_range.rb +++ b/test/ruby/test_range.rb @@ -2,7 +2,7 @@ require 'test/unit' require 'delegate' require 'timeout' -require 'date' +require 'bigdecimal' require 'rbconfig/sizeof' class TestRange < Test::Unit::TestCase @@ -392,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 } @@ -476,171 +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_reverse_each - a = [] - (1..3).reverse_each {|x| a << x } - assert_equal([3, 2, 1], a) - - a = [] - (1...3).reverse_each {|x| a << x } - assert_equal([2, 1], a) - - fmax = RbConfig::LIMITS['FIXNUM_MAX'] - fmin = RbConfig::LIMITS['FIXNUM_MIN'] - - a = [] - (fmax+1..fmax+3).reverse_each {|x| a << x } - assert_equal([fmax+3, fmax+2, fmax+1], a) - - a = [] - (fmax+1...fmax+3).reverse_each {|x| a << x } - assert_equal([fmax+2, fmax+1], a) - - a = [] - (fmax-1..fmax+1).reverse_each {|x| a << x } - assert_equal([fmax+1, fmax, fmax-1], a) - - a = [] - (fmax-1...fmax+1).reverse_each {|x| a << x } - assert_equal([fmax, fmax-1], a) - - a = [] - (fmin-1..fmin+1).reverse_each{|x| a << x } - assert_equal([fmin+1, fmin, fmin-1], a) - - a = [] - (fmin-1...fmin+1).reverse_each{|x| a << x } - assert_equal([fmin, fmin-1], a) - - a = [] - (fmin-3..fmin-1).reverse_each{|x| a << x } - assert_equal([fmin-1, fmin-2, fmin-3], a) - - a = [] - (fmin-3...fmin-1).reverse_each{|x| a << x } - assert_equal([fmin-2, fmin-3], a) - - a = [] - ("a".."c").reverse_each {|x| a << x } - assert_equal(["c", "b", "a"], a) - end - - def test_reverse_each_for_beginless_range - fmax = RbConfig::LIMITS['FIXNUM_MAX'] - fmin = RbConfig::LIMITS['FIXNUM_MIN'] - - a = [] - (..3).reverse_each {|x| a << x; break if x <= 0 } - assert_equal([3, 2, 1, 0], a) - - a = [] - (...3).reverse_each {|x| a << x; break if x <= 0 } - assert_equal([2, 1, 0], a) - - a = [] - (..fmax+1).reverse_each {|x| a << x; break if x <= fmax-1 } - assert_equal([fmax+1, fmax, fmax-1], a) - - a = [] - (...fmax+1).reverse_each {|x| a << x; break if x <= fmax-1 } - assert_equal([fmax, fmax-1], a) - - a = [] - (..fmin+1).reverse_each {|x| a << x; break if x <= fmin-1 } - assert_equal([fmin+1, fmin, fmin-1], a) - - a = [] - (...fmin+1).reverse_each {|x| a << x; break if x <= fmin-1 } - assert_equal([fmin, fmin-1], a) - - a = [] - (..fmin-1).reverse_each {|x| a << x; break if x <= fmin-3 } - assert_equal([fmin-1, fmin-2, fmin-3], a) - - a = [] - (...fmin-1).reverse_each {|x| a << x; break if x <= fmin-3 } - assert_equal([fmin-2, fmin-3], a) - end - - def test_reverse_each_for_endless_range - assert_raise(TypeError) { (1..).reverse_each {} } - - enum = nil - assert_nothing_raised { enum = (1..).reverse_each } - assert_raise(TypeError) { enum.each {} } - end - - def test_reverse_each_for_single_point_range - fmin = RbConfig::LIMITS['FIXNUM_MIN'] - fmax = RbConfig::LIMITS['FIXNUM_MAX'] - - values = [fmin*2, fmin-1, fmin, 0, fmax, fmax+1, fmax*2] - - values.each do |b| - r = b..b - a = [] - r.reverse_each {|x| a << x } - assert_equal([b], a, "failed on #{r}") - - r = b...b+1 - a = [] - r.reverse_each {|x| a << x } - assert_equal([b], a, "failed on #{r}") - end - end - - def test_reverse_each_for_empty_range - fmin = RbConfig::LIMITS['FIXNUM_MIN'] - fmax = RbConfig::LIMITS['FIXNUM_MAX'] - - values = [fmin*2, fmin-1, fmin, 0, fmax, fmax+1, fmax*2] - - values.each do |b| - r = b..b-1 - a = [] - r.reverse_each {|x| a << x } - assert_equal([], a, "failed on #{r}") - end - - values.repeated_permutation(2).to_a.product([true, false]).each do |(b, e), excl| - next unless b > e || (b == e && excl) - - r = Range.new(b, e, excl) - a = [] - r.reverse_each {|x| a << x } - assert_equal([], a, "failed on #{r}") - end - end - - def test_reverse_each_with_no_block - enum = (1..5).reverse_each - assert_equal 5, enum.size - - a = [] - enum.each {|x| a << x } - assert_equal [5, 4, 3, 2, 1], a - end - def test_begin_end assert_equal(0, (0..1).begin) assert_equal(1, (0..1).end) @@ -724,10 +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) - assert_operator(nil..nil, :===, Object.new) - assert_not_operator(0..10, :===, 0..10) end def test_eqq_string @@ -772,28 +583,6 @@ class TestRange < Test::Unit::TestCase assert_operator(c.new(0)..c.new(10), :===, c.new(5), bug12003) end - def test_eqq_unbounded_ruby_bug_19864 - t1 = Date.today - t2 = t1 + 1 - assert_equal(true, (..t1) === t1) - assert_equal(false, (..t1) === t2) - assert_equal(true, (..t2) === t1) - assert_equal(true, (..t2) === t2) - assert_equal(false, (...t1) === t1) - assert_equal(false, (...t1) === t2) - assert_equal(true, (...t2) === t1) - assert_equal(false, (...t2) === t2) - - assert_equal(true, (t1..) === t1) - assert_equal(true, (t1..) === t2) - assert_equal(false, (t2..) === t1) - assert_equal(true, (t2..) === t2) - assert_equal(true, (t1...) === t1) - assert_equal(true, (t1...) === t2) - assert_equal(false, (t2...) === t1) - assert_equal(true, (t2...) === t2) - end - def test_eqq_non_iteratable k = Class.new do include Comparable @@ -810,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 @@ -987,22 +771,14 @@ class TestRange < Test::Unit::TestCase assert_equal 41, (1...42).size assert_equal 6, (1...6.3).size assert_equal 5, (1.1...6).size - assert_equal 3, (1..3r).size - assert_equal 2, (1...3r).size - assert_equal 3, (1..3.1r).size - assert_equal 3, (1...3.1r).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 assert_equal Float::INFINITY, (...1).size assert_equal Float::INFINITY, (...1.0).size assert_nil ("a"...).size - assert_nil (..."z").size end def test_bsearch_typechecks_return_values @@ -1026,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 @@ -1199,10 +978,7 @@ class TestRange < Test::Unit::TestCase assert_equal(nil, (bignum...bignum+ary.size).bsearch {|i| ary[i - bignum] >= 100 }) assert_equal(bignum + 0, (bignum...bignum+ary.size).bsearch {|i| true }) assert_equal(nil, (bignum...bignum+ary.size).bsearch {|i| false }) - - assert_equal(bignum * 2 + 1, (0...).bsearch {|i| i > bignum * 2 }) assert_equal(bignum * 2 + 1, (bignum...).bsearch {|i| i > bignum * 2 }) - assert_equal(-bignum * 2 + 1, (...0).bsearch {|i| i > -bignum * 2 }) assert_equal(-bignum * 2 + 1, (...-bignum).bsearch {|i| i > -bignum * 2 }) assert_raise(TypeError) { ("a".."z").bsearch {} } @@ -1227,81 +1003,6 @@ class TestRange < Test::Unit::TestCase end def test_count - assert_equal 42, (1..42).count - assert_equal 41, (1...42).count - assert_equal 0, (42..1).count - assert_equal 0, (42...1).count - assert_equal 2**100, (1..2**100).count - assert_equal 6, (1...6.3).count - assert_equal 4, ('a'..'d').count - assert_equal 3, ('a'...'d').count - assert_equal(Float::INFINITY, (1..).count) - assert_equal(Float::INFINITY, (..1).count) - end - - def test_overlap? - assert_not_operator(0..2, :overlap?, -2..-1) - assert_not_operator(0..2, :overlap?, -2...0) - assert_operator(0..2, :overlap?, -1..0) - assert_operator(0..2, :overlap?, 1..2) - assert_operator(0..2, :overlap?, 2..3) - assert_not_operator(0..2, :overlap?, 3..4) - assert_not_operator(0...2, :overlap?, 2..3) - - assert_operator(..0, :overlap?, -1..0) - assert_operator(...0, :overlap?, -1..0) - assert_operator(..0, :overlap?, 0..1) - assert_operator(..0, :overlap?, ..1) - assert_not_operator(..0, :overlap?, 1..2) - assert_not_operator(...0, :overlap?, 0..1) - - assert_not_operator(0.., :overlap?, -2..-1) - assert_not_operator(0.., :overlap?, ...0) - assert_operator(0.., :overlap?, -1..0) - assert_operator(0.., :overlap?, ..0) - assert_operator(0.., :overlap?, 0..1) - assert_operator(0.., :overlap?, 1..2) - assert_operator(0.., :overlap?, 1..) - - assert_not_operator((1..3), :overlap?, ('a'..'d')) - assert_not_operator((1..), :overlap?, ('a'..)) - assert_not_operator((..1), :overlap?, (..'a')) - - assert_raise(TypeError) { (0..).overlap?(1) } - assert_raise(TypeError) { (0..).overlap?(nil) } - - assert_operator((1..3), :overlap?, (2..4)) - assert_operator((1...3), :overlap?, (2..3)) - assert_operator((2..3), :overlap?, (1..2)) - assert_operator((..3), :overlap?, (3..)) - assert_operator((nil..nil), :overlap?, (3..)) - assert_operator((nil...nil), :overlap?, (nil..)) - - assert_raise(TypeError) { (1..3).overlap?(1) } - - assert_not_operator((1..2), :overlap?, (2...2)) - assert_not_operator((2...2), :overlap?, (1..2)) - - assert_not_operator((4..1), :overlap?, (2..3)) - assert_not_operator((4..1), :overlap?, (..3)) - assert_not_operator((4..1), :overlap?, (2..)) - - assert_not_operator((1..4), :overlap?, (3..2)) - assert_not_operator((..4), :overlap?, (3..2)) - assert_not_operator((1..), :overlap?, (3..2)) - - assert_not_operator((4..5), :overlap?, (2..3)) - assert_not_operator((4..5), :overlap?, (2...4)) - - assert_not_operator((1..2), :overlap?, (3..4)) - assert_not_operator((1...3), :overlap?, (3..4)) - - assert_not_operator((4..5), :overlap?, (2..3)) - assert_not_operator((4..5), :overlap?, (2...4)) - - assert_not_operator((1..2), :overlap?, (3..4)) - assert_not_operator((1...3), :overlap?, (3..4)) - assert_not_operator((...3), :overlap?, (3..)) end end 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 d081bc9127..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]' @@ -1606,35 +1675,18 @@ class TestRefinement < Test::Unit::TestCase end using R - def m - C.new.m - end - assert_equal(:foo, C.new.m) - assert_equal(:foo, m) module R refine C do - - assert_equal(:foo, C.new.m) - assert_equal(:foo, m) - alias m m - - assert_equal(:foo, C.new.m) - assert_equal(:foo, m) - def m :bar end - - assert_equal(:bar, C.new.m, "[ruby-core:71423] [Bug #11672]") - assert_equal(:bar, m, "[Bug #20285]") end end assert_equal(:bar, C.new.m, "[ruby-core:71423] [Bug #11672]") - assert_equal(:bar, m, "[Bug #20285]") end; end @@ -1739,8 +1791,6 @@ class TestRefinement < Test::Unit::TestCase refine Object do def in_ref_a end - - RefA.const_set(:REF, self) end end @@ -1748,8 +1798,6 @@ class TestRefinement < Test::Unit::TestCase refine Object do def in_ref_b end - - RefB.const_set(:REF, self) end end @@ -1759,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 @@ -1792,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 = [ @@ -1977,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 @@ -2624,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 @@ -2631,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 @@ -2649,46 +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 - - def test_inline_cache_invalidation - klass = Class.new do - def cached_foo_callsite = foo - - def foo = :v1 - - host = self - @refinement = Module.new do - refine(host) do - def foo = :unused - end - end - end - - obj = klass.new - obj.cached_foo_callsite # prime cache - klass.class_eval do - def foo = :v2 # invalidate - end - assert_equal(:v2, obj.cached_foo_callsite) - end - private def eval_using(mod, s) diff --git a/test/ruby/test_regexp.rb b/test/ruby/test_regexp.rb index 74425c4b31..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 @@ -72,140 +85,12 @@ class TestRegexp < Test::Unit::TestCase end end - def test_to_s_under_gc_compact_stress - EnvUtil.under_gc_compact_stress do - str = "abcd\u3042" - [:UTF_16BE, :UTF_16LE, :UTF_32BE, :UTF_32LE].each do |es| - enc = Encoding.const_get(es) - rs = Regexp.new(str.encode(enc)).to_s - assert_equal("(?-mix:abcd\u3042)".encode(enc), rs) - assert_equal(enc, rs.encoding) - end - end - end - def test_to_s_extended_subexp re = /#\g#{"\n"}/x re = /#{re}/ 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( @@ -323,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) @@ -469,12 +351,6 @@ class TestRegexp < Test::Unit::TestCase assert_equal('/\/\xF1\xF2\xF3/i', /\/#{s}/i.inspect) end - def test_inspect_under_gc_compact_stress - EnvUtil.under_gc_compact_stress do - assert_equal('/(?-mix:\\/)|/', Regexp.union(/\//, "").inspect) - end - end - def test_char_to_option assert_equal("BAR", "FOOBARBAZ"[/b../i]) assert_equal("bar", "foobarbaz"[/ b . . /x]) @@ -548,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) @@ -679,73 +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_match_no_match_no_matchdata - EnvUtil.without_gc do - h = {} - ObjectSpace.count_objects(h) - prev_matches = h[:T_MATCH] || 0 - md = /[A-Z]/.match('1') # no match - ObjectSpace.count_objects(h) - new_matches = h[:T_MATCH] || 0 - assert_equal prev_matches, new_matches, "Bug [#20104]" - end - 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_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_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(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') } @@ -753,35 +552,6 @@ class TestRegexp < Test::Unit::TestCase assert_raise(RegexpError) { Regexp.new("((?<v>))\\g<0>") } end - def test_initialize_from_regex_memory_corruption - assert_ruby_status([], <<-'end;') - 10_000.times { Regexp.new(Regexp.new("(?<name>)")) } - end; - 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") @@ -890,13 +660,6 @@ class TestRegexp < Test::Unit::TestCase $_ = nil; assert_nil(~/./) end - def test_match_under_gc_compact_stress - EnvUtil.under_gc_compact_stress do - m = /(?<foo>.)(?<n>[^aeiou])?(?<bar>.+)/.match("hoge\u3042") - assert_equal("h", m.match(:foo)) - end - end - def test_match_p /backref/ =~ 'backref' # must match here, but not in a separate method, e.g., assert_send, @@ -1403,109 +1166,25 @@ class TestRegexp < Test::Unit::TestCase end def test_unicode_age - assert_unicode_age("\u261c", matches: %w"6.0 1.1", unmatches: []) - - assert_unicode_age("\u31f6", matches: %w"6.0 3.2", unmatches: %w"3.1 3.0 1.1") - assert_unicode_age("\u2754", matches: %w"6.0", unmatches: %w"5.0 4.0 3.0 2.0 1.1") - - assert_unicode_age("\u32FF", matches: %w"12.1", unmatches: %w"12.0") - end - - def test_unicode_age_14_0 - @matches = %w"14.0" - @unmatches = %w"13.0" - - assert_unicode_age("\u{10570}") - assert_unicode_age("\u9FFF") - assert_unicode_age("\u{2A6DF}") - assert_unicode_age("\u{2B738}") - end - - def test_unicode_age_15_0 - @matches = %w"15.0" - @unmatches = %w"14.0" - - assert_unicode_age("\u{0CF3}", - "KANNADA SIGN COMBINING ANUSVARA ABOVE RIGHT") - assert_unicode_age("\u{0ECE}", "LAO YAMAKKAN") - assert_unicode_age("\u{10EFD}".."\u{10EFF}", - "ARABIC SMALL LOW WORD SAKTA..ARABIC SMALL LOW WORD MADDA") - assert_unicode_age("\u{1123F}".."\u{11241}", - "KHOJKI LETTER QA..KHOJKI VOWEL SIGN VOCALIC R") - assert_unicode_age("\u{11B00}".."\u{11B09}", - "DEVANAGARI HEAD MARK..DEVANAGARI SIGN MINDU") - assert_unicode_age("\u{11F00}".."\u{11F10}", - "KAWI SIGN CANDRABINDU..KAWI LETTER O") - assert_unicode_age("\u{11F12}".."\u{11F3A}", - "KAWI LETTER KA..KAWI VOWEL SIGN VOCALIC R") - assert_unicode_age("\u{11F3E}".."\u{11F59}", - "KAWI VOWEL SIGN E..KAWI DIGIT NINE") - assert_unicode_age("\u{1342F}", - "EGYPTIAN HIEROGLYPH V011D") - assert_unicode_age("\u{13439}".."\u{1343F}", - "EGYPTIAN HIEROGLYPH INSERT AT MIDDLE..EGYPTIAN HIEROGLYPH END WALLED ENCLOSURE") - assert_unicode_age("\u{13440}".."\u{13455}", - "EGYPTIAN HIEROGLYPH MIRROR HORIZONTALLY..EGYPTIAN HIEROGLYPH MODIFIER DAMAGED") - assert_unicode_age("\u{1B132}", "HIRAGANA LETTER SMALL KO") - assert_unicode_age("\u{1B155}", "KATAKANA LETTER SMALL KO") - assert_unicode_age("\u{1D2C0}".."\u{1D2D3}", - "KAKTOVIK NUMERAL ZERO..KAKTOVIK NUMERAL NINETEEN") - assert_unicode_age("\u{1DF25}".."\u{1DF2A}", - "LATIN SMALL LETTER D WITH MID-HEIGHT LEFT HOOK..LATIN SMALL LETTER T WITH MID-HEIGHT LEFT HOOK") - assert_unicode_age("\u{1E030}".."\u{1E06D}", - "MODIFIER LETTER CYRILLIC SMALL A..MODIFIER LETTER CYRILLIC SMALL STRAIGHT U WITH STROKE") - assert_unicode_age("\u{1E08F}", - "COMBINING CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I") - assert_unicode_age("\u{1E4D0}".."\u{1E4F9}", - "NAG MUNDARI LETTER O..NAG MUNDARI DIGIT NINE") - assert_unicode_age("\u{1F6DC}", "WIRELESS") - assert_unicode_age("\u{1F774}".."\u{1F776}", - "LOT OF FORTUNE..LUNAR ECLIPSE") - assert_unicode_age("\u{1F77B}".."\u{1F77F}", - "HAUMEA..ORCUS") - assert_unicode_age("\u{1F7D9}", "NINE POINTED WHITE STAR") - assert_unicode_age("\u{1FA75}".."\u{1FA77}", - "LIGHT BLUE HEART..PINK HEART") - assert_unicode_age("\u{1FA87}".."\u{1FA88}", - "MARACAS..FLUTE") - assert_unicode_age("\u{1FAAD}".."\u{1FAAF}", - "FOLDING HAND FAN..KHANDA") - assert_unicode_age("\u{1FABB}".."\u{1FABD}", - "HYACINTH..WING") - assert_unicode_age("\u{1FABF}", "GOOSE") - assert_unicode_age("\u{1FACE}".."\u{1FACF}", - "MOOSE..DONKEY") - assert_unicode_age("\u{1FADA}".."\u{1FADB}", - "GINGER ROOT..PEA POD") - assert_unicode_age("\u{1FAE8}", "SHAKING FACE") - assert_unicode_age("\u{1FAF7}".."\u{1FAF8}", - "LEFTWARDS PUSHING HAND..RIGHTWARDS PUSHING HAND") - assert_unicode_age("\u{2B739}", - "CJK UNIFIED IDEOGRAPH-2B739") - assert_unicode_age("\u{31350}".."\u{323AF}", - "CJK UNIFIED IDEOGRAPH-31350..CJK UNIFIED IDEOGRAPH-323AF") - end - - UnicodeAgeRegexps = Hash.new do |h, age| - h[age] = [/\A\p{age=#{age}}+\z/u, /\A\P{age=#{age}}+\z/u].freeze - end - - def assert_unicode_age(char, mesg = nil, matches: @matches, unmatches: @unmatches) - if Range === char - char = char.to_a.join("") - end + assert_match(/^\p{Age=6.0}$/u, "\u261c") + assert_match(/^\p{Age=1.1}$/u, "\u261c") + assert_no_match(/^\P{age=6.0}$/u, "\u261c") - matches.each do |age| - pos, neg = UnicodeAgeRegexps[age] - assert_match(pos, char, mesg) - assert_not_match(neg, char, mesg) - end + assert_match(/^\p{age=6.0}$/u, "\u31f6") + assert_match(/^\p{age=3.2}$/u, "\u31f6") + assert_no_match(/^\p{age=3.1}$/u, "\u31f6") + assert_no_match(/^\p{age=3.0}$/u, "\u31f6") + assert_no_match(/^\p{age=1.1}$/u, "\u31f6") - unmatches.each do |age| - pos, neg = UnicodeAgeRegexps[age] - assert_not_match(pos, char, mesg) - assert_match(neg, char, mesg) - end + assert_match(/^\p{age=6.0}$/u, "\u2754") + assert_no_match(/^\p{age=5.0}$/u, "\u2754") + assert_no_match(/^\p{age=4.0}$/u, "\u2754") + assert_no_match(/^\p{age=3.0}$/u, "\u2754") + assert_no_match(/^\p{age=2.0}$/u, "\u2754") + assert_no_match(/^\p{age=1.1}$/u, "\u2754") + + assert_no_match(/^\p{age=12.0}$/u, "\u32FF") + assert_match(/^\p{age=12.1}$/u, "\u32FF") end MatchData_A = eval("class MatchData_\u{3042} < MatchData; self; end") @@ -1710,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 @@ -1721,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; @@ -1736,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) @@ -1765,309 +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 test_s_timeout_memory_leak - assert_no_memory_leak([], "#{<<~"begin;"}", "#{<<~"end;"}", "[Bug #20228]", rss: true) - Regexp.timeout = 0.001 - regex = /^(a*)*$/ - str = "a" * 1000000 + "x" - - code = proc do - regex =~ str - rescue - end - - 10.times(&code) - begin; - 1_000.times(&code) - 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 - omit "timeout test is too unstable on s390x" if RUBY_PLATFORM =~ /s390x/ - per_instance_redos_test(10, 0.2, 0.2) - end - - def test_timeout_longer_than_global - omit "timeout test is too unstable on s390x" if RUBY_PLATFORM =~ /s390x/ - 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" * 1000000 + "x") - end; - end - - def test_match_cache_atomic_complex - assert_separately([], "#{<<-"begin;"}\n#{<<-'end;'}") - timeout = #{ EnvUtil.apply_timeout_scale(10).inspect } - begin; - Regexp.timeout = timeout - assert_nil(/a*(?>a*)ab/ =~ "a" * 1000000 + "b") - end; - end - - def test_match_cache_positive_look_ahead - assert_separately([], "#{<<-"begin;"}\n#{<<-'end;'}") - timeout = #{ EnvUtil.apply_timeout_scale(10).inspect } - begin; - Regexp.timeout = timeout - assert_nil(/^a*?(?=a*a*)$/ =~ "a" * 1000000 + "x") - end; - end - - def test_match_cache_positive_look_ahead_complex - assert_separately([], "#{<<-"begin;"}\n#{<<-'end;'}") - timeout = #{ EnvUtil.apply_timeout_scale(10).inspect } - begin; - Regexp.timeout = timeout - assert_equal(/(?:(?=a*)a)*/ =~ "a" * 1000000, 0) - end; - end - - def test_match_cache_negative_look_ahead - assert_separately([], "#{<<-"begin;"}\n#{<<-'end;'}") - timeout = #{ EnvUtil.apply_timeout_scale(10).inspect } - begin; - Regexp.timeout = timeout - assert_nil(/^a*?(?!a*a*)$/ =~ "a" * 1000000 + "x") - end; - end - - def test_match_cache_positive_look_behind - assert_separately([], "#{<<-"begin;"}\n#{<<-'end;'}") - timeout = #{ EnvUtil.apply_timeout_scale(10).inspect } - begin; - Regexp.timeout = timeout - assert_nil(/(?<=abc|def)(a|a)*$/ =~ "abc" + "a" * 1000000 + "x") - end; - end - - def test_match_cache_negative_look_behind - assert_separately([], "#{<<-"begin;"}\n#{<<-'end;'}") - timeout = #{ EnvUtil.apply_timeout_scale(10).inspect } - begin; - Regexp.timeout = timeout - assert_nil(/(?<!x)(a|a)*$/ =~ "a" * 1000000 + "x") - end; - end - - def test_match_cache_with_peek_optimization - assert_separately([], "#{<<-"begin;"}\n#{<<-'end;'}") - timeout = #{ EnvUtil.apply_timeout_scale(10).inspect } - begin; - Regexp.timeout = timeout - assert_nil(/a+z/ =~ "a" * 1000000 + "xz") - 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 # [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_encoding_flags_are_preserved_when_initialized_with_another_regexp - re = Regexp.new("\u2018hello\u2019".encode("UTF-8")) - str = "".encode("US-ASCII") - - assert_nothing_raised do - str.match?(re) - str.match?(Regexp.new(re)) - end - end - - def test_bug_19537 # [Bug #19537] - str = 'aac' - re = '^([ab]{1,3})(a?)*$' - 100.times do - assert !Regexp.new(re).match?(str) - end - end - - def test_bug_20083 # [Bug #20083] - re = /([\s]*ABC)$/i - (1..100).each do |n| - text = "#{"0" * n}ABC" - assert text.match?(re) - end - end - - def test_bug_20098 # [Bug #20098] - assert /a((.|.)|bc){,4}z/.match? 'abcbcbcbcz' - assert /a(b+?c*){4,5}z/.match? 'abbbccbbbccbcbcz' - assert /a(b+?(.|.)){2,3}z/.match? 'abbbcbbbcbbbcz' - assert /a(b*?(.|.)[bc]){2,5}z/.match? 'abcbbbcbcccbcz' - assert /^(?:.+){2,4}?b|b/.match? "aaaabaa" - end - - def test_bug_20207 # [Bug #20207] - assert(!'clan'.match?(/(?=.*a)(?!.*n)/)) - end - - def test_bug_20212 # [Bug #20212] - regex = Regexp.new( - /\A((?=.*?[a-z])(?!.*--)[a-z\d]+[a-z\d-]*[a-z\d]+).((?=.*?[a-z])(?!.*--)[a-z\d]+[a-z\d-]*[a-z\d]+).((?=.*?[a-z])(?!.*--)[a-zd]+[a-zd-]*[a-zd]+).((?=.*?[a-z])(?!.*--)[a-zd]+[a-zd-]*[a-zd]+)\Z/x - ) - string = "www.google.com" - 100.times.each { assert(regex.match?(string)) } - end - - def test_bug_20246 # [Bug #20246] - assert_equal '1.2.3', '1.2.3'[/(\d+)(\.\g<1>){2}/] - assert_equal '1.2.3', '1.2.3'[/((?:\d|foo|bar)+)(\.\g<1>){2}/] - 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_not_send [Regexp, :linear_time?, /(?=(a))/] - assert_not_send [Regexp, :linear_time?, /(?!(a))/] - - 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 fd5092aaf0..a71fe0932e 100644 --- a/test/ruby/test_require.rb +++ b/test/ruby/test_require.rb @@ -110,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__'} @@ -192,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 @@ -209,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 @@ -227,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 @@ -478,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 } } @@ -504,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 } } @@ -697,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 @@ -725,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 @@ -755,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}" @@ -839,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) @@ -867,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 @@ -928,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) @@ -976,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 38ca119a8f..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,22 +83,11 @@ 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 - save_rubyopt = ENV.delete('RUBYOPT') + save_rubyopt = ENV['RUBYOPT'] + ENV['RUBYOPT'] = nil assert_in_out_err(%w(-W0 -e) + ['p $-W'], "", %w(0), []) assert_in_out_err(%w(-W1 -e) + ['p $-W'], "", %w(1), []) assert_in_out_err(%w(-Wx -e) + ['p $-W'], "", %w(2), []) @@ -110,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) @@ -153,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 (\+MN )?\[#{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]) @@ -188,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'/) @@ -210,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 @@ -233,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]) @@ -263,43 +241,31 @@ 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 - def test_parser_flag - warning = /compiler based on the Prism parser is currently experimental/ - - assert_in_out_err(%w(--parser=prism -e) + ["puts :hi"], "", %w(hi), warning) - - assert_in_out_err(%w(--parser=parse.y -e) + ["puts :hi"], "", %w(hi), []) - assert_norun_with_rflag('--parser=parse.y', '--version', "") - - assert_in_out_err(%w(--parser=notreal -e) + ["puts :hi"], "", [], /unknown parser notreal/) - - assert_in_out_err(%w(--parser=prism --version), "", /\+PRISM/, warning) - end - def test_eval assert_in_out_err(%w(-e), "", [], /no code specified for -e \(RuntimeError\)/) end @@ -381,25 +347,7 @@ class TestRubyOptions < Test::Unit::TestCase end def test_syntax_check - assert_in_out_err(%w(-cw -e a=1+1 -e !a), "", ["Syntax OK"], []) - assert_in_out_err(%w(-cw -e break), "", [], ["-e:1: Invalid break", :*]) - assert_in_out_err(%w(-cw -e next), "", [], ["-e:1: Invalid next", :*]) - assert_in_out_err(%w(-cw -e redo), "", [], ["-e:1: Invalid redo", :*]) - assert_in_out_err(%w(-cw -e retry), "", [], ["-e:1: Invalid retry", :*]) - assert_in_out_err(%w(-cw -e yield), "", [], ["-e:1: Invalid yield", :*]) - assert_in_out_err(%w(-cw -e begin -e break -e end), "", [], ["-e:2: Invalid break", :*]) - assert_in_out_err(%w(-cw -e begin -e next -e end), "", [], ["-e:2: Invalid next", :*]) - assert_in_out_err(%w(-cw -e begin -e redo -e end), "", [], ["-e:2: Invalid redo", :*]) - assert_in_out_err(%w(-cw -e begin -e retry -e end), "", [], ["-e:2: Invalid retry", :*]) - assert_in_out_err(%w(-cw -e begin -e yield -e end), "", [], ["-e:2: Invalid yield", :*]) - assert_in_out_err(%w(-cw -e !defined?(break)), "", ["Syntax OK"], []) - assert_in_out_err(%w(-cw -e !defined?(next)), "", ["Syntax OK"], []) - assert_in_out_err(%w(-cw -e !defined?(redo)), "", ["Syntax OK"], []) - assert_in_out_err(%w(-cw -e !defined?(retry)), "", ["Syntax OK"], []) - assert_in_out_err(%w(-cw -e !defined?(yield)), "", ["Syntax OK"], []) - assert_in_out_err(%w(-n -cw -e break), "", ["Syntax OK"], []) - assert_in_out_err(%w(-n -cw -e next), "", ["Syntax OK"], []) - assert_in_out_err(%w(-n -cw -e redo), "", ["Syntax OK"], []) + assert_in_out_err(%w(-c -e a=1+1 -e !a), "", ["Syntax OK"], []) end def test_invalid_option @@ -407,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 @@ -447,11 +395,12 @@ class TestRubyOptions < Test::Unit::TestCase assert_in_out_err(%w(), "p Warning[:experimental]", ["false"]) ENV['RUBYOPT'] = '-W:qux' assert_in_out_err(%w(), "", [], /unknown warning category: `qux'/) - - ENV['RUBYOPT'] = 'w' - assert_in_out_err(%w(), "p $VERBOSE", ["true"]) ensure - ENV['RUBYOPT'] = rubyopt_orig + if rubyopt_orig + ENV['RUBYOPT'] = rubyopt_orig + else + ENV.delete('RUBYOPT') + end end def test_search @@ -725,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") @@ -748,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#{<<-'};'}") {# @@ -789,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)? @@ -806,9 +755,6 @@ class TestRubyOptions < Test::Unit::TestCase )? )x, %r( - (?:--\sThreading(?:.+\n)*\n)? - )x, - %r( (?:--\sMachine(?:.+\n)*\n)? )x, %r( @@ -824,32 +770,26 @@ class TestRubyOptions < Test::Unit::TestCase )? )x, ] - - KILL_SELF = "Process.kill :SEGV, $$" end - def assert_segv(args, message=nil, list: SEGVTest::ExpectedStderrList, **opt) - # We want YJIT to be enabled in the subprocess if it's enabled for us - # so that the Ruby description matches. - env = Hash === args.first ? args.shift : {} - args.unshift("--yjit") if self.class.yjit_enabled? - env.update({'RUBY_ON_BUG' => nil}) - args.unshift(env) + def assert_segv(args, message=nil) + skip if ENV['RUBY_ON_BUG'] test_stdin = "" + opt = SEGVTest::ExecOptions.dup + list = SEGVTest::ExpectedStderrList - assert_in_out_err(args, test_stdin, //, list, encoding: "ASCII-8BIT", - **SEGVTest::ExecOptions, **opt) + assert_in_out_err(args, test_stdin, //, list, encoding: "ASCII-8BIT", **opt) end def test_segv_test - assert_segv(["--disable-gems", "-e", SEGVTest::KILL_SELF]) + assert_segv(["--disable-gems", "-e", "Process.kill :SEGV, $$"]) end def test_segv_loaded_features bug7402 = '[ruby-core:49573]' - status = assert_segv(['-e', "END {#{SEGVTest::KILL_SELF}}", + status = assert_segv(['-e', 'END {Process.kill :SEGV, $$}', '-e', 'class Bogus; def to_str; exit true; end; end', '-e', '$".clear', '-e', '$".unshift Bogus.new', @@ -863,70 +803,10 @@ class TestRubyOptions < Test::Unit::TestCase Tempfile.create(["test_ruby_test_bug7597", ".rb"]) {|t| t.write "f" * 100 t.flush - assert_segv(["--disable-gems", "-e", "$0=ARGV[0]; #{SEGVTest::KILL_SELF}", t.path], bug7597) + assert_segv(["--disable-gems", "-e", "$0=ARGV[0]; Process.kill :SEGV, $$", t.path], bug7597) } end - def assert_crash_report(path, cmd = nil) - Dir.mktmpdir("ruby_crash_report") do |dir| - list = SEGVTest::ExpectedStderrList - if cmd - FileUtils.mkpath(File.join(dir, File.dirname(cmd))) - File.write(File.join(dir, cmd), SEGVTest::KILL_SELF+"\n") - c = Regexp.quote(cmd) - list = list.map {|re| Regexp.new(re.source.gsub(/^\s*(\(\?:)?\K-e(?=:)/) {c}, re.options)} - else - cmd = ['-e', SEGVTest::KILL_SELF] - end - status = assert_segv([{"RUBY_CRASH_REPORT"=>path}, *cmd], list: [], chdir: dir) - reports = Dir.glob("*.log", File::FNM_DOTMATCH, base: dir) - assert_equal(1, reports.size) - assert_pattern_list(list, File.read(File.join(dir, reports.first))) - break status, reports.first - end - end - - def test_crash_report - assert_crash_report("%e.%f.%p.log") do |status, report| - assert_equal("#{File.basename(EnvUtil.rubybin)}.-e.#{status.pid}.log", report) - end - end - - def test_crash_report_script - assert_crash_report("%e.%f.%p.log", "bug.rb") do |status, report| - assert_equal("#{File.basename(EnvUtil.rubybin)}.bug.rb.#{status.pid}.log", report) - end - end - - def test_crash_report_executable_path - omit if EnvUtil.rubybin.size > 245 - assert_crash_report("%E.%p.log") do |status, report| - assert_equal("#{EnvUtil.rubybin.tr('/', '!')}.#{status.pid}.log", report) - end - end - - def test_crash_report_script_path - assert_crash_report("%F.%p.log", "test/bug.rb") do |status, report| - assert_equal("test!bug.rb.#{status.pid}.log", report) - end - end - - def test_crash_report_pipe - if File.executable?(echo = "/bin/echo") - elsif /mswin|ming/ =~ RUBY_PLATFORM - echo = "echo" - else - omit "/bin/echo not found" - end - env = {"RUBY_CRASH_REPORT"=>"| #{echo} %e:%f:%p", "RUBY_ON_BUG"=>nil} - assert_in_out_err([env], SEGVTest::KILL_SELF, - encoding: "ASCII-8BIT", - **SEGVTest::ExecOptions) do |stdout, stderr, status| - assert_empty(stderr) - assert_equal(["#{File.basename(EnvUtil.rubybin)}:-:#{status.pid}"], stdout) - end - end - def test_DATA Tempfile.create(["test_ruby_test_rubyoption", ".rb"]) {|t| t.puts "puts DATA.read.inspect" @@ -978,7 +858,7 @@ class TestRubyOptions < Test::Unit::TestCase Process.wait pid } rescue RuntimeError - omit $! + skip $! end } assert_equal("", result, '[ruby-dev:37798]') @@ -1028,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" @@ -1114,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 @@ -1138,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 @@ -1237,13 +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_free_at_exit_env_var - env = {"RUBY_FREE_AT_EXIT"=>"1"} - assert_ruby_status([env, "-e;"]) - assert_in_out_err([env, "-W"], "", [], /Free at exit is experimental and may be unstable/) + 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 dbaf0aaf09..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], @@ -358,18 +334,18 @@ class TestSetTraceFunc < Test::Unit::TestCase def test_thread_trace events = {:set => [], :add => []} - name = "#{self.class}\##{__method__}" prc = Proc.new { |event, file, lineno, mid, binding, klass| - events[:set] << [event, lineno, mid, klass, :set] if file == name + events[:set] << [event, lineno, mid, klass, :set] } prc = prc # suppress warning prc2 = Proc.new { |event, file, lineno, mid, binding, klass| - events[:add] << [event, lineno, mid, klass, :add] if file == name + events[:add] << [event, lineno, mid, klass, :add] } prc2 = prc2 # suppress warning th = Thread.new do th = Thread.current + name = "#{self.class}\##{__method__}" eval <<-EOF.gsub(/^.*?: /, ""), nil, name 1: th.set_trace_func(prc) 2: th.add_trace_func(prc2) @@ -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], ] @@ -625,19 +597,6 @@ PREP CODE end - def test_tracepoint_bmethod_memory_leak - assert_no_memory_leak([], '', "#{<<~"begin;"}\n#{<<~'end;'}", "[Bug #20194]", rss: true) - obj = Object.new - obj.define_singleton_method(:foo) {} - bmethod = obj.method(:foo) - tp = TracePoint.new(:return) {} - begin; - 1_000_000.times do - tp.enable(target: bmethod) {} - end - end; - end - def trace_by_set_trace_func events = [] trace = nil @@ -650,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 @@ -675,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], @@ -710,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| @@ -789,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 @@ -968,55 +914,6 @@ CODE assert_equal(expected*2, events) end - def test_tracepoint_struct - c = Struct.new(:x) do - alias y x - alias y= x= - end - obj = c.new - - ar_meth = obj.method(:x) - aw_meth = obj.method(:x=) - aar_meth = obj.method(:y) - aaw_meth = obj.method(:y=) - events = [] - trace = TracePoint.new(:c_call, :c_return){|tp| - next if !target_thread? - next if tp.path != __FILE__ - next if tp.method_id == :call - case tp.event - when :c_call - assert_raise(RuntimeError) {tp.return_value} - events << [tp.event, tp.method_id, tp.callee_id] - when :c_return - events << [tp.event, tp.method_id, tp.callee_id, tp.return_value] - end - } - test_proc = proc do - obj.x = 1 - obj.x - obj.y = 2 - obj.y - aw_meth.call(1) - ar_meth.call - aaw_meth.call(2) - aar_meth.call - end - test_proc.call # populate call caches - trace.enable(&test_proc) - expected = [ - [:c_call, :x=, :x=], - [:c_return, :x=, :x=, 1], - [:c_call, :x, :x], - [:c_return, :x, :x, 1], - [:c_call, :x=, :y=], - [:c_return, :x=, :y=, 2], - [:c_call, :x, :y], - [:c_return, :x, :y, 2], - ] - assert_equal(expected*2, events) - end - class XYZZYException < Exception; end def method_test_tracepoint_raised_exception err raise err @@ -1056,7 +953,7 @@ CODE /return/ =~ tp.event ? tp.return_value : nil ] }.enable{ - [1].map{ + 1.times{ 3 } method_for_test_tracepoint_block{ @@ -1066,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], @@ -1093,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 } @@ -1372,7 +1269,7 @@ CODE next if !target_thread? events << tp.event }.enable{ - [1].map{ + 1.times{ 3 } method_for_test_tracepoint_block{ @@ -1394,7 +1291,7 @@ CODE next if !target_thread? events << tp.event }.enable{ - [1].map{ + 1.times{ 3 } method_for_test_tracepoint_block{ @@ -1753,7 +1650,7 @@ CODE Bug10724.new } - assert_equal([:call, :call, :return, :return], evs) + assert_equal([:call, :return], evs) end require 'fiber' @@ -1985,11 +1882,7 @@ CODE def tp_return_value mid ary = [] - TracePoint.new(:return, :b_return){|tp| - next if !target_thread? - next if tp.path != __FILE__ - ary << [tp.event, tp.method_id, tp.return_value] - }.enable{ + TracePoint.new(:return, :b_return){|tp| next if !target_thread?; ary << [tp.event, tp.method_id, tp.return_value]}.enable{ send mid } ary.pop # last b_return event is not required. @@ -2198,7 +2091,7 @@ CODE q = Thread::Queue.new t = Thread.new{ Thread.current.add_trace_func proc{|ev, file, line, *args| - events << [ev, line] if file == __FILE__ + events << [ev, line] } # do not stop trace. They will be stopped at Thread termination. q.push 1 _x = 1 @@ -2234,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__ @@ -2249,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 @@ -2358,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 @@ -2472,40 +2366,6 @@ CODE assert_equal [:tp1, 1, 2, :tp2, 3], events end - def test_multiple_enable - ary = [] - trace = TracePoint.new(:call) do |tp| - ary << tp.method_id - end - trace.enable - trace.enable - foo - trace.disable - assert_equal(1, ary.count(:foo), '[Bug #19114]') - 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| @@ -2534,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{ @@ -2703,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 @@ -2776,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 ee99fbad6d..0000000000 --- a/test/ruby/test_shapes.rb +++ /dev/null @@ -1,1041 +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 - MANY_IVS = 80 - - 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 - assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") - begin; - class Hi; end - - RubyVM::Shape.exhaust_shapes(2) - - obj = Hi.new - obj.instance_variable_set(:@b, 1) - obj.instance_variable_set(:@c, 1) - obj.instance_variable_set(:@d, 1) - - assert_predicate RubyVM::Shape.of(obj), :too_complex? - end; - end - - def test_too_many_ivs_on_class - obj = Class.new - - (MANY_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 - - (MANY_IVS + 2).times do - obj.instance_variable_set(:"@a#{_1}", 1) - end - (MANY_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 - - (MANY_IVS + 2).times do - obj.instance_variable_set(:"@a#{_1}", 1) - end - (MANY_IVS + 2).times do - obj.remove_instance_variable(:"@a#{_1}") - end - - assert_empty obj.instance_variables - end - - def test_too_complex_geniv - assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") - begin; - class TooComplex < Hash - attr_reader :very_unique - end - - RubyVM::Shape.exhaust_shapes - - (RubyVM::Shape::SHAPE_MAX_VARIATIONS * 2).times do - TooComplex.new.instance_variable_set(:"@unique_#{_1}", 1) - end - - tc = TooComplex.new - tc.instance_variable_set(:@very_unique, 3) - tc.instance_variable_set(:@very_unique2, 4) - assert_equal 3, tc.instance_variable_get(:@very_unique) - assert_equal 4, tc.instance_variable_get(:@very_unique2) - - assert_equal [:@very_unique, :@very_unique2], tc.instance_variables - end; - end - - def test_use_all_shapes_then_freeze - assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") - begin; - class Hi; end - RubyVM::Shape.exhaust_shapes(3) - - obj = Hi.new - i = 0 - while RubyVM::Shape.shapes_available > 0 - obj.instance_variable_set(:"@b#{i}", 1) - i += 1 - end - obj.freeze - - assert obj.frozen? - end; - end - - def test_run_out_of_shape_for_object - assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") - begin; - class A - def initialize - @a = 1 - end - end - RubyVM::Shape.exhaust_shapes - - A.new - end; - end - - def test_run_out_of_shape_for_class_ivar - assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") - begin; - RubyVM::Shape.exhaust_shapes - - c = Class.new - c.instance_variable_set(:@a, 1) - assert_equal(1, c.instance_variable_get(:@a)) - - c.remove_instance_variable(:@a) - assert_nil(c.instance_variable_get(:@a)) - - assert_raise(NameError) do - c.remove_instance_variable(:@a) - end - end; - end - - def test_evacuate_class_ivar_and_compaction - assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") - begin; - count = 20 - - c = Class.new - count.times do |ivar| - c.instance_variable_set("@i#{ivar}", "ivar-#{ivar}") - end - - RubyVM::Shape.exhaust_shapes - - GC.auto_compact = true - GC.stress = true - # Cause evacuation - c.instance_variable_set(:@a, o = Object.new) - assert_equal(o, c.instance_variable_get(:@a)) - GC.stress = false - - count.times do |ivar| - assert_equal "ivar-#{ivar}", c.instance_variable_get("@i#{ivar}") - end - end; - end - - def test_evacuate_generic_ivar_and_compaction - assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") - begin; - count = 20 - - c = Hash.new - count.times do |ivar| - c.instance_variable_set("@i#{ivar}", "ivar-#{ivar}") - end - - RubyVM::Shape.exhaust_shapes - - GC.auto_compact = true - GC.stress = true - - # Cause evacuation - c.instance_variable_set(:@a, o = Object.new) - assert_equal(o, c.instance_variable_get(:@a)) - - GC.stress = false - - count.times do |ivar| - assert_equal "ivar-#{ivar}", c.instance_variable_get("@i#{ivar}") - end - end; - end - - def test_evacuate_object_ivar_and_compaction - assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") - begin; - count = 20 - - c = Object.new - count.times do |ivar| - c.instance_variable_set("@i#{ivar}", "ivar-#{ivar}") - end - - RubyVM::Shape.exhaust_shapes - - GC.auto_compact = true - GC.stress = true - - # Cause evacuation - c.instance_variable_set(:@a, o = Object.new) - assert_equal(o, c.instance_variable_get(:@a)) - - GC.stress = false - - count.times do |ivar| - assert_equal "ivar-#{ivar}", c.instance_variable_get("@i#{ivar}") - end - end; - end - - def test_gc_stress_during_evacuate_generic_ivar - assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") - begin; - [].instance_variable_set(:@a, 1) - - RubyVM::Shape.exhaust_shapes - - ary = 10.times.map { [] } - - GC.stress = true - ary.each do |o| - o.instance_variable_set(:@a, 1) - o.instance_variable_set(:@b, 1) - end - end; - end - - def test_run_out_of_shape_for_module_ivar - assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") - begin; - RubyVM::Shape.exhaust_shapes - - module Foo - @a = 1 - @b = 2 - assert_equal 1, @a - assert_equal 2, @b - end - end; - end - - def test_run_out_of_shape_for_class_cvar - assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") - begin; - RubyVM::Shape.exhaust_shapes - - c = Class.new - - c.class_variable_set(:@@a, 1) - assert_equal(1, c.class_variable_get(:@@a)) - - c.class_eval { remove_class_variable(:@@a) } - assert_false(c.class_variable_defined?(:@@a)) - - assert_raise(NameError) do - c.class_eval { remove_class_variable(:@@a) } - end - end; - end - - def test_run_out_of_shape_generic_instance_variable_set - assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") - begin; - class TooComplex < Hash - end - - RubyVM::Shape.exhaust_shapes - - tc = TooComplex.new - tc.instance_variable_set(:@a, 1) - tc.instance_variable_set(:@b, 2) - - tc.remove_instance_variable(:@a) - assert_nil(tc.instance_variable_get(:@a)) - - assert_raise(NameError) do - tc.remove_instance_variable(:@a) - end - end; - end - - def test_run_out_of_shape_generic_ivar_set - assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") - begin; - class Hi < String - def initialize - 8.times do |i| - instance_variable_set("@ivar_#{i}", i) - end - end - - def transition - @hi_transition ||= 1 - end - end - - a = Hi.new - - # Try to run out of shapes - RubyVM::Shape.exhaust_shapes - - assert_equal 1, a.transition - assert_equal 1, a.transition - end; - end - - def test_run_out_of_shape_instance_variable_defined - assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") - begin; - class A - attr_reader :a, :b, :c, :d - def initialize - @a = @b = @c = @d = 1 - end - end - - RubyVM::Shape.exhaust_shapes - - a = A.new - assert_equal true, a.instance_variable_defined?(:@a) - end; - end - - def test_run_out_of_shape_instance_variable_defined_on_module - assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") - begin; - RubyVM::Shape.exhaust_shapes - - module A - @a = @b = @c = @d = 1 - end - - assert_equal true, A.instance_variable_defined?(:@a) - end; - end - - def test_run_out_of_shape_during_remove_instance_variable - assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") - begin; - o = Object.new - 10.times { |i| o.instance_variable_set(:"@a#{i}", i) } - - RubyVM::Shape.exhaust_shapes - - o.remove_instance_variable(:@a0) - (1...10).each do |i| - assert_equal(i, o.instance_variable_get(:"@a#{i}")) - end - end; - end - - def test_run_out_of_shape_remove_instance_variable - assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") - begin; - class A - attr_reader :a, :b, :c, :d - def initialize - @a = @b = @c = @d = 1 - end - end - - a = A.new - - RubyVM::Shape.exhaust_shapes - - a.remove_instance_variable(:@b) - assert_nil a.b - - a.remove_instance_variable(:@a) - assert_nil a.a - - a.remove_instance_variable(:@c) - assert_nil a.c - - assert_equal 1, a.d - end; - end - - def test_run_out_of_shape_rb_obj_copy_ivar - assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") - begin; - class A - def initialize - init # Avoid right sizing - end - - def init - @a = @b = @c = @d = @e = @f = 1 - end - end - - a = A.new - - RubyVM::Shape.exhaust_shapes - - a.dup - end; - end - - def test_evacuate_generic_ivar_memory_leak - assert_no_memory_leak([], "#{<<~'begin;'}", "#{<<~'end;'}", rss: true) - o = [] - o.instance_variable_set(:@a, 1) - - RubyVM::Shape.exhaust_shapes - - ary = 1_000_000.times.map { [] } - begin; - ary.each do |o| - o.instance_variable_set(:@a, 1) - o.instance_variable_set(:@b, 1) - end - ary.clear - ary = nil - GC.start - end; - end - - def test_use_all_shapes_module - assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") - begin; - class Hi; end - - RubyVM::Shape.exhaust_shapes(2) - - obj = Module.new - 3.times do - obj.instance_variable_set(:"@a#{_1}", _1) - end - - ivs = 3.times.map do - obj.instance_variable_get(:"@a#{_1}") - end - - assert_equal [0, 1, 2], ivs - end; - end - - def test_complex_freeze_after_clone - assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") - begin; - class Hi; end - - RubyVM::Shape.exhaust_shapes(2) - - obj = Object.new - i = 0 - while RubyVM::Shape.shapes_available > 0 - obj.instance_variable_set(:"@b#{i}", i) - i += 1 - end - - v = obj.clone(freeze: true) - assert_predicate v, :frozen? - assert_equal 0, v.instance_variable_get(:@b0) - end; - 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_too_complex_obj_ivar_ractor_share - assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") - begin; - $VERBOSE = nil - - RubyVM::Shape.exhaust_shapes - - r = Ractor.new do - o = Object.new - o.instance_variable_set(:@a, "hello") - Ractor.yield(o) - end - - o = r.take - assert_equal "hello", o.instance_variable_get(:@a) - end; - end - - def test_too_complex_generic_ivar_ractor_share - assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") - begin; - $VERBOSE = nil - - RubyVM::Shape.exhaust_shapes - - r = Ractor.new do - o = [] - o.instance_variable_set(:@a, "hello") - Ractor.yield(o) - end - - o = r.take - assert_equal "hello", o.instance_variable_get(:@a) - 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_remove_instance_variable - ivars_count = 5 - object = Object.new - ivars_count.times do |i| - object.instance_variable_set("@ivar_#{i}", i) - end - - ivars = ivars_count.times.map do |i| - object.instance_variable_get("@ivar_#{i}") - end - assert_equal [0, 1, 2, 3, 4], ivars - - object.remove_instance_variable(:@ivar_2) - - ivars = ivars_count.times.map do |i| - object.instance_variable_get("@ivar_#{i}") - end - assert_equal [0, 1, nil, 3, 4], ivars - end - - def test_remove_instance_variable_when_out_of_shapes - assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") - begin; - ivars_count = 5 - object = Object.new - ivars_count.times do |i| - object.instance_variable_set("@ivar_#{i}", i) - end - - ivars = ivars_count.times.map do |i| - object.instance_variable_get("@ivar_#{i}") - end - assert_equal [0, 1, 2, 3, 4], ivars - - RubyVM::Shape.exhaust_shapes - - object.remove_instance_variable(:@ivar_2) - - ivars = ivars_count.times.map do |i| - object.instance_variable_get("@ivar_#{i}") - end - assert_equal [0, 1, nil, 3, 4], ivars - end; - end - - def test_remove_instance_variable_capacity_transition - assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") - begin; - t_object_shape = RubyVM::Shape.find_by_id(GC::INTERNAL_CONSTANTS[:SIZE_POOL_COUNT]) - assert_equal(RubyVM::Shape::SHAPE_T_OBJECT, t_object_shape.type) - - initial_capacity = t_object_shape.capacity - - # a does not transition in capacity - a = Class.new.new - initial_capacity.times do |i| - a.instance_variable_set(:"@ivar#{i + 1}", i) - end - - # b transitions in capacity - b = Class.new.new - (initial_capacity + 1).times do |i| - b.instance_variable_set(:"@ivar#{i}", i) - end - - assert_operator(RubyVM::Shape.of(a).capacity, :<, RubyVM::Shape.of(b).capacity) - - # b will now have the same tree as a - b.remove_instance_variable(:@ivar0) - - a.instance_variable_set(:@foo, 1) - a.instance_variable_set(:@bar, 1) - - # Check that there is no heap corruption - GC.verify_internal_consistency - end; - 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 } - # doesn't transition to frozen shape in this case - assert_predicate RubyVM::Shape.of(tc), :too_complex? - 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 - assert_predicate RubyVM::Shape.of(tc), :too_complex? - 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 - obj = TestObject.new - shape = RubyVM::Shape.of(obj) - assert_equal RubyVM::Shape::SHAPE_T_OBJECT, shape.type - assert_shape_equal(RubyVM::Shape.root_shape, shape.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_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_root_shape_transition_to_special_const_on_frozen - assert_equal(RubyVM::Shape::SPECIAL_CONST_SHAPE_ID, RubyVM::Shape.of([].freeze).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(1, obj.instance_variable_get(:@a)) - 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_duplicating_too_complex_objects_memory_leak - assert_no_memory_leak([], "#{<<~'begin;'}", "#{<<~'end;'}", "[Bug #20162]", rss: true) - RubyVM::Shape.exhaust_shapes - - o = Object.new - o.instance_variable_set(:@a, 0) - begin; - 1_000_000.times do - o.dup - end - end; - 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_cloning_with_freeze_option - obj = Object.new - obj2 = obj.clone(freeze: true) - assert_predicate(obj2, :frozen?) - refute_shape_equal(RubyVM::Shape.of(obj), RubyVM::Shape.of(obj2)) - assert_equal(RubyVM::Shape::SHAPE_FROZEN, RubyVM::Shape.of(obj2).type) - assert_shape_equal(RubyVM::Shape.of(obj), RubyVM::Shape.of(obj2).parent) - 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 42f2544b5a..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 # '<<' @@ -301,9 +297,6 @@ CODE assert_raise(RangeError, bug) {S("a".force_encoding(Encoding::UTF_8)) << -1} assert_raise(RangeError, bug) {S("a".force_encoding(Encoding::UTF_8)) << 0x81308130} assert_nothing_raised {S("a".force_encoding(Encoding::GB18030)) << 0x81308130} - - s = "\x95".force_encoding(Encoding::SJIS).tap(&:valid_encoding?) - assert_predicate(s << 0x5c, :valid_encoding?) end def test_MATCH # '=~' @@ -590,8 +583,6 @@ CODE assert_equal("foo", s.chomp!("\n")) s = "foo\r" assert_equal("foo", s.chomp!("\n")) - - assert_raise(ArgumentError) {String.new.chomp!("", "")} ensure $/ = save $VERBOSE = verbose @@ -657,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"))) @@ -694,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? @@ -747,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! @@ -862,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 } @@ -897,21 +867,10 @@ 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 - def test_undump_gc_compact_stress - a = S("Test") << 1 << 2 << 3 << 9 << 13 << 10 - EnvUtil.under_gc_compact_stress do - assert_equal(a, S('"Test\\x01\\x02\\x03\\t\\r\\n"').undump) - end - - EnvUtil.under_gc_compact_stress do - assert_equal(S("\u{ABCDE 10ABCD}"), S('"\\u{ABCDE 10ABCD}"').undump) - end - end - def test_dup for frozen in [ false, true ] a = S("hello") @@ -924,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 @@ -1100,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) @@ -1111,17 +1058,6 @@ CODE assert_equal("C", res[2]) end - def test_grapheme_clusters_memory_leak - assert_no_memory_leak([], "", "#{<<~"begin;"}\n#{<<~'end;'}", "[Bug #todo]", rss: true) - begin; - str = "hello world".encode(Encoding::UTF_32LE) - - 10_000.times do - str.grapheme_clusters - end - end; - end - def test_each_line verbose, $VERBOSE = $VERBOSE, nil @@ -1159,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 @@ -1167,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 @@ -1181,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} @@ -1206,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 @@ -1271,13 +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 } - end - - def test_gsub_gc_compact_stress - EnvUtil.under_gc_compact_stress { assert_equal(S("h<e>ll<o>"), S("hello").gsub(/([aeiou])/, S('<\1>'))) } + assert_raise(ArgumentError) { "foo".gsub } end def test_gsub_encoding @@ -1323,32 +1250,24 @@ CODE assert_nil(a.sub!(S('X'), S('Y'))) end - def test_gsub_bang_gc_compact_stress - EnvUtil.under_gc_compact_stress do - a = S("hello") - a.gsub!(/([aeiou])/, S('<\1>')) - assert_equal(S("h<e>ll<o>"), a) - end - 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 @@ -1358,9 +1277,6 @@ CODE assert_not_equal(S("a").hash, S("a\0").hash, bug4104) bug9172 = '[ruby-core:58658] [Bug #9172]' assert_not_equal(S("sub-setter").hash, S("discover").hash, bug9172) - assert_equal(S("").hash, S("".encode(Encoding::UTF_32BE)).hash) - h1, h2 = ["\x80", "\x81"].map {|c| c.b.hash ^ c.hash} - assert_not_equal(h1, h2) end def test_hex @@ -1381,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 @@ -1535,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() } @@ -1575,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_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").rindex(?l)) + assert_equal(6, S("ell, hello").rindex(S("ell"))) + assert_equal(7, S("ell, hello").rindex(/ll./)) - assert_rindex(nil, S("hello"), ?z, 3) - assert_rindex(nil, S("hello"), S("z"), 3) - assert_rindex(nil, S("hello"), /z./, 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) - assert_rindex(nil, S("hello"), S("z")) - assert_rindex(nil, S("hello"), /z./) + assert_nil(S("hello").rindex(?z, 3)) + assert_nil(S("hello").rindex(S("z"), 3)) + assert_nil(S("hello").rindex(/z./, 3)) - 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) - - m = assert_rindex(3, S("foo"), //) - assert_equal([3, 3], m.offset(0)) - assert_rindex(3, S("foo"), //, 4) + assert_equal(6, "foobarbarbaz".rindex(o)) + assert_raise(TypeError) { "foo".rindex(Object.new) } - 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 @@ -1664,19 +1548,6 @@ CODE assert_equal(%w[1 2 3], S("a1 a2 a3").scan(/a\K./)) end - def test_scan_gc_compact_stress - EnvUtil.under_gc_compact_stress { assert_equal([["1a"], ["2b"], ["3c"]], S("1a2b3c").scan(/(\d.)/)) } - 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) @@ -1818,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 @@ -1844,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 @@ -1883,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, /\$;/) { $; = [] } @@ -1984,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 @@ -2005,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! @@ -2072,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 @@ -2091,19 +1954,10 @@ 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 - def test_sub_gc_compact_stress - EnvUtil.under_gc_compact_stress do - m = /&(?<foo>.*?);/.match(S("aaa & yyy")) - assert_equal("amp", m["foo"]) - - assert_equal("aaa [amp] yyy", S("aaa & yyy").sub(/&(?<foo>.*?);/, S('[\k<foo>]'))) - end - end - def test_sub! a = S("hello") b = a.dup @@ -2147,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 @@ -2210,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 @@ -2233,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| @@ -2281,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 @@ -2345,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]' @@ -2361,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! @@ -2384,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! @@ -2410,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 @@ -2499,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! @@ -2573,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] @@ -2583,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] @@ -2601,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 = "" @@ -2629,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 @@ -2642,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 @@ -2684,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 @@ -2718,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| @@ -2744,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| @@ -2772,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" @@ -2782,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; @@ -2821,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 @@ -2842,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 @@ -2914,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 @@ -2951,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) @@ -2977,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) @@ -2988,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) @@ -3032,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")} @@ -3070,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) @@ -3096,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" @@ -3128,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')} @@ -3145,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) @@ -3167,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) @@ -3177,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" @@ -3229,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] @@ -3244,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 @@ -3264,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)) @@ -3276,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 ") @@ -3290,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 @@ -3332,8 +3123,6 @@ CODE end def test_eq_tilde_can_be_overridden - return unless @cls == String - assert_separately([], <<-RUBY) class String undef =~ @@ -3351,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)) @@ -3361,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 @@ -3373,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?) @@ -3396,8 +3182,6 @@ CODE end def test_uminus_frozen - return unless @cls == String - # embedded str1 = ("foobar" * 3).freeze str2 = ("foobar" * 3).freeze @@ -3414,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 3d727adf04..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) } @@ -534,20 +526,6 @@ module TestStruct assert_equal [[:req, :_]], klass.instance_method(:c=).parameters end - def test_named_structs_are_not_rooted - # [Bug #20311] - assert_no_memory_leak([], <<~PREP, <<~CODE, rss: true) - code = proc do - Struct.new("A") - Struct.send(:remove_const, :A) - end - - 1_000.times(&code) - PREP - 50_000.times(&code) - CODE - end - class TopStruct < Test::Unit::TestCase include TestStruct diff --git a/test/ruby/test_super.rb b/test/ruby/test_super.rb index ce78e66c52..6a575b88c5 100644 --- a/test/ruby/test_super.rb +++ b/test/ruby/test_super.rb @@ -558,18 +558,6 @@ class TestSuper < Test::Unit::TestCase end end - def test_zsuper_kw_splat_not_mutable - extend(Module.new{def a(**k) k[:a] = 1 end}) - extend(Module.new do - def a(**k) - before = k.dup - super - [before, k] - end - end) - assert_equal(*a) - end - def test_from_eval bug10263 = '[ruby-core:65122] [Bug #10263a]' a = Class.new do diff --git a/test/ruby/test_symbol.rb b/test/ruby/test_symbol.rb index 7f75ecd90e..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) @@ -118,12 +105,6 @@ class TestSymbol < Test::Unit::TestCase end end - def test_inspect_under_gc_compact_stress - EnvUtil.under_gc_compact_stress do - assert_inspect_evaled(':testing') - end - end - def test_name assert_equal("foo", :foo.name) assert_same(:foo.name, :foo.name) diff --git a/test/ruby/test_syntax.rb b/test/ruby/test_syntax.rb index 2d4ce59b39..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) @@ -76,122 +77,70 @@ class TestSyntax < Test::Unit::TestCase def test_anonymous_block_forwarding assert_syntax_error("def b; c(&); end", /no anonymous block parameter/) - assert_syntax_error("def b(&) ->(&) {c(&)} end", /anonymous block parameter is also used/) - assert_valid_syntax("def b(&) ->() {c(&)} end") assert_separately([], "#{<<-"begin;"}\n#{<<-'end;'}") begin; - def b(&); c(&) end - def c(&); yield 1 end - a = nil - b{|c| a = c} - assert_equal(1, a) - - def inner - yield - end - - def block_only(&) - inner(&) - end - assert_equal(1, block_only{1}) - - def pos(arg1, &) - inner(&) - end - assert_equal(2, pos(nil){2}) + def b(&); c(&) end + def c(&); yield 1 end + a = nil + b{|c| a = c} + assert_equal(1, a) + + def inner + yield + end - def pos_kwrest(arg1, **kw, &) - inner(&) - end - assert_equal(3, pos_kwrest(nil){3}) + def block_only(&) + inner(&) + end + assert_equal(1, block_only{1}) - def no_kw(arg1, **nil, &) - inner(&) - end - assert_equal(4, no_kw(nil){4}) + def pos(arg1, &) + inner(&) + end + assert_equal(2, pos(nil){2}) - def rest_kw(*a, kwarg: 1, &) - inner(&) - end - assert_equal(5, rest_kw{5}) + def pos_kwrest(arg1, **kw, &) + inner(&) + end + assert_equal(3, pos_kwrest(nil){3}) - def kw(kwarg:1, &) - inner(&) - end - assert_equal(6, kw{6}) + def no_kw(arg1, **nil, &) + inner(&) + end + assert_equal(4, no_kw(nil){4}) - def pos_kw_kwrest(arg1, kwarg:1, **kw, &) - inner(&) - end - assert_equal(7, pos_kw_kwrest(nil){7}) + def rest_kw(*a, kwarg: 1, &) + inner(&) + end + assert_equal(5, rest_kw{5}) - def pos_rkw(arg1, kwarg1:, &) - inner(&) - end - assert_equal(8, pos_rkw(nil, kwarg1: nil){8}) + def kw(kwarg:1, &) + inner(&) + end + assert_equal(6, kw{6}) - def all(arg1, arg2, *rest, post1, post2, kw1: 1, kw2: 2, okw1:, okw2:, &) - inner(&) - end - assert_equal(9, all(nil, nil, nil, nil, okw1: nil, okw2: nil){9}) + def pos_kw_kwrest(arg1, kwarg:1, **kw, &) + inner(&) + end + assert_equal(7, pos_kw_kwrest(nil){7}) - def all_kwrest(arg1, arg2, *rest, post1, post2, kw1: 1, kw2: 2, okw1:, okw2:, **kw, &) - inner(&) - end - assert_equal(10, all_kwrest(nil, nil, nil, nil, okw1: nil, okw2: nil){10}) - end; - end + def pos_rkw(arg1, kwarg1:, &) + inner(&) + end + assert_equal(8, pos_rkw(nil, kwarg1: nil){8}) - 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_syntax_error("def b(*) ->(*) {c(*)} end", /anonymous rest parameter is also used/) - assert_syntax_error("def b(a, *) ->(*) {c(1, *)} end", /anonymous rest parameter is also used/) - assert_syntax_error("def b(*) ->(a, *) {c(*)} end", /anonymous rest parameter is also used/) - assert_valid_syntax("def b(*) ->() {c(*)} end") - assert_valid_syntax("def b(a, *) ->() {c(1, *)} end") - assert_valid_syntax("def b(*) ->(a) {c(*)} end") - 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 all(arg1, arg2, *rest, post1, post2, kw1: 1, kw2: 2, okw1:, okw2:, &) + inner(&) + end + assert_equal(9, all(nil, nil, nil, nil, okw1: nil, okw2: nil){9}) - 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_syntax_error("def b(**) ->(**) {c(**)} end", /anonymous keyword rest parameter is also used/) - assert_syntax_error("def b(k:, **) ->(**) {c(k: 1, **)} end", /anonymous keyword rest parameter is also used/) - assert_syntax_error("def b(**) ->(k:, **) {c(**)} end", /anonymous keyword rest parameter is also used/) - assert_valid_syntax("def b(**) ->() {c(**)} end") - assert_valid_syntax("def b(k:, **) ->() {c(k: 1, **)} end") - assert_valid_syntax("def b(**) ->(k:) {c(**)} end") - 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)) + def all_kwrest(arg1, arg2, *rest, post1, post2, kw1: 1, kw2: 2, okw1:, okw2:, **kw, &) + inner(&) + end + assert_equal(10, all_kwrest(nil, nil, nil, nil, okw1: nil, okw2: nil){10}) 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| @@ -349,12 +298,6 @@ class TestSyntax < Test::Unit::TestCase assert_warn(/duplicated/) {r = eval("a.f(**{k: a.add(1), j: a.add(2), k: a.add(3), k: a.add(4)})")} assert_equal(4, r) assert_equal([1, 2, 3, 4], a) - a.clear - r = nil - _z = {} - assert_warn(/duplicated/) {r = eval("a.f(k: a.add(1), **_z, k: a.add(2))")} - assert_equal(2, r) - assert_equal([1, 2], a) end def test_keyword_empty_splat @@ -656,8 +599,6 @@ WARN assert_equal(42, obj.foo(42)) assert_equal(42, obj.foo(2, _: 0)) assert_equal(2, obj.foo(x: 2, _: 0)) - ensure - self.class.remove_method(:foo) end def test_duplicated_opt_kw @@ -1011,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 @@ -1043,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 @@ -1390,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| @@ -1421,54 +1360,6 @@ eom end end - def test_eval_return_toplevel - feature4840 = '[ruby-core:36785] [Feature #4840]' - line = __LINE__+2 - code = "#{<<~"begin;"}#{<<~'end;'}" - begin; - eval "return"; raise - begin eval "return"; rescue SystemExit; exit false; end - begin eval "return"; ensure puts "ensured"; end #=> ensured - begin ensure eval "return"; end - begin raise; ensure; eval "return"; end - begin raise; rescue; eval "return"; end - eval "return false"; raise - eval "return 1"; raise - "#{eval "return"}" - raise((eval "return"; "should not raise")) - begin raise; ensure eval "return"; end; self - begin raise; ensure eval "return"; end and self - eval "return puts('ignored')" #=> ignored - BEGIN {eval "return"} - end; - .split(/\n/).map {|s|[(line+=1), *s.split(/#=> /, 2)]} - failed = proc do |n, s| - RubyVM::InstructionSequence.compile(s, __FILE__, nil, n).disasm - end - Tempfile.create(%w"test_return_ .rb") do |lib| - lib.close - args = %W[-W0 -r#{lib.path}] - all_assertions_foreach(feature4840, *[:main, :lib].product([:class, :top], code)) do |main, klass, (n, s, *ex)| - if klass == :class - s = "class X; #{s}; end" - if main == :main - assert_in_out_err(%[-W0], s, ex, /return/, proc {failed[n, s]}, success: false) - else - File.write(lib, s) - assert_in_out_err(args, "", ex, /return/, proc {failed[n, s]}, success: false) - end - else - if main == :main - assert_in_out_err(%[-W0], s, ex, [], proc {failed[n, s]}, success: true) - else - File.write(lib, s) - assert_in_out_err(args, "", ex, [], proc {failed[n, s]}, success: true) - end - end - end - end - end - def test_return_toplevel_with_argument assert_warn(/argument of top-level return is ignored/) {eval("return 1")} end @@ -1477,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) @@ -1710,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 @@ -1778,23 +1632,6 @@ eom assert_raise(NameError) {eval("_1")}, ] } - - assert_valid_syntax("proc {def foo(_);end;_1}") - assert_valid_syntax("p { [_1 **2] }") - assert_valid_syntax("proc {_1;def foo();end;_1}") - end - - def test_it - assert_no_warning(/`it`/) {eval('if false; it; end')} - assert_no_warning(/`it`/) {eval('def foo; it; end')} - assert_warn(/`it`/) {eval('0.times { it }')} - assert_no_warning(/`it`/) {eval('0.times { || it }')} - assert_no_warning(/`it`/) {eval('0.times { |_n| it }')} - assert_warn(/`it`/) {eval('0.times { it; it = 1; it }')} - assert_no_warning(/`it`/) {eval('0.times { it = 1; it }')} - assert_no_warning(/`it`/) {eval('it = 1; 0.times { it }')} - ensure - self.class.remove_method(:foo) end def test_value_expr_in_condition @@ -1805,11 +1642,6 @@ eom assert_valid_syntax("tap {a = (break unless true)}") end - def test_value_expr_in_singleton - mesg = /void value expression/ - assert_syntax_error("class << (return); end", mesg) - end - def test_tautological_condition assert_valid_syntax("def f() return if false and invalid; nil end") assert_valid_syntax("def f() return unless true or invalid; nil end") @@ -1847,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) @@ -2049,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 da14c429e6..41cee124be 100644 --- a/test/ruby/test_thread.rb +++ b/test/ruby/test_thread.rb @@ -3,7 +3,6 @@ require 'test/unit' require "rbconfig/sizeof" require "timeout" -require "fiddle" class TestThread < Test::Unit::TestCase class Thread < ::Thread @@ -30,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 @@ -324,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? @@ -396,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 } @@ -507,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 @@ -738,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) @@ -973,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' @@ -1077,7 +1068,7 @@ q.pop puts mth.status Process.kill(:INT, $$) } - sleep + sleep 0.1 INPUT end @@ -1264,7 +1255,6 @@ q.pop assert_predicate(status, :success?, bug18902) ensure th.kill - th.join end end if Process.respond_to?(:fork) @@ -1280,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 = [] @@ -1301,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 @@ -1362,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} @@ -1424,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} @@ -1435,8 +1370,7 @@ q.pop Thread.pass until th1.stop? # After a thread starts (and execute `sleep`), it returns native_thread_id - native_tid = th1.native_thread_id - assert_instance_of Integer, native_tid if native_tid # it can be nil + assert_instance_of Integer, th1.native_thread_id th1.wakeup Thread.pass while th1.alive? @@ -1445,40 +1379,11 @@ q.pop assert_nil th1.native_thread_id end - def test_thread_native_thread_id_across_fork_on_linux - rtld_default = Fiddle.dlopen(nil) - omit "this test is only for Linux" unless rtld_default.sym_defined?('gettid') - - gettid = Fiddle::Function.new(rtld_default['gettid'], [], Fiddle::TYPE_INT) - - parent_thread_id = Thread.main.native_thread_id - real_parent_thread_id = gettid.call - - assert_equal real_parent_thread_id, parent_thread_id - - child_lines = nil - IO.popen('-') do |pipe| - if pipe - # parent - child_lines = pipe.read.lines - else - # child - puts Thread.main.native_thread_id - puts gettid.call - end - end - child_thread_id = child_lines[0].chomp.to_i - real_child_thread_id = child_lines[1].chomp.to_i - - assert_equal real_child_thread_id, child_thread_id - refute_equal parent_thread_id, child_thread_id - end - 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 @@ -1493,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 @@ -1547,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 545bf98888..3fa0eae2c1 100644 --- a/test/ruby/test_thread_queue.rb +++ b/test/ruby/test_thread_queue.rb @@ -8,23 +8,14 @@ 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/) { - SizedQueue.allocate.push(nil) - } - end - - def test_freeze - assert_raise(TypeError) { - Queue.new.freeze - } assert_raise(TypeError) { - SizedQueue.new(5).freeze + SizedQueue.allocate.push(nil) } end @@ -120,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 @@ -152,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 @@ -177,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) @@ -213,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 @@ -594,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 @@ -619,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 @@ -651,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 2a541bbe8c..36c79273db 100644 --- a/test/ruby/test_time.rb +++ b/test/ruby/test_time.rb @@ -58,102 +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(Time.new(2021, 12, 25, in: "+09:00"), Time.new("2021-12-25+09:00", in: "-01: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)) @@ -215,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) @@ -439,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) @@ -1282,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) @@ -1407,41 +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[:RVALUE_OVERHEAD] > 0 - omit "memsize is not accurate due to using malloc_usable_size" if GC::INTERNAL_CONSTANTS[:SIZE_POOL_COUNT] == 1 - omit "Only run this test on 64-bit" if RbConfig::SIZEOF["void*"] != 8 - + 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 - assert_operator ObjectSpace.memsize_of(t), :<=, expect + 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 f66cd9bec2..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 @@ -695,13 +695,6 @@ module TestTimeTZ::WithTZ assert_equal(t.dst?, t2.dst?) end - def subtest_fractional_second(time_class, tz, tzarg, tzname, abbr, utc_offset) - t = time_class.new(2024, 1, 1, 23, 59, 59.9r, tzarg) - assert_equal(utc_offset[t.dst? ? 1 : 0], t.utc_offset) - t = time_class.new(2024, 7, 1, 23, 59, 59.9r, tzarg) - assert_equal(utc_offset[t.dst? ? 1 : 0], t.utc_offset) - end - def test_invalid_zone make_timezone("INVALID", "INV", 0) rescue => e @@ -726,7 +719,6 @@ module TestTimeTZ::WithTZ "Asia/Tokyo" => ["JST", +9*3600], "America/Los_Angeles" => ["PST", -8*3600, "PDT", -7*3600], "Africa/Ndjamena" => ["WAT", +1*3600], - "Etc/UTC" => ["UTC", 0], } def make_timezone(tzname, abbr, utc_offset, abbr2 = nil, utc_offset2 = nil) diff --git a/test/ruby/test_transcode.rb b/test/ruby/test_transcode.rb index 4b63263aae..c8b0034e06 100644 --- a/test/ruby/test_transcode.rb +++ b/test/ruby/test_transcode.rb @@ -10,9 +10,9 @@ class TestTranscode < Test::Unit::TestCase assert_raise(Encoding::ConverterNotFoundError) { 'abc'.encode!('foo', 'bar') } assert_raise(Encoding::ConverterNotFoundError) { 'abc'.force_encoding('utf-8').encode('foo') } assert_raise(Encoding::ConverterNotFoundError) { 'abc'.force_encoding('utf-8').encode!('foo') } - assert_undefined_in("\x80", 'ASCII-8BIT') - assert_invalid_in("\x80", 'US-ASCII') - assert_undefined_in("\xA5", 'iso-8859-3') + assert_raise(Encoding::UndefinedConversionError) { "\x80".encode('utf-8','ASCII-8BIT') } + assert_raise(Encoding::InvalidByteSequenceError) { "\x80".encode('utf-8','US-ASCII') } + assert_raise(Encoding::UndefinedConversionError) { "\xA5".encode('utf-8','iso-8859-3') } assert_raise(FrozenError) { 'hello'.freeze.encode!('iso-8859-1') } assert_raise(FrozenError) { '\u3053\u3093\u306b\u3061\u306f'.freeze.encode!('iso-8859-1') } # こんにちは end @@ -52,6 +52,16 @@ class TestTranscode < Test::Unit::TestCase assert_equal("\u20AC"*200000, ("\xA4"*200000).encode!('utf-8', 'iso-8859-15')) end + def check_both_ways(utf8, raw, encoding) + assert_equal(utf8.force_encoding('utf-8'), raw.encode('utf-8', encoding),utf8.dump+raw.dump) + assert_equal(raw.force_encoding(encoding), utf8.encode(encoding, 'utf-8')) + end + + def check_both_ways2(str1, enc1, str2, enc2) + assert_equal(str1.force_encoding(enc1), str2.encode(enc1, enc2)) + assert_equal(str2.force_encoding(enc2), str1.encode(enc2, enc1)) + end + def test_encoding_of_ascii_originating_from_binary binary_string = [0x82, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x6c, 0x6f, @@ -178,16 +188,16 @@ class TestTranscode < Test::Unit::TestCase def test_windows_874 check_both_ways("\u20AC", "\x80", 'windows-874') # € - assert_undefined_in("\x81", 'windows-874') - assert_undefined_in("\x84", 'windows-874') + assert_raise(Encoding::UndefinedConversionError) { "\x81".encode("utf-8", 'windows-874') } + assert_raise(Encoding::UndefinedConversionError) { "\x84".encode("utf-8", 'windows-874') } check_both_ways("\u2026", "\x85", 'windows-874') # … - assert_undefined_in("\x86", 'windows-874') - assert_undefined_in("\x8F", 'windows-874') - assert_undefined_in("\x90", 'windows-874') + assert_raise(Encoding::UndefinedConversionError) { "\x86".encode("utf-8", 'windows-874') } + assert_raise(Encoding::UndefinedConversionError) { "\x8F".encode("utf-8", 'windows-874') } + assert_raise(Encoding::UndefinedConversionError) { "\x90".encode("utf-8", 'windows-874') } check_both_ways("\u2018", "\x91", 'windows-874') # ‘ check_both_ways("\u2014", "\x97", 'windows-874') # — - assert_undefined_in("\x98", 'windows-874') - assert_undefined_in("\x9F", 'windows-874') + assert_raise(Encoding::UndefinedConversionError) { "\x98".encode("utf-8", 'windows-874') } + assert_raise(Encoding::UndefinedConversionError) { "\x9F".encode("utf-8", 'windows-874') } check_both_ways("\u00A0", "\xA0", 'windows-874') # non-breaking space check_both_ways("\u0E0F", "\xAF", 'windows-874') # ฏ check_both_ways("\u0E10", "\xB0", 'windows-874') # ฐ @@ -196,31 +206,31 @@ class TestTranscode < Test::Unit::TestCase check_both_ways("\u0E2F", "\xCF", 'windows-874') # ฯ check_both_ways("\u0E30", "\xD0", 'windows-874') # ะ check_both_ways("\u0E3A", "\xDA", 'windows-874') # ฺ - assert_undefined_in("\xDB", 'windows-874') - assert_undefined_in("\xDE", 'windows-874') + assert_raise(Encoding::UndefinedConversionError) { "\xDB".encode("utf-8", 'windows-874') } + assert_raise(Encoding::UndefinedConversionError) { "\xDE".encode("utf-8", 'windows-874') } check_both_ways("\u0E3F", "\xDF", 'windows-874') # ฿ check_both_ways("\u0E40", "\xE0", 'windows-874') # เ check_both_ways("\u0E4F", "\xEF", 'windows-874') # ๏ check_both_ways("\u0E50", "\xF0", 'windows-874') # ๐ check_both_ways("\u0E5B", "\xFB", 'windows-874') # ๛ - assert_undefined_in("\xFC", 'windows-874') - assert_undefined_in("\xFF", 'windows-874') + assert_raise(Encoding::UndefinedConversionError) { "\xFC".encode("utf-8", 'windows-874') } + assert_raise(Encoding::UndefinedConversionError) { "\xFF".encode("utf-8", 'windows-874') } end def test_windows_1250 check_both_ways("\u20AC", "\x80", 'windows-1250') # € - assert_undefined_in("\x81", 'windows-1250') + assert_raise(Encoding::UndefinedConversionError) { "\x81".encode("utf-8", 'windows-1250') } check_both_ways("\u201A", "\x82", 'windows-1250') # ‚ - assert_undefined_in("\x83", 'windows-1250') + assert_raise(Encoding::UndefinedConversionError) { "\x83".encode("utf-8", 'windows-1250') } check_both_ways("\u201E", "\x84", 'windows-1250') # „ check_both_ways("\u2021", "\x87", 'windows-1250') # ‡ - assert_undefined_in("\x88", 'windows-1250') + assert_raise(Encoding::UndefinedConversionError) { "\x88".encode("utf-8", 'windows-1250') } check_both_ways("\u2030", "\x89", 'windows-1250') # ‰ check_both_ways("\u0179", "\x8F", 'windows-1250') # Ź - assert_undefined_in("\x90", 'windows-1250') + assert_raise(Encoding::UndefinedConversionError) { "\x90".encode("utf-8", 'windows-1250') } check_both_ways("\u2018", "\x91", 'windows-1250') # ‘ check_both_ways("\u2014", "\x97", 'windows-1250') # — - assert_undefined_in("\x98", 'windows-1250') + assert_raise(Encoding::UndefinedConversionError) { "\x98".encode("utf-8", 'windows-1250') } check_both_ways("\u2122", "\x99", 'windows-1250') # ™ check_both_ways("\u00A0", "\xA0", 'windows-1250') # non-breaking space check_both_ways("\u017B", "\xAF", 'windows-1250') # Ż @@ -241,7 +251,7 @@ class TestTranscode < Test::Unit::TestCase check_both_ways("\u20AC", "\x88", 'windows-1251') # € check_both_ways("\u040F", "\x8F", 'windows-1251') # Џ check_both_ways("\u0452", "\x90", 'windows-1251') # ђ - assert_undefined_in("\x98", 'windows-1251') + assert_raise(Encoding::UndefinedConversionError) { "\x98".encode("utf-8", 'windows-1251') } check_both_ways("\u045F", "\x9F", 'windows-1251') # џ check_both_ways("\u00A0", "\xA0", 'windows-1251') # non-breaking space check_both_ways("\u0407", "\xAF", 'windows-1251') # Ї @@ -259,16 +269,16 @@ class TestTranscode < Test::Unit::TestCase def test_windows_1252 check_both_ways("\u20AC", "\x80", 'windows-1252') # € - assert_undefined_in("\x81", 'windows-1252') + assert_raise(Encoding::UndefinedConversionError) { "\x81".encode("utf-8", 'windows-1252') } check_both_ways("\u201A", "\x82", 'windows-1252') # ‚ check_both_ways("\u0152", "\x8C", 'windows-1252') # >Œ - assert_undefined_in("\x8D", 'windows-1252') + assert_raise(Encoding::UndefinedConversionError) { "\x8D".encode("utf-8", 'windows-1252') } check_both_ways("\u017D", "\x8E", 'windows-1252') # Ž - assert_undefined_in("\x8F", 'windows-1252') - assert_undefined_in("\x90", 'windows-1252') + assert_raise(Encoding::UndefinedConversionError) { "\x8F".encode("utf-8", 'windows-1252') } + assert_raise(Encoding::UndefinedConversionError) { "\x90".encode("utf-8", 'windows-1252') } check_both_ways("\u2018", "\x91", 'windows-1252') #‘ check_both_ways("\u0153", "\x9C", 'windows-1252') # œ - assert_undefined_in("\x9D", 'windows-1252') + assert_raise(Encoding::UndefinedConversionError) { "\x9D".encode("utf-8", 'windows-1252') } check_both_ways("\u017E", "\x9E", 'windows-1252') # ž check_both_ways("\u00A0", "\xA0", 'windows-1252') # non-breaking space check_both_ways("\u00AF", "\xAF", 'windows-1252') # ¯ @@ -286,24 +296,24 @@ class TestTranscode < Test::Unit::TestCase def test_windows_1253 check_both_ways("\u20AC", "\x80", 'windows-1253') # € - assert_undefined_in("\x81", 'windows-1253') + assert_raise(Encoding::UndefinedConversionError) { "\x81".encode("utf-8", 'windows-1253') } check_both_ways("\u201A", "\x82", 'windows-1253') # ‚ check_both_ways("\u2021", "\x87", 'windows-1253') # ‡ - assert_undefined_in("\x88", 'windows-1253') + assert_raise(Encoding::UndefinedConversionError) { "\x88".encode("utf-8", 'windows-1253') } check_both_ways("\u2030", "\x89", 'windows-1253') # ‰ - assert_undefined_in("\x8A", 'windows-1253') + assert_raise(Encoding::UndefinedConversionError) { "\x8A".encode("utf-8", 'windows-1253') } check_both_ways("\u2039", "\x8B", 'windows-1253') # ‹ - assert_undefined_in("\x8C", 'windows-1253') - assert_undefined_in("\x8F", 'windows-1253') - assert_undefined_in("\x90", 'windows-1253') + assert_raise(Encoding::UndefinedConversionError) { "\x8C".encode("utf-8", 'windows-1253') } + assert_raise(Encoding::UndefinedConversionError) { "\x8F".encode("utf-8", 'windows-1253') } + assert_raise(Encoding::UndefinedConversionError) { "\x90".encode("utf-8", 'windows-1253') } check_both_ways("\u2018", "\x91", 'windows-1253') # ‘ check_both_ways("\u2014", "\x97", 'windows-1253') # — - assert_undefined_in("\x98", 'windows-1253') + assert_raise(Encoding::UndefinedConversionError) { "\x98".encode("utf-8", 'windows-1253') } check_both_ways("\u2122", "\x99", 'windows-1253') # ™ - assert_undefined_in("\x9A", 'windows-1253') + assert_raise(Encoding::UndefinedConversionError) { "\x9A".encode("utf-8", 'windows-1253') } check_both_ways("\u203A", "\x9B", 'windows-1253') # › - assert_undefined_in("\x9C", 'windows-1253') - assert_undefined_in("\x9F", 'windows-1253') + assert_raise(Encoding::UndefinedConversionError) { "\x9C".encode("utf-8", 'windows-1253') } + assert_raise(Encoding::UndefinedConversionError) { "\x9F".encode("utf-8", 'windows-1253') } check_both_ways("\u00A0", "\xA0", 'windows-1253') # non-breaking space check_both_ways("\u2015", "\xAF", 'windows-1253') # ― check_both_ways("\u00B0", "\xB0", 'windows-1253') # ° @@ -312,28 +322,28 @@ class TestTranscode < Test::Unit::TestCase check_both_ways("\u039F", "\xCF", 'windows-1253') # Ο check_both_ways("\u03A0", "\xD0", 'windows-1253') # Π check_both_ways("\u03A1", "\xD1", 'windows-1253') # Ρ - assert_undefined_in("\xD2", 'windows-1253') + assert_raise(Encoding::UndefinedConversionError) { "\xD2".encode("utf-8", 'windows-1253') } check_both_ways("\u03A3", "\xD3", 'windows-1253') # Σ check_both_ways("\u03AF", "\xDF", 'windows-1253') # ί check_both_ways("\u03B0", "\xE0", 'windows-1253') # ΰ check_both_ways("\u03BF", "\xEF", 'windows-1253') # ο check_both_ways("\u03C0", "\xF0", 'windows-1253') # π check_both_ways("\u03CE", "\xFE", 'windows-1253') # ώ - assert_undefined_in("\xFF", 'windows-1253') + assert_raise(Encoding::UndefinedConversionError) { "\xFF".encode("utf-8", 'windows-1253') } end def test_windows_1254 check_both_ways("\u20AC", "\x80", 'windows-1254') # € - assert_undefined_in("\x81", 'windows-1254') + assert_raise(Encoding::UndefinedConversionError) { "\x81".encode("utf-8", 'windows-1254') } check_both_ways("\u201A", "\x82", 'windows-1254') # ‚ check_both_ways("\u0152", "\x8C", 'windows-1254') # Œ - assert_undefined_in("\x8D", 'windows-1254') - assert_undefined_in("\x8F", 'windows-1254') - assert_undefined_in("\x90", 'windows-1254') + assert_raise(Encoding::UndefinedConversionError) { "\x8D".encode("utf-8", 'windows-1254') } + assert_raise(Encoding::UndefinedConversionError) { "\x8F".encode("utf-8", 'windows-1254') } + assert_raise(Encoding::UndefinedConversionError) { "\x90".encode("utf-8", 'windows-1254') } check_both_ways("\u2018", "\x91", 'windows-1254') # ‘ check_both_ways("\u0153", "\x9C", 'windows-1254') # œ - assert_undefined_in("\x9D", 'windows-1254') - assert_undefined_in("\x9E", 'windows-1254') + assert_raise(Encoding::UndefinedConversionError) { "\x9D".encode("utf-8", 'windows-1254') } + assert_raise(Encoding::UndefinedConversionError) { "\x9E".encode("utf-8", 'windows-1254') } check_both_ways("\u0178", "\x9F", 'windows-1254') # Ÿ check_both_ways("\u00A0", "\xA0", 'windows-1254') # non-breaking space check_both_ways("\u00AF", "\xAF", 'windows-1254') # ¯ @@ -351,20 +361,20 @@ class TestTranscode < Test::Unit::TestCase def test_windows_1255 check_both_ways("\u20AC", "\x80", 'windows-1255') # € - assert_undefined_in("\x81", 'windows-1255') + assert_raise(Encoding::UndefinedConversionError) { "\x81".encode("utf-8", 'windows-1255') } check_both_ways("\u201A", "\x82", 'windows-1255') # ‚ check_both_ways("\u2030", "\x89", 'windows-1255') # ‰ - assert_undefined_in("\x8A", 'windows-1255') + assert_raise(Encoding::UndefinedConversionError) { "\x8A".encode("utf-8", 'windows-1255') } check_both_ways("\u2039", "\x8B", 'windows-1255') # ‹ - assert_undefined_in("\x8C", 'windows-1255') - assert_undefined_in("\x8F", 'windows-1255') - assert_undefined_in("\x90", 'windows-1255') + assert_raise(Encoding::UndefinedConversionError) { "\x8C".encode("utf-8", 'windows-1255') } + assert_raise(Encoding::UndefinedConversionError) { "\x8F".encode("utf-8", 'windows-1255') } + assert_raise(Encoding::UndefinedConversionError) { "\x90".encode("utf-8", 'windows-1255') } check_both_ways("\u2018", "\x91", 'windows-1255') # ‘ check_both_ways("\u2122", "\x99", 'windows-1255') # ™ - assert_undefined_in("\x9A", 'windows-1255') + assert_raise(Encoding::UndefinedConversionError) { "\x9A".encode("utf-8", 'windows-1255') } check_both_ways("\u203A", "\x9B", 'windows-1255') # › - assert_undefined_in("\x9C", 'windows-1255') - assert_undefined_in("\x9F", 'windows-1255') + assert_raise(Encoding::UndefinedConversionError) { "\x9C".encode("utf-8", 'windows-1255') } + assert_raise(Encoding::UndefinedConversionError) { "\x9F".encode("utf-8", 'windows-1255') } check_both_ways("\u00A0", "\xA0", 'windows-1255') # non-breaking space check_both_ways("\u00A1", "\xA1", 'windows-1255') # ¡ check_both_ways("\u00D7", "\xAA", 'windows-1255') # × @@ -381,17 +391,17 @@ class TestTranscode < Test::Unit::TestCase check_both_ways("\u05C0", "\xD0", 'windows-1255') # ׀ check_both_ways("\u05F3", "\xD7", 'windows-1255') # ׳ check_both_ways("\u05F4", "\xD8", 'windows-1255') # ״ - assert_undefined_in("\xD9", 'windows-1255') - assert_undefined_in("\xDF", 'windows-1255') + assert_raise(Encoding::UndefinedConversionError) { "\xD9".encode("utf-8", 'windows-1255') } + assert_raise(Encoding::UndefinedConversionError) { "\xDF".encode("utf-8", 'windows-1255') } check_both_ways("\u05D0", "\xE0", 'windows-1255') # א check_both_ways("\u05DF", "\xEF", 'windows-1255') # ן check_both_ways("\u05E0", "\xF0", 'windows-1255') # נ check_both_ways("\u05EA", "\xFA", 'windows-1255') # ת - assert_undefined_in("\xFB", 'windows-1255') - assert_undefined_in("\xFC", 'windows-1255') + assert_raise(Encoding::UndefinedConversionError) { "\xFB".encode("utf-8", 'windows-1255') } + assert_raise(Encoding::UndefinedConversionError) { "\xFC".encode("utf-8", 'windows-1255') } check_both_ways("\u200E", "\xFD", 'windows-1255') # left-to-right mark check_both_ways("\u200F", "\xFE", 'windows-1255') # right-to-left mark - assert_undefined_in("\xFF", 'windows-1255') + assert_raise(Encoding::UndefinedConversionError) { "\xFF".encode("utf-8", 'windows-1255') } end def test_windows_1256 @@ -419,35 +429,35 @@ class TestTranscode < Test::Unit::TestCase def test_windows_1257 check_both_ways("\u20AC", "\x80", 'windows-1257') # € - assert_undefined_in("\x81", 'windows-1257') + assert_raise(Encoding::UndefinedConversionError) { "\x81".encode("utf-8", 'windows-1257') } check_both_ways("\u201A", "\x82", 'windows-1257') # ‚ - assert_undefined_in("\x83", 'windows-1257') + assert_raise(Encoding::UndefinedConversionError) { "\x83".encode("utf-8", 'windows-1257') } check_both_ways("\u201E", "\x84", 'windows-1257') # „ check_both_ways("\u2021", "\x87", 'windows-1257') # ‡ - assert_undefined_in("\x88", 'windows-1257') + assert_raise(Encoding::UndefinedConversionError) { "\x88".encode("utf-8", 'windows-1257') } check_both_ways("\u2030", "\x89", 'windows-1257') # ‰ - assert_undefined_in("\x8A", 'windows-1257') + assert_raise(Encoding::UndefinedConversionError) { "\x8A".encode("utf-8", 'windows-1257') } check_both_ways("\u2039", "\x8B", 'windows-1257') # ‹ - assert_undefined_in("\x8C", 'windows-1257') + assert_raise(Encoding::UndefinedConversionError) { "\x8C".encode("utf-8", 'windows-1257') } check_both_ways("\u00A8", "\x8D", 'windows-1257') # ¨ check_both_ways("\u02C7", "\x8E", 'windows-1257') # ˇ check_both_ways("\u00B8", "\x8F", 'windows-1257') # ¸ - assert_undefined_in("\x90", 'windows-1257') + assert_raise(Encoding::UndefinedConversionError) { "\x90".encode("utf-8", 'windows-1257') } check_both_ways("\u2018", "\x91", 'windows-1257') # ‘ check_both_ways("\u2014", "\x97", 'windows-1257') # — - assert_undefined_in("\x98", 'windows-1257') + assert_raise(Encoding::UndefinedConversionError) { "\x98".encode("utf-8", 'windows-1257') } check_both_ways("\u2122", "\x99", 'windows-1257') # ™ - assert_undefined_in("\x9A", 'windows-1257') + assert_raise(Encoding::UndefinedConversionError) { "\x9A".encode("utf-8", 'windows-1257') } check_both_ways("\u203A", "\x9B", 'windows-1257') # › - assert_undefined_in("\x9C", 'windows-1257') + assert_raise(Encoding::UndefinedConversionError) { "\x9C".encode("utf-8", 'windows-1257') } check_both_ways("\u00AF", "\x9D", 'windows-1257') # ¯ check_both_ways("\u02DB", "\x9E", 'windows-1257') # ˛ - assert_undefined_in("\x9F", 'windows-1257') + assert_raise(Encoding::UndefinedConversionError) { "\x9F".encode("utf-8", 'windows-1257') } check_both_ways("\u00A0", "\xA0", 'windows-1257') # non-breaking space - assert_undefined_in("\xA1", 'windows-1257') + assert_raise(Encoding::UndefinedConversionError) { "\xA1".encode("utf-8", 'windows-1257') } check_both_ways("\u00A2", "\xA2", 'windows-1257') # ¢ check_both_ways("\u00A4", "\xA4", 'windows-1257') # ¤ - assert_undefined_in("\xA5", 'windows-1257') + assert_raise(Encoding::UndefinedConversionError) { "\xA5".encode("utf-8", 'windows-1257') } check_both_ways("\u00A6", "\xA6", 'windows-1257') # ¦ check_both_ways("\u00C6", "\xAF", 'windows-1257') # Æ check_both_ways("\u00B0", "\xB0", 'windows-1257') # ° @@ -482,9 +492,9 @@ class TestTranscode < Test::Unit::TestCase end def test_IBM720 - assert_undefined_in("\x80", 'IBM720') - assert_undefined_in("\x8F", 'IBM720') - assert_undefined_in("\x90", 'IBM720') + assert_raise(Encoding::UndefinedConversionError) { "\x80".encode("utf-8", 'IBM720') } + assert_raise(Encoding::UndefinedConversionError) { "\x8F".encode("utf-8", 'IBM720') } + assert_raise(Encoding::UndefinedConversionError) { "\x90".encode("utf-8", 'IBM720') } check_both_ways("\u0627", "\x9F", 'IBM720') # ا check_both_ways("\u0628", "\xA0", 'IBM720') # ب check_both_ways("\u00BB", "\xAF", 'IBM720') # » @@ -570,17 +580,17 @@ class TestTranscode < Test::Unit::TestCase check_both_ways("\u00A4", "\xCF", 'IBM857') # ¤ check_both_ways("\u00BA", "\xD0", 'IBM857') # º check_both_ways("\u00C8", "\xD4", 'IBM857') # È - assert_undefined_in("\xD5", 'IBM857') + assert_raise(Encoding::UndefinedConversionError) { "\xD5".encode("utf-8", 'IBM857') } check_both_ways("\u00CD", "\xD6", 'IBM857') # Í check_both_ways("\u2580", "\xDF", 'IBM857') # ▀ check_both_ways("\u00D3", "\xE0", 'IBM857') # Ó check_both_ways("\u00B5", "\xE6", 'IBM857') # µ - assert_undefined_in("\xE7", 'IBM857') + assert_raise(Encoding::UndefinedConversionError) { "\xE7".encode("utf-8", 'IBM857') } check_both_ways("\u00D7", "\xE8", 'IBM857') # × check_both_ways("\u00B4", "\xEF", 'IBM857') # ´ check_both_ways("\u00AD", "\xF0", 'IBM857') # soft hyphen check_both_ways("\u00B1", "\xF1", 'IBM857') # ± - assert_undefined_in("\xF2", 'IBM857') + assert_raise(Encoding::UndefinedConversionError) { "\xF2".encode("utf-8", 'IBM857') } check_both_ways("\u00BE", "\xF3", 'IBM857') # ¾ check_both_ways("\u00A0", "\xFF", 'IBM857') # non-breaking space end @@ -700,16 +710,16 @@ class TestTranscode < Test::Unit::TestCase end def test_IBM869 - assert_undefined_in("\x80", 'IBM869') - assert_undefined_in("\x85", 'IBM869') + assert_raise(Encoding::UndefinedConversionError) { "\x80".encode("utf-8", 'IBM869') } + assert_raise(Encoding::UndefinedConversionError) { "\x85".encode("utf-8", 'IBM869') } check_both_ways("\u0386", "\x86", 'IBM869') # Ά - assert_undefined_in("\x87", 'IBM869') + assert_raise(Encoding::UndefinedConversionError) { "\x87".encode("utf-8", 'IBM869') } check_both_ways("\u00B7", "\x88", 'IBM869') # · check_both_ways("\u0389", "\x8F", 'IBM869') # Ή check_both_ways("\u038A", "\x90", 'IBM869') # Ί check_both_ways("\u038C", "\x92", 'IBM869') # Ό - assert_undefined_in("\x93", 'IBM869') - assert_undefined_in("\x94", 'IBM869') + assert_raise(Encoding::UndefinedConversionError) { "\x93".encode("utf-8", 'IBM869') } + assert_raise(Encoding::UndefinedConversionError) { "\x94".encode("utf-8", 'IBM869') } check_both_ways("\u038E", "\x95", 'IBM869') # Ύ check_both_ways("\u03AF", "\x9F", 'IBM869') # ί check_both_ways("\u03CA", "\xA0", 'IBM869') # ϊ @@ -798,7 +808,7 @@ class TestTranscode < Test::Unit::TestCase check_both_ways("\u03BF", "\xEF", 'macGreek') # ο check_both_ways("\u03C0", "\xF0", 'macGreek') # π check_both_ways("\u03B0", "\xFE", 'macGreek') # ΰ - assert_undefined_in("\xFF", 'macGreek') + assert_raise(Encoding::UndefinedConversionError) { "\xFF".encode("utf-8", 'macGreek') } end def test_macIceland @@ -877,7 +887,7 @@ class TestTranscode < Test::Unit::TestCase check_both_ways("\u00D4", "\xEF", 'macTurkish') # Ô #check_both_ways("\uF8FF", "\xF0", 'macTurkish') # Apple logo check_both_ways("\u00D9", "\xF4", 'macTurkish') # Ù - assert_undefined_in("\xF5", 'macTurkish') + assert_raise(Encoding::UndefinedConversionError) { "\xF5".encode("utf-8", 'macTurkish') } check_both_ways("\u02C6", "\xF6", 'macTurkish') # ˆ check_both_ways("\u02C7", "\xFF", 'macTurkish') # ˇ end @@ -948,11 +958,11 @@ class TestTranscode < Test::Unit::TestCase end def test_TIS_620 - assert_undefined_in("\x80", 'TIS-620') - assert_undefined_in("\x8F", 'TIS-620') - assert_undefined_in("\x90", 'TIS-620') - assert_undefined_in("\x9F", 'TIS-620') - assert_undefined_in("\xA0", 'TIS-620') + assert_raise(Encoding::UndefinedConversionError) { "\x80".encode("utf-8", 'TIS-620') } + assert_raise(Encoding::UndefinedConversionError) { "\x8F".encode("utf-8", 'TIS-620') } + assert_raise(Encoding::UndefinedConversionError) { "\x90".encode("utf-8", 'TIS-620') } + assert_raise(Encoding::UndefinedConversionError) { "\x9F".encode("utf-8", 'TIS-620') } + assert_raise(Encoding::UndefinedConversionError) { "\xA0".encode("utf-8", 'TIS-620') } check_both_ways("\u0E01", "\xA1", 'TIS-620') # ก check_both_ways("\u0E0F", "\xAF", 'TIS-620') # ฏ check_both_ways("\u0E10", "\xB0", 'TIS-620') # ฐ @@ -961,15 +971,15 @@ class TestTranscode < Test::Unit::TestCase check_both_ways("\u0E2F", "\xCF", 'TIS-620') # ฯ check_both_ways("\u0E30", "\xD0", 'TIS-620') # ะ check_both_ways("\u0E3A", "\xDA", 'TIS-620') # ฺ - assert_undefined_in("\xDB", 'TIS-620') - assert_undefined_in("\xDE", 'TIS-620') + assert_raise(Encoding::UndefinedConversionError) { "\xDB".encode("utf-8", 'TIS-620') } + assert_raise(Encoding::UndefinedConversionError) { "\xDE".encode("utf-8", 'TIS-620') } check_both_ways("\u0E3F", "\xDF", 'TIS-620') # ฿ check_both_ways("\u0E40", "\xE0", 'TIS-620') # เ check_both_ways("\u0E4F", "\xEF", 'TIS-620') # ๏ check_both_ways("\u0E50", "\xF0", 'TIS-620') # ๐ check_both_ways("\u0E5B", "\xFB", 'TIS-620') # ๛ - assert_undefined_in("\xFC", 'TIS-620') - assert_undefined_in("\xFF", 'TIS-620') + assert_raise(Encoding::UndefinedConversionError) { "\xFC".encode("utf-8", 'TIS-620') } + assert_raise(Encoding::UndefinedConversionError) { "\xFF".encode("utf-8", 'TIS-620') } end def test_CP850 @@ -1172,15 +1182,15 @@ class TestTranscode < Test::Unit::TestCase expected = "\u{3042}\u{3044}\u{20bb7}" assert_equal(expected, %w/fffe4230443042d8b7df/.pack("H*").encode("UTF-8","UTF-16")) check_both_ways(expected, %w/feff30423044d842dfb7/.pack("H*"), "UTF-16") - assert_invalid_in(%w/feffdfb7/.pack("H*"), "UTF-16") - assert_invalid_in(%w/fffeb7df/.pack("H*"), "UTF-16") + assert_raise(Encoding::InvalidByteSequenceError){%w/feffdfb7/.pack("H*").encode("UTF-8","UTF-16")} + assert_raise(Encoding::InvalidByteSequenceError){%w/fffeb7df/.pack("H*").encode("UTF-8","UTF-16")} end def test_utf_32_bom expected = "\u{3042}\u{3044}\u{20bb7}" assert_equal(expected, %w/fffe00004230000044300000b70b0200/.pack("H*").encode("UTF-8","UTF-32")) check_both_ways(expected, %w/0000feff000030420000304400020bb7/.pack("H*"), "UTF-32") - assert_invalid_in(%w/0000feff00110000/.pack("H*"), "UTF-32") + assert_raise(Encoding::InvalidByteSequenceError){%w/0000feff00110000/.pack("H*").encode("UTF-8","UTF-32")} end def check_utf_32_both_ways(utf8, raw) @@ -1362,24 +1372,24 @@ class TestTranscode < Test::Unit::TestCase check_both_ways("\u71FC", "\xE0\x9E", 'shift_jis') # 燼 check_both_ways("\u71F9", "\xE0\x9F", 'shift_jis') # 燹 check_both_ways("\u73F1", "\xE0\xFC", 'shift_jis') # 珱 - assert_undefined_in("\xEF\x40", 'shift_jis') - assert_undefined_in("\xEF\x7E", 'shift_jis') - assert_undefined_in("\xEF\x80", 'shift_jis') - assert_undefined_in("\xEF\x9E", 'shift_jis') - assert_undefined_in("\xEF\x9F", 'shift_jis') - assert_undefined_in("\xEF\xFC", 'shift_jis') - assert_undefined_in("\xF0\x40", 'shift_jis') - assert_undefined_in("\xF0\x7E", 'shift_jis') - assert_undefined_in("\xF0\x80", 'shift_jis') - assert_undefined_in("\xF0\x9E", 'shift_jis') - assert_undefined_in("\xF0\x9F", 'shift_jis') - assert_undefined_in("\xF0\xFC", 'shift_jis') + assert_raise(Encoding::UndefinedConversionError) { "\xEF\x40".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::UndefinedConversionError) { "\xEF\x7E".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::UndefinedConversionError) { "\xEF\x80".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::UndefinedConversionError) { "\xEF\x9E".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::UndefinedConversionError) { "\xEF\x9F".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::UndefinedConversionError) { "\xEF\xFC".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::UndefinedConversionError) { "\xF0\x40".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::UndefinedConversionError) { "\xF0\x7E".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::UndefinedConversionError) { "\xF0\x80".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::UndefinedConversionError) { "\xF0\x9E".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::UndefinedConversionError) { "\xF0\x9F".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::UndefinedConversionError) { "\xF0\xFC".encode("utf-8", 'shift_jis') } #check_both_ways("\u9ADC", "\xFC\x40", 'shift_jis') # 髜 (IBM extended) - assert_undefined_in("\xFC\x7E", 'shift_jis') - assert_undefined_in("\xFC\x80", 'shift_jis') - assert_undefined_in("\xFC\x9E", 'shift_jis') - assert_undefined_in("\xFC\x9F", 'shift_jis') - assert_undefined_in("\xFC\xFC", 'shift_jis') + assert_raise(Encoding::UndefinedConversionError) { "\xFC\x7E".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::UndefinedConversionError) { "\xFC\x80".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::UndefinedConversionError) { "\xFC\x9E".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::UndefinedConversionError) { "\xFC\x9F".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::UndefinedConversionError) { "\xFC\xFC".encode("utf-8", 'shift_jis') } check_both_ways("\u677E\u672C\u884C\u5F18", "\x8f\xbc\x96\x7b\x8d\x73\x8d\x4f", 'shift_jis') # 松本行弘 check_both_ways("\u9752\u5C71\u5B66\u9662\u5927\u5B66", "\x90\xC2\x8E\x52\x8A\x77\x89\x40\x91\xE5\x8A\x77", 'shift_jis') # 青山学院大学 check_both_ways("\u795E\u6797\u7FA9\u535A", "\x90\x5F\x97\xD1\x8B\x60\x94\x8E", 'shift_jis') # 神林義博 @@ -1399,34 +1409,34 @@ class TestTranscode < Test::Unit::TestCase check_both_ways("\u00F7", "\xA1\xE0", 'euc-jp') # ÷ check_both_ways("\u25C7", "\xA1\xFE", 'euc-jp') # ◇ check_both_ways("\u25C6", "\xA2\xA1", 'euc-jp') # ◆ - assert_undefined_in("\xA2\xAF", 'euc-jp') - assert_undefined_in("\xA2\xB9", 'euc-jp') - assert_undefined_in("\xA2\xC2", 'euc-jp') - assert_undefined_in("\xA2\xC9", 'euc-jp') - assert_undefined_in("\xA2\xD1", 'euc-jp') - assert_undefined_in("\xA2\xDB", 'euc-jp') - assert_undefined_in("\xA2\xEB", 'euc-jp') - assert_undefined_in("\xA2\xF1", 'euc-jp') - assert_undefined_in("\xA2\xFA", 'euc-jp') - assert_undefined_in("\xA2\xFD", 'euc-jp') + assert_raise(Encoding::UndefinedConversionError) { "\xA2\xAF".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xA2\xB9".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xA2\xC2".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xA2\xC9".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xA2\xD1".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xA2\xDB".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xA2\xEB".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xA2\xF1".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xA2\xFA".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xA2\xFD".encode("utf-8", 'euc-jp') } check_both_ways("\u25EF", "\xA2\xFE", 'euc-jp') # ◯ - assert_undefined_in("\xA3\xAF", 'euc-jp') - assert_undefined_in("\xA3\xBA", 'euc-jp') - assert_undefined_in("\xA3\xC0", 'euc-jp') - assert_undefined_in("\xA3\xDB", 'euc-jp') - assert_undefined_in("\xA3\xE0", 'euc-jp') - assert_undefined_in("\xA3\xFB", 'euc-jp') - assert_undefined_in("\xA4\xF4", 'euc-jp') - assert_undefined_in("\xA5\xF7", 'euc-jp') - assert_undefined_in("\xA6\xB9", 'euc-jp') - assert_undefined_in("\xA6\xC0", 'euc-jp') - assert_undefined_in("\xA6\xD9", 'euc-jp') - assert_undefined_in("\xA7\xC2", 'euc-jp') - assert_undefined_in("\xA7\xD0", 'euc-jp') - assert_undefined_in("\xA7\xF2", 'euc-jp') - assert_undefined_in("\xA8\xC1", 'euc-jp') - assert_undefined_in("\xCF\xD4", 'euc-jp') - assert_undefined_in("\xCF\xFE", 'euc-jp') + assert_raise(Encoding::UndefinedConversionError) { "\xA3\xAF".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xA3\xBA".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xA3\xC0".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xA3\xDB".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xA3\xE0".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xA3\xFB".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xA4\xF4".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xA5\xF7".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xA6\xB9".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xA6\xC0".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xA6\xD9".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xA7\xC2".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xA7\xD0".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xA7\xF2".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xA8\xC1".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xCF\xD4".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::UndefinedConversionError) { "\xCF\xFE".encode("utf-8", 'euc-jp') } check_both_ways("\u6A97", "\xDD\xA1", 'euc-jp') # 檗 check_both_ways("\u6BEF", "\xDD\xDF", 'euc-jp') # 毯 check_both_ways("\u9EBE", "\xDD\xE0", 'euc-jp') # 麾 @@ -1439,7 +1449,7 @@ class TestTranscode < Test::Unit::TestCase check_both_ways("\u71FC", "\xDF\xFE", 'euc-jp') # 燼 check_both_ways("\u71F9", "\xE0\xA1", 'euc-jp') # 燹 check_both_ways("\u73F1", "\xE0\xFE", 'euc-jp') # 珱 - assert_undefined_in("\xF4\xA7", 'euc-jp') + assert_raise(Encoding::UndefinedConversionError) { "\xF4\xA7".encode("utf-8", 'euc-jp') } #check_both_ways("\u9ADC", "\xFC\xE3", 'euc-jp') # 髜 (IBM extended) check_both_ways("\u677E\u672C\u884C\u5F18", "\xBE\xBE\xCB\xDC\xB9\xD4\xB9\xB0", 'euc-jp') # 松本行弘 @@ -1471,7 +1481,7 @@ class TestTranscode < Test::Unit::TestCase check_both_ways("\u2127", "\xA3\xE0", 'euc-jis-2004') # ℧ check_both_ways("\u30A0", "\xA3\xFB", 'euc-jis-2004') # ゠ check_both_ways("\uFF54", "\xA3\xF4", 'euc-jis-2004') # t - assert_undefined_in("\xA5\xF7", 'euc-jis-2004') + assert_raise(Encoding::UndefinedConversionError) { "\xA5\xF7".encode("utf-8", 'euc-jis-2004') } check_both_ways("\u2664", "\xA6\xB9", 'euc-jis-2004') # ♤ check_both_ways("\u2663", "\xA6\xC0", 'euc-jis-2004') # ♣ check_both_ways("\u03C2", "\xA6\xD9", 'euc-jis-2004') # ς @@ -1556,33 +1566,33 @@ class TestTranscode < Test::Unit::TestCase end def test_eucjp_sjis_undef - assert_undefined_conversion("\x8e\xe0", "Shift_JIS", "EUC-JP") - assert_undefined_conversion("\x8e\xfe", "Shift_JIS", "EUC-JP") - assert_undefined_conversion("\x8f\xa1\xa1", "Shift_JIS", "EUC-JP") - assert_undefined_conversion("\x8f\xa1\xfe", "Shift_JIS", "EUC-JP") - assert_undefined_conversion("\x8f\xfe\xa1", "Shift_JIS", "EUC-JP") - assert_undefined_conversion("\x8f\xfe\xfe", "Shift_JIS", "EUC-JP") - - assert_undefined_conversion("\xf0\x40", "EUC-JP", "Shift_JIS") - assert_undefined_conversion("\xf0\x7e", "EUC-JP", "Shift_JIS") - assert_undefined_conversion("\xf0\x80", "EUC-JP", "Shift_JIS") - assert_undefined_conversion("\xf0\xfc", "EUC-JP", "Shift_JIS") - assert_undefined_conversion("\xfc\x40", "EUC-JP", "Shift_JIS") - assert_undefined_conversion("\xfc\x7e", "EUC-JP", "Shift_JIS") - assert_undefined_conversion("\xfc\x80", "EUC-JP", "Shift_JIS") - assert_undefined_conversion("\xfc\xfc", "EUC-JP", "Shift_JIS") + assert_raise(Encoding::UndefinedConversionError) { "\x8e\xe0".encode("Shift_JIS", "EUC-JP") } + assert_raise(Encoding::UndefinedConversionError) { "\x8e\xfe".encode("Shift_JIS", "EUC-JP") } + assert_raise(Encoding::UndefinedConversionError) { "\x8f\xa1\xa1".encode("Shift_JIS", "EUC-JP") } + assert_raise(Encoding::UndefinedConversionError) { "\x8f\xa1\xfe".encode("Shift_JIS", "EUC-JP") } + assert_raise(Encoding::UndefinedConversionError) { "\x8f\xfe\xa1".encode("Shift_JIS", "EUC-JP") } + assert_raise(Encoding::UndefinedConversionError) { "\x8f\xfe\xfe".encode("Shift_JIS", "EUC-JP") } + + assert_raise(Encoding::UndefinedConversionError) { "\xf0\x40".encode("EUC-JP", "Shift_JIS") } + assert_raise(Encoding::UndefinedConversionError) { "\xf0\x7e".encode("EUC-JP", "Shift_JIS") } + assert_raise(Encoding::UndefinedConversionError) { "\xf0\x80".encode("EUC-JP", "Shift_JIS") } + assert_raise(Encoding::UndefinedConversionError) { "\xf0\xfc".encode("EUC-JP", "Shift_JIS") } + assert_raise(Encoding::UndefinedConversionError) { "\xfc\x40".encode("EUC-JP", "Shift_JIS") } + assert_raise(Encoding::UndefinedConversionError) { "\xfc\x7e".encode("EUC-JP", "Shift_JIS") } + assert_raise(Encoding::UndefinedConversionError) { "\xfc\x80".encode("EUC-JP", "Shift_JIS") } + assert_raise(Encoding::UndefinedConversionError) { "\xfc\xfc".encode("EUC-JP", "Shift_JIS") } end def test_iso_2022_jp - assert_invalid_in("\x1b(A", "iso-2022-jp") - assert_invalid_in("\x1b$(A", "iso-2022-jp") - assert_invalid_in("\x1b$C", "iso-2022-jp") - assert_invalid_in("\x0e", "iso-2022-jp") - assert_invalid_in("\x80", "iso-2022-jp") - assert_invalid_in("\x1b$(Dd!\x1b(B", "iso-2022-jp") - assert_undefined_conversion("\u9299", "iso-2022-jp") - assert_undefined_conversion("\uff71\uff72\uff73\uff74\uff75", "iso-2022-jp") - assert_invalid_in("\x1b(I12345\x1b(B", "iso-2022-jp") + assert_raise(Encoding::InvalidByteSequenceError) { "\x1b(A".encode("utf-8", "iso-2022-jp") } + assert_raise(Encoding::InvalidByteSequenceError) { "\x1b$(A".encode("utf-8", "iso-2022-jp") } + assert_raise(Encoding::InvalidByteSequenceError) { "\x1b$C".encode("utf-8", "iso-2022-jp") } + assert_raise(Encoding::InvalidByteSequenceError) { "\x0e".encode("utf-8", "iso-2022-jp") } + assert_raise(Encoding::InvalidByteSequenceError) { "\x80".encode("utf-8", "iso-2022-jp") } + assert_raise(Encoding::InvalidByteSequenceError) { "\x1b$(Dd!\x1b(B".encode("utf-8", "iso-2022-jp") } + assert_raise(Encoding::UndefinedConversionError) { "\u9299".encode("iso-2022-jp") } + assert_raise(Encoding::UndefinedConversionError) { "\uff71\uff72\uff73\uff74\uff75".encode("iso-2022-jp") } + assert_raise(Encoding::InvalidByteSequenceError) { "\x1b(I12345\x1b(B".encode("utf-8", "iso-2022-jp") } assert_equal("\xA1\xA1".force_encoding("euc-jp"), "\e$B!!\e(B".encode("EUC-JP", "ISO-2022-JP")) assert_equal("\e$B!!\e(B".force_encoding("ISO-2022-JP"), @@ -1645,11 +1655,11 @@ class TestTranscode < Test::Unit::TestCase assert_equal("\u005C", "\e(J\x5C\e(B".encode("UTF-8", "ISO-2022-JP")) assert_equal("\u005C", "\x5C".encode("stateless-ISO-2022-JP", "ISO-2022-JP")) assert_equal("\u005C", "\e(J\x5C\e(B".encode("stateless-ISO-2022-JP", "ISO-2022-JP")) - assert_undefined_conversion("\u00A5", "Shift_JIS") - assert_undefined_conversion("\u00A5", "Windows-31J") - assert_undefined_conversion("\u00A5", "EUC-JP") - assert_undefined_conversion("\u00A5", "eucJP-ms") - assert_undefined_conversion("\u00A5", "CP51932") + assert_raise(Encoding::UndefinedConversionError) { "\u00A5".encode("Shift_JIS") } + assert_raise(Encoding::UndefinedConversionError) { "\u00A5".encode("Windows-31J") } + assert_raise(Encoding::UndefinedConversionError) { "\u00A5".encode("EUC-JP") } + assert_raise(Encoding::UndefinedConversionError) { "\u00A5".encode("eucJP-ms") } + assert_raise(Encoding::UndefinedConversionError) { "\u00A5".encode("CP51932") } # FULLWIDTH REVERSE SOLIDUS check_both_ways("\uFF3C", "\x81\x5F", "Shift_JIS") @@ -1670,21 +1680,21 @@ class TestTranscode < Test::Unit::TestCase assert_equal("\u007E", "\e(J\x7E\e(B".encode("UTF-8", "ISO-2022-JP")) assert_equal("\u007E", "\x7E".encode("stateless-ISO-2022-JP", "ISO-2022-JP")) assert_equal("\u007E", "\e(J\x7E\e(B".encode("stateless-ISO-2022-JP", "ISO-2022-JP")) - assert_undefined_conversion("\u203E", "Shift_JIS") - assert_undefined_conversion("\u203E", "Windows-31J") - assert_undefined_conversion("\u203E", "EUC-JP") - assert_undefined_conversion("\u203E", "eucJP-ms") - assert_undefined_conversion("\u203E", "CP51932") + assert_raise(Encoding::UndefinedConversionError) { "\u203E".encode("Shift_JIS") } + assert_raise(Encoding::UndefinedConversionError) { "\u203E".encode("Windows-31J") } + assert_raise(Encoding::UndefinedConversionError) { "\u203E".encode("EUC-JP") } + assert_raise(Encoding::UndefinedConversionError) { "\u203E".encode("eucJP-ms") } + assert_raise(Encoding::UndefinedConversionError) { "\u203E".encode("CP51932") } end def test_gb2312 check_both_ways("\u3000", "\xA1\xA1", 'GB2312') # full-width space check_both_ways("\u3013", "\xA1\xFE", 'GB2312') # 〓 - assert_undefined_in("\xA2\xB0", 'GB2312') + assert_raise(Encoding::UndefinedConversionError) { "\xA2\xB0".encode("utf-8", 'GB2312') } check_both_ways("\u2488", "\xA2\xB1", 'GB2312') # ⒈ - assert_undefined_in("\xA2\xE4", 'GB2312') + assert_raise(Encoding::UndefinedConversionError) { "\xA2\xE4".encode("utf-8", 'GB2312') } check_both_ways("\u3220", "\xA2\xE5", 'GB2312') # ㈠ - assert_undefined_in("\xA2\xF0", 'GB2312') + assert_raise(Encoding::UndefinedConversionError) { "\xA2\xF0".encode("utf-8", 'GB2312') } check_both_ways("\u2160", "\xA2\xF1", 'GB2312') # Ⅰ check_both_ways("\uFF01", "\xA3\xA1", 'GB2312') # ! check_both_ways("\uFFE3", "\xA3\xFE", 'GB2312') #  ̄ @@ -1695,9 +1705,9 @@ class TestTranscode < Test::Unit::TestCase check_both_ways("\u0410", "\xA7\xA1", 'GB2312') # А check_both_ways("\u0430", "\xA7\xD1", 'GB2312') # а check_both_ways("\u0101", "\xA8\xA1", 'GB2312') # ā - assert_undefined_in("\xA8\xC4", 'GB2312') + assert_raise(Encoding::UndefinedConversionError) { "\xA8\xC4".encode("utf-8", 'GB2312') } check_both_ways("\u3105", "\xA8\xC5", 'GB2312') # ㄅ - assert_undefined_in("\xA9\xA3", 'GB2312') + assert_raise(Encoding::UndefinedConversionError) { "\xA9\xA3".encode("utf-8", 'GB2312') } check_both_ways("\u2500", "\xA9\xA4", 'GB2312') # ─ check_both_ways("\u554A", "\xB0\xA1", 'GB2312') # 啊 check_both_ways("\u5265", "\xB0\xFE", 'GB2312') # 剥 @@ -1711,7 +1721,7 @@ class TestTranscode < Test::Unit::TestCase check_both_ways("\u7384", "\xD0\xFE", 'GB2312') # 玄 check_both_ways("\u4F4F", "\xD7\xA1", 'GB2312') # 住 check_both_ways("\u5EA7", "\xD7\xF9", 'GB2312') # 座 - assert_undefined_in("\xD7\xFA", 'GB2312') + assert_raise(Encoding::UndefinedConversionError) { "\xD7\xFA".encode("utf-8", 'GB2312') } check_both_ways("\u647A", "\xDF\xA1", 'GB2312') # 摺 check_both_ways("\u553C", "\xDF\xFE", 'GB2312') # 唼 check_both_ways("\u5537", "\xE0\xA1", 'GB2312') # 唷 @@ -1749,48 +1759,48 @@ class TestTranscode < Test::Unit::TestCase check_both_ways("\u3000", "\xA1\xA1", 'GBK') # full-width space check_both_ways("\u3001", "\xA1\xA2", 'GBK') # 、 check_both_ways("\u3013", "\xA1\xFE", 'GBK') # 〓 - assert_undefined_in("\xA2\xA0", 'GBK') + assert_raise(Encoding::UndefinedConversionError) { "\xA2\xA0".encode("utf-8", 'GBK') } check_both_ways("\u2170", "\xA2\xA1", 'GBK') # ⅰ - assert_undefined_in("\xA2\xB0", 'GBK') + assert_raise(Encoding::UndefinedConversionError) { "\xA2\xB0".encode("utf-8", 'GBK') } check_both_ways("\u2488", "\xA2\xB1", 'GBK') # ⒈ - assert_undefined_in("\xA2\xE4", 'GBK') + assert_raise(Encoding::UndefinedConversionError) { "\xA2\xE4".encode("utf-8", 'GBK') } check_both_ways("\u3220", "\xA2\xE5", 'GBK') # ㈠ - assert_undefined_in("\xA2\xF0", 'GBK') + assert_raise(Encoding::UndefinedConversionError) { "\xA2\xF0".encode("utf-8", 'GBK') } check_both_ways("\u2160", "\xA2\xF1", 'GBK') # Ⅰ - assert_undefined_in("\xA3\xA0", 'GBK') + assert_raise(Encoding::UndefinedConversionError) { "\xA3\xA0".encode("utf-8", 'GBK') } check_both_ways("\uFF01", "\xA3\xA1", 'GBK') # ! check_both_ways("\uFFE3", "\xA3\xFE", 'GBK') #  ̄ - assert_undefined_in("\xA4\xA0", 'GBK') + assert_raise(Encoding::UndefinedConversionError) { "\xA4\xA0".encode("utf-8", 'GBK') } check_both_ways("\u3041", "\xA4\xA1", 'GBK') # ぁ - assert_undefined_in("\xA5\xA0", 'GBK') + assert_raise(Encoding::UndefinedConversionError) { "\xA5\xA0".encode("utf-8", 'GBK') } check_both_ways("\u30A1", "\xA5\xA1", 'GBK') # ァ check_both_ways("\u0391", "\xA6\xA1", 'GBK') # Α check_both_ways("\u03B1", "\xA6\xC1", 'GBK') # α - assert_undefined_in("\xA6\xED", 'GBK') + assert_raise(Encoding::UndefinedConversionError) { "\xA6\xED".encode("utf-8", 'GBK') } check_both_ways("\uFE3B", "\xA6\xEE", 'GBK') # ︻ check_both_ways("\u0410", "\xA7\xA1", 'GBK') # А check_both_ways("\u0430", "\xA7\xD1", 'GBK') # а check_both_ways("\u02CA", "\xA8\x40", 'GBK') # ˊ check_both_ways("\u2587", "\xA8\x7E", 'GBK') # ▇ - assert_undefined_in("\xA8\x96", 'GBK') + assert_raise(Encoding::UndefinedConversionError) { "\xA8\x96".encode("utf-8", 'GBK') } check_both_ways("\u0101", "\xA8\xA1", 'GBK') # ā - assert_undefined_in("\xA8\xBC", 'GBK') - assert_undefined_in("\xA8\xBF", 'GBK') - assert_undefined_in("\xA8\xC4", 'GBK') + assert_raise(Encoding::UndefinedConversionError) { "\xA8\xBC".encode("utf-8", 'GBK') } + assert_raise(Encoding::UndefinedConversionError) { "\xA8\xBF".encode("utf-8", 'GBK') } + assert_raise(Encoding::UndefinedConversionError) { "\xA8\xC4".encode("utf-8", 'GBK') } check_both_ways("\u3105", "\xA8\xC5", 'GBK') # ㄅ check_both_ways("\u3021", "\xA9\x40", 'GBK') # 〡 - assert_undefined_in("\xA9\x58", 'GBK') - assert_undefined_in("\xA9\x5B", 'GBK') - assert_undefined_in("\xA9\x5D", 'GBK') + assert_raise(Encoding::UndefinedConversionError) { "\xA9\x58".encode("utf-8", 'GBK') } + assert_raise(Encoding::UndefinedConversionError) { "\xA9\x5B".encode("utf-8", 'GBK') } + assert_raise(Encoding::UndefinedConversionError) { "\xA9\x5D".encode("utf-8", 'GBK') } check_both_ways("\u3007", "\xA9\x96", 'GBK') # 〇 - assert_undefined_in("\xA9\xA3", 'GBK') + assert_raise(Encoding::UndefinedConversionError) { "\xA9\xA3".encode("utf-8", 'GBK') } check_both_ways("\u2500", "\xA9\xA4", 'GBK') # ─ - assert_undefined_in("\xA9\xF0", 'GBK') + assert_raise(Encoding::UndefinedConversionError) { "\xA9\xF0".encode("utf-8", 'GBK') } check_both_ways("\u7588", "\xAF\x40", 'GBK') # 疈 check_both_ways("\u7607", "\xAF\x7E", 'GBK') # 瘇 check_both_ways("\u7608", "\xAF\x80", 'GBK') # 瘈 check_both_ways("\u7644", "\xAF\xA0", 'GBK') # 癄 - assert_undefined_in("\xAF\xA1", 'GBK') + assert_raise(Encoding::UndefinedConversionError) { "\xAF\xA1".encode("utf-8", 'GBK') } check_both_ways("\u7645", "\xB0\x40", 'GBK') # 癅 check_both_ways("\u769B", "\xB0\x7E", 'GBK') # 皛 check_both_ways("\u769C", "\xB0\x80", 'GBK') # 皜 @@ -1831,10 +1841,10 @@ class TestTranscode < Test::Unit::TestCase check_both_ways("\u9F78", "\xFD\x7E", 'GBK') # 齸 check_both_ways("\u9F79", "\xFD\x80", 'GBK') # 齹 check_both_ways("\uF9F1", "\xFD\xA0", 'GBK') # 隣 - assert_undefined_in("\xFD\xA1", 'GBK') + assert_raise(Encoding::UndefinedConversionError) { "\xFD\xA1".encode("utf-8", 'GBK') } check_both_ways("\uFA0C", "\xFE\x40", 'GBK') # 兀 check_both_ways("\uFA29", "\xFE\x4F", 'GBK') # 﨩 - assert_undefined_in("\xFE\x50", 'GBK') + assert_raise(Encoding::UndefinedConversionError) { "\xFE\x50".encode("utf-8", 'GBK') } check_both_ways("\u9752\u5C71\u5B66\u9662\u5927\u5B66", "\xC7\xE0\xC9\xBD\xD1\xA7\xD4\xBA\xB4\xF3\xD1\xA7", 'GBK') # 青山学院大学 check_both_ways("\u795E\u6797\u7FA9\u535A", "\xC9\xF1\xC1\xD6\xC1\x78\xB2\xA9", 'GBK') # 神林義博 end @@ -1870,48 +1880,48 @@ class TestTranscode < Test::Unit::TestCase check_both_ways("\u3000", "\xA1\xA1", 'GB18030') # full-width space check_both_ways("\u3001", "\xA1\xA2", 'GB18030') # check_both_ways("\u3013", "\xA1\xFE", 'GB18030') # - #assert_undefined_in("\xA2\xA0", 'GB18030') + #assert_raise(Encoding::UndefinedConversionError) { "\xA2\xA0".encode("utf-8", 'GB18030') } check_both_ways("\u2170", "\xA2\xA1", 'GB18030') # ⅰ - #assert_undefined_in("\xA2\xB0", 'GB18030') + #assert_raise(Encoding::UndefinedConversionError) { "\xA2\xB0".encode("utf-8", 'GB18030') } check_both_ways("\u2488", "\xA2\xB1", 'GB18030') # - #assert_undefined_in("\xA2\xE4", 'GB18030') + #assert_raise(Encoding::UndefinedConversionError) { "\xA2\xE4".encode("utf-8", 'GB18030') } check_both_ways("\u3220", "\xA2\xE5", 'GB18030') # ㈠ - #assert_undefined_in("\xA2\xF0", 'GB18030') + #assert_raise(Encoding::UndefinedConversionError) { "\xA2\xF0".encode("utf-8", 'GB18030') } check_both_ways("\u2160", "\xA2\xF1", 'GB18030') # Ⅰ - #assert_undefined_in("\xA3\xA0", 'GB18030') + #assert_raise(Encoding::UndefinedConversionError) { "\xA3\xA0".encode("utf-8", 'GB18030') } check_both_ways("\uFF01", "\xA3\xA1", 'GB18030') # E check_both_ways("\uFFE3", "\xA3\xFE", 'GB18030') # E - #assert_undefined_in("\xA4\xA0", 'GB18030') + #assert_raise(Encoding::UndefinedConversionError) { "\xA4\xA0".encode("utf-8", 'GB18030') } check_both_ways("\u3041", "\xA4\xA1", 'GB18030') # - #assert_undefined_in("\xA5\xA0", 'GB18030') + #assert_raise(Encoding::UndefinedConversionError) { "\xA5\xA0".encode("utf-8", 'GB18030') } check_both_ways("\u30A1", "\xA5\xA1", 'GB18030') # ァ check_both_ways("\u0391", "\xA6\xA1", 'GB18030') # check_both_ways("\u03B1", "\xA6\xC1", 'GB18030') # α - #assert_undefined_in("\xA6\xED", 'GB18030') + #assert_raise(Encoding::UndefinedConversionError) { "\xA6\xED".encode("utf-8", 'GB18030') } check_both_ways("\uFE3B", "\xA6\xEE", 'GB18030') # E check_both_ways("\u0410", "\xA7\xA1", 'GB18030') # check_both_ways("\u0430", "\xA7\xD1", 'GB18030') # а check_both_ways("\u02CA", "\xA8\x40", 'GB18030') # check_both_ways("\u2587", "\xA8\x7E", 'GB18030') # - #assert_undefined_in("\xA8\x96", 'GB18030') + #assert_raise(Encoding::UndefinedConversionError) { "\xA8\x96".encode("utf-8", 'GB18030') } check_both_ways("\u0101", "\xA8\xA1", 'GB18030') # - #assert_undefined_in("\xA8\xBC", 'GB18030') - #assert_undefined_in("\xA8\xBF", 'GB18030') - #assert_undefined_in("\xA8\xC4", 'GB18030') + #assert_raise(Encoding::UndefinedConversionError) { "\xA8\xBC".encode("utf-8", 'GB18030') } + #assert_raise(Encoding::UndefinedConversionError) { "\xA8\xBF".encode("utf-8", 'GB18030') } + #assert_raise(Encoding::UndefinedConversionError) { "\xA8\xC4".encode("utf-8", 'GB18030') } check_both_ways("\u3105", "\xA8\xC5", 'GB18030') # check_both_ways("\u3021", "\xA9\x40", 'GB18030') # 〡 - #assert_undefined_in("\xA9\x58", 'GB18030') - #assert_undefined_in("\xA9\x5B", 'GB18030') - #assert_undefined_in("\xA9\x5D", 'GB18030') + #assert_raise(Encoding::UndefinedConversionError) { "\xA9\x58".encode("utf-8", 'GB18030') } + #assert_raise(Encoding::UndefinedConversionError) { "\xA9\x5B".encode("utf-8", 'GB18030') } + #assert_raise(Encoding::UndefinedConversionError) { "\xA9\x5D".encode("utf-8", 'GB18030') } check_both_ways("\u3007", "\xA9\x96", 'GB18030') # - #assert_undefined_in("\xA9\xA3", 'GB18030') + #assert_raise(Encoding::UndefinedConversionError) { "\xA9\xA3".encode("utf-8", 'GB18030') } check_both_ways("\u2500", "\xA9\xA4", 'GB18030') # ─ - #assert_undefined_in("\xA9\xF0", 'GB18030') + #assert_raise(Encoding::UndefinedConversionError) { "\xA9\xF0".encode("utf-8", 'GB18030') } check_both_ways("\u7588", "\xAF\x40", 'GB18030') # check_both_ways("\u7607", "\xAF\x7E", 'GB18030') # check_both_ways("\u7608", "\xAF\x80", 'GB18030') # check_both_ways("\u7644", "\xAF\xA0", 'GB18030') # - #assert_undefined_in("\xAF\xA1", 'GB18030') + #assert_raise(Encoding::UndefinedConversionError) { "\xAF\xA1".encode("utf-8", 'GB18030') } check_both_ways("\u7645", "\xB0\x40", 'GB18030') # check_both_ways("\u769B", "\xB0\x7E", 'GB18030') # check_both_ways("\u769C", "\xB0\x80", 'GB18030') # @@ -1952,10 +1962,10 @@ class TestTranscode < Test::Unit::TestCase check_both_ways("\u9F78", "\xFD\x7E", 'GB18030') # 齸 check_both_ways("\u9F79", "\xFD\x80", 'GB18030') # 齹 check_both_ways("\uF9F1", "\xFD\xA0", 'GB18030') # E - #assert_undefined_in("\xFD\xA1", 'GB18030') + #assert_raise(Encoding::UndefinedConversionError) { "\xFD\xA1".encode("utf-8", 'GB18030') } check_both_ways("\uFA0C", "\xFE\x40", 'GB18030') # E check_both_ways("\uFA29", "\xFE\x4F", 'GB18030') # E - #assert_undefined_in("\xFE\x50", 'GB18030') + #assert_raise(Encoding::UndefinedConversionError) { "\xFE\x50".encode("utf-8", 'GB18030') } check_both_ways("\u9752\u5C71\u5B66\u9662\u5927\u5B66", "\xC7\xE0\xC9\xBD\xD1\xA7\xD4\xBA\xB4\xF3\xD1\xA7", 'GB18030') # 青山学院大学 check_both_ways("\u795E\u6797\u7FA9\u535A", "\xC9\xF1\xC1\xD6\xC1\x78\xB2\xA9", 'GB18030') # 神林義 @@ -2010,7 +2020,7 @@ class TestTranscode < Test::Unit::TestCase check_both_ways("\u310F", "\xA3\x7E", 'Big5') # ㄏ check_both_ways("\u3110", "\xA3\xA1", 'Big5') # ㄐ check_both_ways("\u02CB", "\xA3\xBF", 'Big5') # ˋ - assert_undefined_in("\xA3\xC0", 'Big5') + assert_raise(Encoding::UndefinedConversionError) { "\xA3\xC0".encode("utf-8", 'Big5') } check_both_ways("\u6D6C", "\xAF\x40", 'Big5') # 浬 check_both_ways("\u7837", "\xAF\x7E", 'Big5') # 砷 check_both_ways("\u7825", "\xAF\xA1", 'Big5') # 砥 @@ -2029,9 +2039,9 @@ class TestTranscode < Test::Unit::TestCase check_both_ways("\u77AC", "\xC0\xFE", 'Big5') # 瞬 check_both_ways("\u8B96", "\xC6\x40", 'Big5') # 讖 check_both_ways("\u7C72", "\xC6\x7E", 'Big5') # 籲 - #assert_undefined_in("\xC6\xA1", 'Big5') - #assert_undefined_in("\xC7\x40", 'Big5') - #assert_undefined_in("\xC8\x40", 'Big5') + #assert_raise(Encoding::UndefinedConversionError) { "\xC6\xA1".encode("utf-8", 'Big5') } + #assert_raise(Encoding::UndefinedConversionError) { "\xC7\x40".encode("utf-8", 'Big5') } + #assert_raise(Encoding::UndefinedConversionError) { "\xC8\x40".encode("utf-8", 'Big5') } check_both_ways("\u4E42", "\xC9\x40", 'Big5') # 乂 check_both_ways("\u6C15", "\xC9\x7E", 'Big5') # 氕 check_both_ways("\u6C36", "\xC9\xA1", 'Big5') # 氶 @@ -2064,7 +2074,7 @@ class TestTranscode < Test::Unit::TestCase check_both_ways("\u9F0A", "\xF9\x7E", 'Big5') # 鼊 check_both_ways("\u9FA4", "\xF9\xA1", 'Big5') # 龤 check_both_ways("\u9F98", "\xF9\xD5", 'Big5') # 龘 - #assert_undefined_in("\xF9\xD6", 'Big5') + #assert_raise(Encoding::UndefinedConversionError) { "\xF9\xD6".encode("utf-8", 'Big5') } check_both_ways("\u795E\u6797\u7FA9\u535A", "\xAF\xAB\xAA\x4C\xB8\x71\xB3\xD5", 'Big5') # 神林義博 end @@ -2077,7 +2087,7 @@ class TestTranscode < Test::Unit::TestCase check_both_ways("\u310F", "\xA3\x7E", 'Big5-HKSCS') # ㄏ check_both_ways("\u3110", "\xA3\xA1", 'Big5-HKSCS') # ㄐ check_both_ways("\u02CB", "\xA3\xBF", 'Big5-HKSCS') # ˋ - #assert_undefined_in("\xA3\xC0", 'Big5-HKSCS') + #assert_raise(Encoding::UndefinedConversionError) { "\xA3\xC0".encode("utf-8", 'Big5-HKSCS') } check_both_ways("\u6D6C", "\xAF\x40", 'Big5-HKSCS') # 浬 check_both_ways("\u7837", "\xAF\x7E", 'Big5-HKSCS') # 砷 check_both_ways("\u7825", "\xAF\xA1", 'Big5-HKSCS') # 砥 @@ -2096,9 +2106,9 @@ class TestTranscode < Test::Unit::TestCase check_both_ways("\u77AC", "\xC0\xFE", 'Big5-HKSCS') # 瞬 check_both_ways("\u8B96", "\xC6\x40", 'Big5-HKSCS') # 讖 check_both_ways("\u7C72", "\xC6\x7E", 'Big5-HKSCS') # 籲 - #assert_undefined_in("\xC6\xA1", 'Big5-HKSCS') - #assert_undefined_in("\xC7\x40", 'Big5-HKSCS') - #assert_undefined_in("\xC8\x40", 'Big5-HKSCS') + #assert_raise(Encoding::UndefinedConversionError) { "\xC6\xA1".encode("utf-8", 'Big5-HKSCS') } + #assert_raise(Encoding::UndefinedConversionError) { "\xC7\x40".encode("utf-8", 'Big5-HKSCS') } + #assert_raise(Encoding::UndefinedConversionError) { "\xC8\x40".encode("utf-8", 'Big5-HKSCS') } check_both_ways("\u4E42", "\xC9\x40", 'Big5-HKSCS') # 乂 check_both_ways("\u6C15", "\xC9\x7E", 'Big5-HKSCS') # 氕 check_both_ways("\u6C36", "\xC9\xA1", 'Big5-HKSCS') # 氶 @@ -2132,7 +2142,7 @@ class TestTranscode < Test::Unit::TestCase check_both_ways("\u9FA4", "\xF9\xA1", 'Big5-HKSCS') # 龤 check_both_ways("\u9F98", "\xF9\xD5", 'Big5-HKSCS') # 龘 #check_both_ways("\u{23ED7}", "\x8E\x40", 'Big5-HKSCS') # 𣻗 - #assert_undefined_in("\xF9\xD6", 'Big5-HKSCS') + #assert_raise(Encoding::UndefinedConversionError) { "\xF9\xD6".encode("utf-8", 'Big5-HKSCS') } check_both_ways("\u795E\u6797\u7FA9\u535A", "\xAF\xAB\xAA\x4C\xB8\x71\xB3\xD5", 'Big5-HKSCS') # 神林義博 end @@ -2222,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 @@ -2295,37 +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 - - private - - def assert_conversion_both_ways_utf8(utf8, raw, encoding) - assert_conversion_both_ways(utf8, 'utf-8', raw, encoding) - end - alias check_both_ways assert_conversion_both_ways_utf8 - - def assert_conversion_both_ways(str1, enc1, str2, enc2) - message = str1.dump+str2.dump - assert_equal(str1.force_encoding(enc1), str2.encode(enc1, enc2), message) - assert_equal(str2.force_encoding(enc2), str1.encode(enc2, enc1), message) - end - alias check_both_ways2 assert_conversion_both_ways - - def assert_undefined_conversion(str, to, from = nil) - assert_raise(Encoding::UndefinedConversionError) { str.encode(to, from) } - end - - def assert_undefined_in(str, encoding) - assert_undefined_conversion(str, 'utf-8', encoding) - end - - def assert_invalid_byte_sequence(str, to, from = nil) - assert_raise(Encoding::InvalidByteSequenceError) { str.encode(to, from) } - end - - def assert_invalid_in(str, encoding) - assert_invalid_byte_sequence(str, 'utf-8', encoding) end end diff --git a/test/ruby/test_variable.rb b/test/ruby/test_variable.rb index 86f2e4bb84..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]) @@ -413,18 +314,6 @@ class TestVariable < Test::Unit::TestCase assert_equal(%i(v1 v2 v3 v4 v5 v6 v7 v8 v9 v10 v11), v, bug11674) end - def test_many_instance_variables - objects = [Object.new, Hash.new, Module.new] - objects.each do |obj| - 1000.times do |i| - obj.instance_variable_set("@var#{i}", i) - end - 1000.times do |i| - assert_equal(i, obj.instance_variable_get("@var#{i}")) - end - end - end - private def with_kwargs_11(v1:, v2:, v3:, v4:, v5:, v6:, v7:, v8:, v9:, v10:, v11:) local_variables 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 799cee2d75..0000000000 --- a/test/ruby/test_weakkeymap.rb +++ /dev/null @@ -1,144 +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 - - def test_gc_compact_stress - EnvUtil.under_gc_compact_stress { ObjectSpace::WeakKeyMap.new } - 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 0371afa77a..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,49 +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_gc_compact_stress - EnvUtil.under_gc_compact_stress { ObjectSpace::WeakMap.new } - 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 55b86bea78..48b3e4acea 100644 --- a/test/ruby/test_yjit.rb +++ b/test/ruby/test_yjit.rb @@ -1,27 +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? -require 'stringio' +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), @@ -31,107 +21,33 @@ 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_yjit_enable - args = [] - args << "--disable=yjit" if RubyVM::YJIT.enabled? - assert_separately(args, <<~RUBY) - assert_false RubyVM::YJIT.enabled? - assert_false RUBY_DESCRIPTION.include?("+YJIT") - - RubyVM::YJIT.enable - - assert_true RubyVM::YJIT.enabled? - assert_true RUBY_DESCRIPTION.include?("+YJIT") - RUBY - end - - def test_yjit_enable_stats_false - assert_separately(["--yjit-disable", "--yjit-stats"], <<~RUBY, ignore_stderr: true) - assert_false RubyVM::YJIT.enabled? - assert_nil RubyVM::YJIT.runtime_stats - - RubyVM::YJIT.enable - - assert_true RubyVM::YJIT.enabled? - assert_true RubyVM::YJIT.runtime_stats[:all_stats] - RUBY - end - - def test_yjit_enable_stats_true - args = [] - args << "--disable=yjit" if RubyVM::YJIT.enabled? - assert_separately(args, <<~RUBY, ignore_stderr: true) - assert_false RubyVM::YJIT.enabled? - assert_nil RubyVM::YJIT.runtime_stats - - RubyVM::YJIT.enable(stats: true) - - assert_true RubyVM::YJIT.enabled? - assert_true RubyVM::YJIT.runtime_stats[:all_stats] - RUBY - end - - def test_yjit_enable_stats_quiet - assert_in_out_err(['--yjit-disable', '-e', 'RubyVM::YJIT.enable(stats: true)']) do |_stdout, stderr, _status| - assert_not_empty stderr - end - assert_in_out_err(['--yjit-disable', '-e', 'RubyVM::YJIT.enable(stats: :quiet)']) do |_stdout, stderr, _status| - assert_empty stderr - end - end - - def test_yjit_enable_with_call_threshold - assert_separately(%w[--yjit-disable --yjit-call-threshold=1], <<~RUBY) - def not_compiled = nil - def will_compile = nil - def compiled_counts = RubyVM::YJIT.runtime_stats&.dig(:compiled_iseq_count) - - not_compiled - assert_nil compiled_counts - assert_false RubyVM::YJIT.enabled? - - RubyVM::YJIT.enable - - will_compile - assert compiled_counts > 0 - assert_true RubyVM::YJIT.enabled? - RUBY - end - - def test_yjit_enable_with_monkey_patch - assert_separately(%w[--yjit-disable], <<~RUBY) - # This lets rb_method_entry_at(rb_mKernel, ...) return NULL - Kernel.prepend(Module.new) - - # This must not crash with "undefined optimized method!" - RubyVM::YJIT.enable - RUBY + 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 - _stdout, stderr, _status = invoke_ruby(%w(-v --yjit-stats), '', true, true) + _stdout, stderr, _status = EnvUtil.invoke_ruby(%w(-v --yjit-stats), '', true, true) refute_includes(stderr, "NoMethodError") end @@ -143,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' @@ -165,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) @@ -399,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) @@ -468,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 @@ -504,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 @@ -532,34 +395,8 @@ class TestYJIT < Test::Unit::TestCase RUBY end - def test_opt_getconstant_path_general - assert_compiles(<<~RUBY, result: [1, 1]) - module Base - Const = 1 - end - - class Sub - def const - _const = nil # make a non-entry block for opt_getconstant_path - Const - end - - def self.const_missing(n) - Base.const_get(n) - end - end - - - sub = Sub.new - result = [] - result << sub.const # generate the general case - result << sub.const # const_missing does not invalidate the block - result - RUBY - 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 @@ -615,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 @@ -876,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 @@ -913,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 @@ -947,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(':') @@ -991,553 +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_disable_code_gc_with_many_iseqs - assert_compiles(code_gc_helpers + <<~'RUBY', exits: :any, result: :ok, mem_size: 1, code_gc: false) - 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_with_many_iseqs - assert_compiles(code_gc_helpers + <<~'RUBY', exits: :any, result: :ok, mem_size: 1, code_gc: true) - 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_with_auto_compact - assert_compiles((code_gc_helpers + <<~'RUBY'), exits: :any, result: :ok, mem_size: 1, code_gc: true) - # Test ISEQ moves in the middle of code GC - GC.auto_compact = true - - 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]], 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 - - 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, exits: { opt_plus: 1 }) - 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, exits: { putspecialobject: 1, definemethod: 1 }) - 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], exits: { definesmethod: 1, getlocal_WC_0: 1 }) - 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_return_to_invalidated_frame - assert_compiles(code_gc_helpers + <<~RUBY, exits: :any, result: :ok) - def jump - [] # something not inlined - end - - def entry(code_gc) - jit_exception(code_gc) - jump # faulty jump after code GC. #jit_exception should not come back. - end - - def jit_exception(code_gc) - if code_gc - tap do - RubyVM::YJIT.code_gc - break # jit_exec_exception catches TAG_BREAK and re-enters JIT code - end - end - end - - add_pages(100) - jump # Compile #jump in a non-first page - add_pages(100) - entry(false) # Compile #entry and its call to #jump in another page - entry(true) # Free #jump but not #entry - - :ok - 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], exits: { defineclass: 1 }) - 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], exits: { definesmethod: 1, opt_eq: 2 }) - 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 - - def test_opt_mult_overflow - assert_no_exits('0xfff_ffff_ffff_ffff * 0x10') - end - - def test_disable_stats - assert_in_out_err(%w[--yjit-stats --yjit-disable]) - 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[:live_page_count] - num_jits.times { return false unless eval('compiles { nil.to_i }') } - pages.nil? || pages < RubyVM::YJIT.runtime_stats[:live_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, code_gc: false) + 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! @@ -1546,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 @@ -1571,7 +610,7 @@ class TestYJIT < Test::Unit::TestCase #{write_results} RUBY - status, out, err, stats = eval_with_jit(script, call_threshold:, mem_size:, code_gc:) + status, out, err, stats = eval_with_jit(script, min_calls: min_calls) assert status.success?, "exited with status #{status.to_i}, stderr:\n#{err}" @@ -1582,88 +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.keys != recorded_exits.keys || !exits.all? { |k, v| v === recorded_exits[k] }) # triple-equal checks range membership or integer equality - stats_reasons = StringIO.new - ::RubyVM::YJIT.send(:_print_stats_reasons, runtime_stats, stats_reasons) - stats_reasons = stats_reasons.string - flunk <<~EOM - Expected #{exits.empty? ? "no" : exits.inspect} exits, but got: - #{recorded_exits.inspect} - Reasons: - #{stats_reasons} - EOM + 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, code_gc: false) + def eval_with_jit(script, min_calls: 1, timeout: 1000) args = [ "--disable-gems", - "--yjit-call-threshold=#{call_threshold}", - "--yjit-stats=quiet" + "--yjit-call-threshold=#{min_calls}", + "--yjit-stats" ] - args << "--yjit-exec-mem-size=#{mem_size}" if mem_size - args << "--yjit-code-gc" if code_gc - 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 = invoke_ruby(args, '', true, true, timeout: timeout, ios: { 3 => stats_w }) + 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 - # A wrapper of EnvUtil.invoke_ruby that uses RbConfig.ruby instead of EnvUtil.ruby - # that might use a wrong Ruby depending on your environment. - def invoke_ruby(*args, **kwargs) - EnvUtil.invoke_ruby(*args, rubybin: RbConfig.ruby, **kwargs) + 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 816ab457ce..0000000000 --- a/test/ruby/test_yjit_exit_locations.rb +++ /dev/null @@ -1,96 +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_expandarray_splat - assert_exit_locations('*arr = []') - 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 |
