From 22e2a6a999b958efe5d84d9c7314e450fda82254 Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Wed, 2 Jun 2021 14:34:07 +0200 Subject: Update to ruby/spec@a0b7d0d --- spec/ruby/core/array/element_set_spec.rb | 8 + spec/ruby/core/encoding/replicate_spec.rb | 21 +++ spec/ruby/core/enumerator/lazy/filter_map_spec.rb | 16 ++ spec/ruby/core/exception/signal_exception_spec.rb | 6 +- spec/ruby/core/exception/system_exit_spec.rb | 4 +- spec/ruby/core/exception/top_level_spec.rb | 6 +- spec/ruby/core/fiber/raise_spec.rb | 20 +++ spec/ruby/core/file/atime_spec.rb | 23 ++- spec/ruby/core/file/basename_spec.rb | 15 ++ spec/ruby/core/hash/rehash_spec.rb | 18 ++ spec/ruby/core/io/binmode_spec.rb | 4 + spec/ruby/core/io/dup_spec.rb | 19 +++ spec/ruby/core/io/external_encoding_spec.rb | 5 + spec/ruby/core/io/internal_encoding_spec.rb | 5 + spec/ruby/core/io/lineno_spec.rb | 36 ++++ spec/ruby/core/io/set_encoding_by_bom_spec.rb | 14 ++ spec/ruby/core/io/sysread_spec.rb | 5 + spec/ruby/core/io/sysseek_spec.rb | 5 + spec/ruby/core/kernel/at_exit_spec.rb | 11 +- spec/ruby/core/kernel/eval_spec.rb | 65 ++++--- spec/ruby/core/kernel/format_spec.rb | 1 + spec/ruby/core/kernel/inspect_spec.rb | 8 + spec/ruby/core/kernel/shared/sprintf.rb | 17 ++ spec/ruby/core/module/define_method_spec.rb | 46 +++++ spec/ruby/core/module/include_spec.rb | 142 ++++++++++++++++ spec/ruby/core/module/prepend_spec.rb | 186 +++++++++++++++++++++ spec/ruby/core/module/remove_method_spec.rb | 22 +++ spec/ruby/core/objectspace/_id2ref_spec.rb | 41 ++++- .../ruby/core/objectspace/define_finalizer_spec.rb | 2 +- spec/ruby/core/process/status/equal_value_spec.rb | 4 +- spec/ruby/core/process/status/exited_spec.rb | 7 +- spec/ruby/core/process/status/exitstatus_spec.rb | 4 +- spec/ruby/core/process/status/signaled_spec.rb | 6 +- spec/ruby/core/process/status/success_spec.rb | 14 +- spec/ruby/core/process/status/termsig_spec.rb | 4 +- spec/ruby/core/process/status/to_i_spec.rb | 4 +- spec/ruby/core/range/step_spec.rb | 39 +++-- spec/ruby/core/signal/trap_spec.rb | 2 +- spec/ruby/core/string/inspect_spec.rb | 6 + spec/ruby/core/string/rpartition_spec.rb | 13 ++ spec/ruby/core/string/split_spec.rb | 10 ++ spec/ruby/core/struct/dig_spec.rb | 10 ++ 42 files changed, 784 insertions(+), 110 deletions(-) create mode 100644 spec/ruby/core/enumerator/lazy/filter_map_spec.rb (limited to 'spec/ruby/core') diff --git a/spec/ruby/core/array/element_set_spec.rb b/spec/ruby/core/array/element_set_spec.rb index 1c143f3e37..07c64b919e 100644 --- a/spec/ruby/core/array/element_set_spec.rb +++ b/spec/ruby/core/array/element_set_spec.rb @@ -36,6 +36,7 @@ describe "Array#[]=" do a[3, 2] = ['a', 'b', 'c', 'd'] a.should == [2, 2, 3, "a", "b", "c", "d", 6] end + it "replaces the section defined by [start,length] with the given values" do a = [1, 2, 3, 4, 5, 6] a[3, 2] = 'a', 'b', 'c', 'd' @@ -169,6 +170,7 @@ describe "Array#[]=" do ary[1...1] = [] ary.should == [1, 2, 3] end + it "does nothing if the section defined by range has negative width and the rhs is an empty array" do ary = [1, 2, 3, 4, 5] ary[1...0] = [] @@ -284,6 +286,12 @@ describe "Array#[]= with [index, count]" do (a[2, 3] = [4, 5]).should == [4, 5] end + it "accepts a frozen String literal as RHS" do + a = ['a', 'b', 'c'] + a[0, 2] = 'd'.freeze + a.should == ['d', 'c'] + end + it "just sets the section defined by [start,length] to nil even if the rhs is nil" do a = ['a', 'b', 'c', 'd', 'e'] a[1, 3] = nil diff --git a/spec/ruby/core/encoding/replicate_spec.rb b/spec/ruby/core/encoding/replicate_spec.rb index 717e9cea72..45727a5c0d 100644 --- a/spec/ruby/core/encoding/replicate_spec.rb +++ b/spec/ruby/core/encoding/replicate_spec.rb @@ -15,6 +15,8 @@ describe "Encoding#replicate" do name = @prefix + '-ASCII' e = Encoding::ASCII.replicate(name) e.name.should == name + Encoding.find(name).should == e + "a".force_encoding(e).valid_encoding?.should be_true "\x80".force_encoding(e).valid_encoding?.should be_false end @@ -23,6 +25,8 @@ describe "Encoding#replicate" do name = @prefix + 'UTF-8' e = Encoding::UTF_8.replicate(name) e.name.should == name + Encoding.find(name).should == e + "a".force_encoding(e).valid_encoding?.should be_true "\u3042".force_encoding(e).valid_encoding?.should be_true "\x80".force_encoding(e).valid_encoding?.should be_false @@ -32,6 +36,8 @@ describe "Encoding#replicate" do name = @prefix + 'UTF-16-BE' e = Encoding::UTF_16BE.replicate(name) e.name.should == name + Encoding.find(name).should == e + "a".force_encoding(e).valid_encoding?.should be_false "\x30\x42".force_encoding(e).valid_encoding?.should be_true "\x80".force_encoding(e).valid_encoding?.should be_false @@ -40,7 +46,22 @@ describe "Encoding#replicate" do it "returns a replica of ISO-2022-JP" do name = @prefix + 'ISO-2022-JP' e = Encoding::ISO_2022_JP.replicate(name) + Encoding.find(name).should == e + e.name.should == name e.dummy?.should be_true end + + # NOTE: it's unclear of the value of this (for the complexity cost of it), + # but it is the current CRuby behavior. + it "can be associated with a String" do + name = @prefix + '-US-ASCII' + e = Encoding::US_ASCII.replicate(name) + e.name.should == name + Encoding.find(name).should == e + + s = "abc".force_encoding(e) + s.encoding.should == e + s.encoding.name.should == name + end end diff --git a/spec/ruby/core/enumerator/lazy/filter_map_spec.rb b/spec/ruby/core/enumerator/lazy/filter_map_spec.rb new file mode 100644 index 0000000000..3480af0865 --- /dev/null +++ b/spec/ruby/core/enumerator/lazy/filter_map_spec.rb @@ -0,0 +1,16 @@ +# -*- encoding: us-ascii -*- + +require_relative '../../../spec_helper' +require_relative 'fixtures/classes' + +ruby_version_is "2.7" do + describe "Enumerator::Lazy#filter_map" do + it "maps only truthy results" do + (1..Float::INFINITY).lazy.filter_map { |i| i if i.odd? }.first(4).should == [1, 3, 5, 7] + end + + it "does not map false results" do + (1..Float::INFINITY).lazy.filter_map { |i| i.odd? ? i : false }.first(4).should == [1, 3, 5, 7] + end + end +end diff --git a/spec/ruby/core/exception/signal_exception_spec.rb b/spec/ruby/core/exception/signal_exception_spec.rb index e494e18cde..2d2179a628 100644 --- a/spec/ruby/core/exception/signal_exception_spec.rb +++ b/spec/ruby/core/exception/signal_exception_spec.rb @@ -95,7 +95,7 @@ describe "SignalException" do platform_is_not :windows do it "runs after at_exit" do - output = ruby_exe(<<-RUBY) + output = ruby_exe(<<-RUBY, exit_status: nil) at_exit do puts "hello" $stdout.flush @@ -109,7 +109,7 @@ describe "SignalException" do end it "cannot be trapped with Signal.trap" do - ruby_exe(<<-RUBY) + ruby_exe(<<-RUBY, exit_status: nil) Signal.trap("PROF") {} raise(SignalException, "PROF") RUBY @@ -118,7 +118,7 @@ describe "SignalException" do end it "self-signals for USR1" do - ruby_exe("raise(SignalException, 'USR1')") + ruby_exe("raise(SignalException, 'USR1')", exit_status: nil) $?.termsig.should == Signal.list.fetch('USR1') end end diff --git a/spec/ruby/core/exception/system_exit_spec.rb b/spec/ruby/core/exception/system_exit_spec.rb index 5c6116576b..eef9faf271 100644 --- a/spec/ruby/core/exception/system_exit_spec.rb +++ b/spec/ruby/core/exception/system_exit_spec.rb @@ -3,14 +3,14 @@ require_relative '../../spec_helper' describe "SystemExit" do it "sets the exit status and exits silently when raised" do code = 'raise SystemExit.new(7)' - result = ruby_exe(code, args: "2>&1") + result = ruby_exe(code, args: "2>&1", exit_status: 7) result.should == "" $?.exitstatus.should == 7 end it "sets the exit status and exits silently when raised when subclassed" do code = 'class CustomExit < SystemExit; end; raise CustomExit.new(8)' - result = ruby_exe(code, args: "2>&1") + result = ruby_exe(code, args: "2>&1", exit_status: 8) result.should == "" $?.exitstatus.should == 8 end diff --git a/spec/ruby/core/exception/top_level_spec.rb b/spec/ruby/core/exception/top_level_spec.rb index 501c7253c3..5c4514f694 100644 --- a/spec/ruby/core/exception/top_level_spec.rb +++ b/spec/ruby/core/exception/top_level_spec.rb @@ -2,7 +2,7 @@ require_relative '../../spec_helper' describe "An Exception reaching the top level" do it "is printed on STDERR" do - ruby_exe('raise "foo"', args: "2>&1").should.include?("in `
': foo (RuntimeError)") + ruby_exe('raise "foo"', args: "2>&1", exit_status: 1).should.include?("in `
': foo (RuntimeError)") end ruby_version_is "2.6" do @@ -20,7 +20,7 @@ describe "An Exception reaching the top level" do raise_wrapped end RUBY - lines = ruby_exe(code, args: "2>&1").lines + lines = ruby_exe(code, args: "2>&1", exit_status: 1).lines lines.reject! { |l| l.include?('rescue in') } lines.map! { |l| l.chomp[/:(in.+)/, 1] } lines.should == ["in `raise_wrapped': wrapped (RuntimeError)", @@ -38,7 +38,7 @@ describe "An Exception reaching the top level" do "/dir/bar.rb:20:in `caller'", ] RUBY - ruby_exe(code, args: "2>&1").should == <<-EOS + ruby_exe(code, args: "2>&1", exit_status: 1).should == <<-EOS /dir/foo.rb:10:in `raising': foo (RuntimeError) \tfrom /dir/bar.rb:20:in `caller' EOS diff --git a/spec/ruby/core/fiber/raise_spec.rb b/spec/ruby/core/fiber/raise_spec.rb index f56219e565..2a465c8bfa 100644 --- a/spec/ruby/core/fiber/raise_spec.rb +++ b/spec/ruby/core/fiber/raise_spec.rb @@ -72,6 +72,26 @@ ruby_version_is "2.7" do -> { fiber.raise }.should raise_error -> { fiber.resume }.should raise_error(FiberError, /dead fiber called|attempt to resume a terminated fiber/) end + + it "returns to calling fiber after raise" do + fiber_one = Fiber.new do + Fiber.yield :yield_one + :unreachable + end + + fiber_two = Fiber.new do + results = [] + results << fiber_one.resume + begin + fiber_one.raise + rescue + results << :rescued + end + results + end + + fiber_two.resume.should == [:yield_one, :rescued] + end end end diff --git a/spec/ruby/core/file/atime_spec.rb b/spec/ruby/core/file/atime_spec.rb index 047bb0e10e..cef07ba010 100644 --- a/spec/ruby/core/file/atime_spec.rb +++ b/spec/ruby/core/file/atime_spec.rb @@ -16,20 +16,17 @@ describe "File.atime" do end platform_is :linux, :windows do - ## NOTE also that some Linux systems disable atime (e.g. via mount params) for better filesystem speed. - it "returns the last access time for the named file with microseconds" do - supports_subseconds = Integer(`stat -c%x '#{__FILE__}'`[/\.(\d+)/, 1], 10) - if supports_subseconds != 0 - expected_time = Time.at(Time.now.to_i + 0.123456) - File.utime expected_time, 0, @file - # FIXME: A random failing test on Travis ppc64le. - # https://bugs.ruby-lang.org/issues/17926 - if ENV.key?('TRAVIS') && ENV['TRAVIS_CPU_ARCH'] == 'ppc64le' - skip '[ruby-core:17926] A random failure on Travis ppc64le' + platform_is_not :"powerpc64le-linux" do # https://bugs.ruby-lang.org/issues/17926 + ## NOTE also that some Linux systems disable atime (e.g. via mount params) for better filesystem speed. + it "returns the last access time for the named file with microseconds" do + supports_subseconds = Integer(`stat -c%x '#{__FILE__}'`[/\.(\d+)/, 1], 10) + if supports_subseconds != 0 + expected_time = Time.at(Time.now.to_i + 0.123456) + File.utime expected_time, 0, @file + File.atime(@file).usec.should == expected_time.usec + else + File.atime(__FILE__).usec.should == 0 end - File.atime(@file).usec.should == expected_time.usec - else - File.atime(__FILE__).usec.should == 0 end end end diff --git a/spec/ruby/core/file/basename_spec.rb b/spec/ruby/core/file/basename_spec.rb index 6d7e432086..989409d76b 100644 --- a/spec/ruby/core/file/basename_spec.rb +++ b/spec/ruby/core/file/basename_spec.rb @@ -164,5 +164,20 @@ describe "File.basename" do basename.encoding.should == Encoding::Windows_1250 end + it "returns a new unfrozen String" do + exts = [nil, '.rb', '.*', '.txt'] + ['foo.rb','//', '/test/', 'test'].each do |example| + exts.each do |ext| + original = example.freeze + result = if ext + File.basename(original, ext) + else + File.basename(original) + end + result.should_not equal(original) + result.frozen?.should == false + end + end + end end diff --git a/spec/ruby/core/hash/rehash_spec.rb b/spec/ruby/core/hash/rehash_spec.rb index ff7b644786..0049080456 100644 --- a/spec/ruby/core/hash/rehash_spec.rb +++ b/spec/ruby/core/hash/rehash_spec.rb @@ -59,6 +59,24 @@ describe "Hash#rehash" do h.keys.should == [a] end + it "removes duplicate keys for large hashes" do + a = [1,2] + b = [1] + + h = {} + h[a] = true + h[b] = true + 100.times { |n| h[n] = true } + b << 2 + h.size.should == 102 + h.keys.should.include? a + h.keys.should.include? b + h.rehash + h.size.should == 101 + h.keys.should.include? a + h.keys.should_not.include? [1] + end + it "raises a FrozenError if called on a frozen instance" do -> { HashSpecs.frozen_hash.rehash }.should raise_error(FrozenError) -> { HashSpecs.empty_frozen_hash.rehash }.should raise_error(FrozenError) diff --git a/spec/ruby/core/io/binmode_spec.rb b/spec/ruby/core/io/binmode_spec.rb index b698777cad..342cac2a9b 100644 --- a/spec/ruby/core/io/binmode_spec.rb +++ b/spec/ruby/core/io/binmode_spec.rb @@ -57,4 +57,8 @@ describe "IO#binmode?" do @duped = @file.dup @duped.binmode?.should == @file.binmode? end + + it "raises an IOError on closed stream" do + -> { IOSpecs.closed_io.binmode? }.should raise_error(IOError) + end end diff --git a/spec/ruby/core/io/dup_spec.rb b/spec/ruby/core/io/dup_spec.rb index 8cadaee118..68d538377f 100644 --- a/spec/ruby/core/io/dup_spec.rb +++ b/spec/ruby/core/io/dup_spec.rb @@ -84,4 +84,23 @@ end dup.close end end + + it "always sets the autoclose flag for the new IO object" do + @f.autoclose = true + dup = @f.dup + begin + dup.should.autoclose? + ensure + dup.close + end + + @f.autoclose = false + dup = @f.dup + begin + dup.should.autoclose? + ensure + dup.close + @f.autoclose = true + end + end end diff --git a/spec/ruby/core/io/external_encoding_spec.rb b/spec/ruby/core/io/external_encoding_spec.rb index 9666974647..c1b727d930 100644 --- a/spec/ruby/core/io/external_encoding_spec.rb +++ b/spec/ruby/core/io/external_encoding_spec.rb @@ -1,4 +1,5 @@ require_relative '../../spec_helper' +require_relative 'fixtures/classes' describe :io_external_encoding_write, shared: true do describe "when Encoding.default_internal is nil" do @@ -93,6 +94,10 @@ describe "IO#external_encoding" do rm_r @name end + it "raises an IOError on closed stream" do + -> { IOSpecs.closed_io.external_encoding }.should raise_error(IOError) + end + describe "with 'r' mode" do describe "when Encoding.default_internal is nil" do before :each do diff --git a/spec/ruby/core/io/internal_encoding_spec.rb b/spec/ruby/core/io/internal_encoding_spec.rb index 10ebf28707..210e969c7b 100644 --- a/spec/ruby/core/io/internal_encoding_spec.rb +++ b/spec/ruby/core/io/internal_encoding_spec.rb @@ -1,4 +1,5 @@ require_relative '../../spec_helper' +require_relative 'fixtures/classes' describe :io_internal_encoding, shared: true do describe "when Encoding.default_internal is not set" do @@ -112,6 +113,10 @@ describe "IO#internal_encoding" do Encoding.default_internal = @internal end + it "raises an IOError on closed stream" do + -> { IOSpecs.closed_io.internal_encoding }.should raise_error(IOError) + end + describe "with 'r' mode" do it_behaves_like :io_internal_encoding, nil, "r" end diff --git a/spec/ruby/core/io/lineno_spec.rb b/spec/ruby/core/io/lineno_spec.rb index 3d1b2275cc..99266ecca1 100644 --- a/spec/ruby/core/io/lineno_spec.rb +++ b/spec/ruby/core/io/lineno_spec.rb @@ -14,6 +14,24 @@ describe "IO#lineno" do -> { IOSpecs.closed_io.lineno }.should raise_error(IOError) end + it "raises an IOError on a write-only stream" do + name = tmp("io_lineno.txt") + begin + File.open(name, 'w') do |f| + -> { f.lineno }.should raise_error(IOError) + end + ensure + rm_r name + end + end + + it "raises an IOError on a duplexed stream with the read side closed" do + IO.popen('cat', 'r+') do |p| + p.close_read + -> { p.lineno }.should raise_error(IOError) + end + end + it "returns the current line number" do @io.lineno.should == 0 @@ -40,6 +58,24 @@ describe "IO#lineno=" do -> { IOSpecs.closed_io.lineno = 5 }.should raise_error(IOError) end + it "raises an IOError on a write-only stream" do + name = tmp("io_lineno.txt") + begin + File.open(name, 'w') do |f| + -> { f.lineno = 0 }.should raise_error(IOError) + end + ensure + rm_r name + end + end + + it "raises an IOError on a duplexed stream with the read side closed" do + IO.popen('cat', 'r+') do |p| + p.close_read + -> { p.lineno = 0 }.should raise_error(IOError) + end + end + it "calls #to_int on a non-numeric argument" do obj = mock('123') obj.should_receive(:to_int).and_return(123) diff --git a/spec/ruby/core/io/set_encoding_by_bom_spec.rb b/spec/ruby/core/io/set_encoding_by_bom_spec.rb index b8e4eedcb9..c551042bee 100644 --- a/spec/ruby/core/io/set_encoding_by_bom_spec.rb +++ b/spec/ruby/core/io/set_encoding_by_bom_spec.rb @@ -34,6 +34,20 @@ describe "IO#set_encoding_by_bom" do @io.external_encoding.should == Encoding::UTF_16BE end + it "returns the result encoding if found BOM UTF_32LE sequence" do + File.binwrite(@name, "\xFF\xFE\x00\x00abc") + + @io.set_encoding_by_bom.should == Encoding::UTF_32LE + @io.external_encoding.should == Encoding::UTF_32LE + end + + it "returns the result encoding if found BOM UTF_32BE sequence" do + File.binwrite(@name, "\x00\x00\xFE\xFFabc") + + @io.set_encoding_by_bom.should == Encoding::UTF_32BE + @io.external_encoding.should == Encoding::UTF_32BE + end + it "returns nil if found BOM sequence not provided" do File.write(@name, "abc") diff --git a/spec/ruby/core/io/sysread_spec.rb b/spec/ruby/core/io/sysread_spec.rb index 024200efea..8201ad47ca 100644 --- a/spec/ruby/core/io/sysread_spec.rb +++ b/spec/ruby/core/io/sysread_spec.rb @@ -50,6 +50,11 @@ describe "IO#sysread on a file" do @file.sysread(5).should == "56789" end + it "raises an error when called after buffered reads" do + @file.readline + -> { @file.sysread(5) }.should raise_error(IOError) + end + it "reads normally even when called immediately after a buffered IO#read" do @file.read(15) @file.sysread(5).should == "56789" diff --git a/spec/ruby/core/io/sysseek_spec.rb b/spec/ruby/core/io/sysseek_spec.rb index df894734e3..e631939bce 100644 --- a/spec/ruby/core/io/sysseek_spec.rb +++ b/spec/ruby/core/io/sysseek_spec.rb @@ -26,6 +26,11 @@ describe "IO#sysseek" do -> { @io.sysseek(-5, IO::SEEK_CUR) }.should raise_error(IOError) end + it "seeks normally even when called immediately after a buffered IO#read" do + @io.read(15) + @io.sysseek(-5, IO::SEEK_CUR).should == 10 + end + it "moves the read position relative to the start with SEEK_SET" do @io.sysseek(43, IO::SEEK_SET) @io.readline.should == "Aquí está la línea tres.\n" diff --git a/spec/ruby/core/kernel/at_exit_spec.rb b/spec/ruby/core/kernel/at_exit_spec.rb index 7bdb5391fe..a784c1ae17 100644 --- a/spec/ruby/core/kernel/at_exit_spec.rb +++ b/spec/ruby/core/kernel/at_exit_spec.rb @@ -33,31 +33,32 @@ describe "Kernel.at_exit" do end EOC - result = ruby_exe(code, args: "2>&1") + result = ruby_exe(code, args: "2>&1", exit_status: 1) result.lines.should.include?("The exception matches: true (message=foo)\n") end it "both exceptions in at_exit and in the main script are printed" do - result = ruby_exe('at_exit { raise "at_exit_error" }; raise "main_script_error"', args: "2>&1") + code = 'at_exit { raise "at_exit_error" }; raise "main_script_error"' + result = ruby_exe(code, args: "2>&1", exit_status: 1) result.should.include?('at_exit_error (RuntimeError)') result.should.include?('main_script_error (RuntimeError)') end it "decides the exit status if both at_exit and the main script raise SystemExit" do - ruby_exe('at_exit { exit 43 }; exit 42', args: "2>&1") + ruby_exe('at_exit { exit 43 }; exit 42', args: "2>&1", exit_status: 43) $?.exitstatus.should == 43 end it "runs all at_exit even if some raise exceptions" do code = 'at_exit { STDERR.puts "last" }; at_exit { exit 43 }; at_exit { STDERR.puts "first" }; exit 42' - result = ruby_exe(code, args: "2>&1") + result = ruby_exe(code, args: "2>&1", exit_status: 43) result.should == "first\nlast\n" $?.exitstatus.should == 43 end it "runs at_exit handlers even if the main script fails to parse" do script = fixture(__FILE__, "at_exit.rb") - result = ruby_exe('{', options: "-r#{script}", args: "2>&1") + result = ruby_exe('{', options: "-r#{script}", args: "2>&1", exit_status: 1) $?.should_not.success? result.should.include?("at_exit ran\n") result.should.include?("syntax error") diff --git a/spec/ruby/core/kernel/eval_spec.rb b/spec/ruby/core/kernel/eval_spec.rb index c53e51e430..1e2764a4de 100644 --- a/spec/ruby/core/kernel/eval_spec.rb +++ b/spec/ruby/core/kernel/eval_spec.rb @@ -228,6 +228,17 @@ describe "Kernel#eval" do ruby_exe(code).chomp.should == "a,b,c,e,LocalJumpError,f" end + it "can be called with Method#call" do + method(:eval).call("2 * 3").should == 6 + end + + it "has the correct default definee when called through Method#call" do + class EvalSpecs + method(:eval).call("def eval_spec_method_call; end") + EvalSpecs.should have_instance_method(:eval_spec_method_call) + end + end + # See language/magic_comment_spec.rb for more magic comments specs describe "with a magic encoding comment" do it "uses the magic comment encoding for the encoding of literal strings" do @@ -374,43 +385,45 @@ CODE end end - it "activates refinements from the eval scope" do - refinery = Module.new do - refine EvalSpecs::A do - def foo - "bar" + describe 'with refinements' do + it "activates refinements from the eval scope" do + refinery = Module.new do + refine EvalSpecs::A do + def foo + "bar" + end end end - end - result = nil + result = nil - Module.new do - using refinery + Module.new do + using refinery - result = eval "EvalSpecs::A.new.foo" - end + result = eval "EvalSpecs::A.new.foo" + end - result.should == "bar" - end + result.should == "bar" + end - it "activates refinements from the binding" do - refinery = Module.new do - refine EvalSpecs::A do - def foo - "bar" + it "activates refinements from the binding" do + refinery = Module.new do + refine EvalSpecs::A do + def foo + "bar" + end end end - end - b = nil - m = Module.new do - using refinery - b = binding - end + b = nil + m = Module.new do + using refinery + b = binding + end - result = eval "EvalSpecs::A.new.foo", b + result = eval "EvalSpecs::A.new.foo", b - result.should == "bar" + result.should == "bar" + end end end diff --git a/spec/ruby/core/kernel/format_spec.rb b/spec/ruby/core/kernel/format_spec.rb index 72fd40b952..e8b031e480 100644 --- a/spec/ruby/core/kernel/format_spec.rb +++ b/spec/ruby/core/kernel/format_spec.rb @@ -1,6 +1,7 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' +# NOTE: most specs are in sprintf_spec.rb, this is just an alias describe "Kernel#format" do it "is a private method" do Kernel.should have_private_instance_method(:format) diff --git a/spec/ruby/core/kernel/inspect_spec.rb b/spec/ruby/core/kernel/inspect_spec.rb index a946d032db..e6fca8bf6f 100644 --- a/spec/ruby/core/kernel/inspect_spec.rb +++ b/spec/ruby/core/kernel/inspect_spec.rb @@ -30,4 +30,12 @@ describe "Kernel#inspect" do obj = Object.new obj.inspect.should =~ /^#$/ end + + it "returns a String for an object without #class method" do + obj = Object.new + class << obj + undef_method :class + end + obj.inspect.should be_kind_of(String) + end end diff --git a/spec/ruby/core/kernel/shared/sprintf.rb b/spec/ruby/core/kernel/shared/sprintf.rb index ca1e6bb2ed..6d62a65f7c 100644 --- a/spec/ruby/core/kernel/shared/sprintf.rb +++ b/spec/ruby/core/kernel/shared/sprintf.rb @@ -342,6 +342,23 @@ describe :kernel_sprintf, shared: true do sub_string = long_string[8, 5] sprintf("%.#{1 * 3}s", sub_string).should == "hel" end + + it "formats string with precision" do + Kernel.format("%.3s", "hello").should == "hel" + Kernel.format("%-3.3s", "hello").should == "hel" + end + + it "formats multibyte string with precision" do + Kernel.format("%.2s", "été").should == "ét" + end + + it "preserves encoding of the format string" do + str = format('%s'.encode(Encoding::UTF_8), 'foobar') + str.encoding.should == Encoding::UTF_8 + + str = format('%s'.encode(Encoding::US_ASCII), 'foobar') + str.encoding.should == Encoding::US_ASCII + end end describe "%" do diff --git a/spec/ruby/core/module/define_method_spec.rb b/spec/ruby/core/module/define_method_spec.rb index 49472c18e1..0cb2ab140c 100644 --- a/spec/ruby/core/module/define_method_spec.rb +++ b/spec/ruby/core/module/define_method_spec.rb @@ -88,6 +88,23 @@ describe "Module#define_method when given an UnboundMethod" do end end +describe "Module#define_method" do + describe "when the default definee is not the same as the module" do + it "sets the visibility of the method to public" do + klass = Class.new + class << klass + private + define_method(:meta) do + define_method(:foo) { :foo } + end + end + + klass.send :meta + klass.new.foo.should == :foo + end + end +end + describe "Module#define_method when name is not a special private name" do describe "given an UnboundMethod" do describe "and called from the target module" do @@ -491,7 +508,36 @@ describe "Module#define_method" do it "receives the value passed as the argument when passed one argument" do @klass.new.m(1).should == 1 end + end + + describe "passed { |a,| } creates a method that" do + before :each do + @klass = Class.new do + define_method(:m) { |a,| a } + end + end + it "raises an ArgumentError when passed zero arguments" do + -> { @klass.new.m }.should raise_error(ArgumentError) + end + + it "raises an ArgumentError when passed zero arguments and a block" do + -> { @klass.new.m { :computed } }.should raise_error(ArgumentError) + end + + it "raises an ArgumentError when passed two arguments" do + -> { @klass.new.m 1, 2 }.should raise_error(ArgumentError) + end + + it "receives the value passed as the argument when passed one argument" do + @klass.new.m(1).should == 1 + end + + it "does not destructure the passed argument" do + @klass.new.m([1, 2]).should == [1, 2] + # for comparison: + proc { |a,| a }.call([1, 2]).should == 1 + end end describe "passed { |*a| } creates a method that" do diff --git a/spec/ruby/core/module/include_spec.rb b/spec/ruby/core/module/include_spec.rb index e7f99a5981..c7ead1079c 100644 --- a/spec/ruby/core/module/include_spec.rb +++ b/spec/ruby/core/module/include_spec.rb @@ -234,6 +234,148 @@ describe "Module#include" do remove_const :C end end + + it "updates the method when an included module is updated" do + a_class = Class.new do + def foo + 'a' + end + end + + m_module = Module.new + + b_class = Class.new(a_class) do + include m_module + end + + b = b_class.new + + foo = -> { b.foo } + + foo.call.should == 'a' + + m_module.module_eval do + def foo + 'm' + end + end + + foo.call.should == 'm' + end + + + it "updates the method when a module included after a call is later updated" do + m_module = Module.new + a_class = Class.new do + def foo + 'a' + end + end + b_class = Class.new(a_class) + b = b_class.new + foo = -> { b.foo } + foo.call.should == 'a' + + b_class.include m_module + foo.call.should == 'a' + + m_module.module_eval do + def foo + "m" + end + end + foo.call.should == 'm' + end + + it "updates the method when a nested included module is updated" do + a_class = Class.new do + def foo + 'a' + end + end + + n_module = Module.new + + m_module = Module.new do + include n_module + end + + b_class = Class.new(a_class) do + include m_module + end + + b = b_class.new + + foo = -> { b.foo } + + foo.call.should == 'a' + + n_module.module_eval do + def foo + 'n' + end + end + + foo.call.should == 'n' + end + + it "updates the method when a new module is included" do + a_class = Class.new do + def foo + 'a' + end + end + + m_module = Module.new do + def foo + 'm' + end + end + + b_class = Class.new(a_class) + b = b_class.new + + foo = -> { b.foo } + + foo.call.should == 'a' + + b_class.class_eval do + include m_module + end + + foo.call.should == 'm' + end + + it "updates the method when a new module with nested module is included" do + a_class = Class.new do + def foo + 'a' + end + end + + n_module = Module.new do + def foo + 'n' + end + end + + m_module = Module.new do + include n_module + end + + b_class = Class.new(a_class) + b = b_class.new + + foo = -> { b.foo } + + foo.call.should == 'a' + + b_class.class_eval do + include m_module + end + + foo.call.should == 'n' + end end describe "Module#include?" do diff --git a/spec/ruby/core/module/prepend_spec.rb b/spec/ruby/core/module/prepend_spec.rb index a501b5e50c..f11ca1b8b6 100644 --- a/spec/ruby/core/module/prepend_spec.rb +++ b/spec/ruby/core/module/prepend_spec.rb @@ -36,6 +36,192 @@ describe "Module#prepend" do ScratchPad.recorded.should == [ [ m3, c], [ m2, c ], [ m, c ] ] end + it "updates the method when a module is prepended" do + m_module = Module.new do + def foo + "m" + end + end + a_class = Class.new do + def foo + 'a' + end + end + a = a_class.new + foo = -> { a.foo } + foo.call.should == 'a' + a_class.class_eval do + prepend m_module + end + foo.call.should == 'm' + end + + it "updates the method when a prepended module is updated" do + m_module = Module.new + a_class = Class.new do + prepend m_module + def foo + 'a' + end + end + a = a_class.new + foo = -> { a.foo } + foo.call.should == 'a' + m_module.module_eval do + def foo + "m" + end + end + foo.call.should == 'm' + end + + it "updates the method when there is a base included method and the prepended module overrides it" do + base_module = Module.new do + def foo + 'a' + end + end + a_class = Class.new do + include base_module + end + a = a_class.new + foo = -> { a.foo } + foo.call.should == 'a' + + m_module = Module.new do + def foo + "m" + end + end + a_class.prepend m_module + foo.call.should == 'm' + end + + it "updates the method when there is a base included method and the prepended module is later updated" do + base_module = Module.new do + def foo + 'a' + end + end + a_class = Class.new do + include base_module + end + a = a_class.new + foo = -> { a.foo } + foo.call.should == 'a' + + m_module = Module.new + a_class.prepend m_module + foo.call.should == 'a' + + m_module.module_eval do + def foo + "m" + end + end + foo.call.should == 'm' + end + + it "updates the method when a module prepended after a call is later updated" do + m_module = Module.new + a_class = Class.new do + def foo + 'a' + end + end + a = a_class.new + foo = -> { a.foo } + foo.call.should == 'a' + + a_class.prepend m_module + foo.call.should == 'a' + + m_module.module_eval do + def foo + "m" + end + end + foo.call.should == 'm' + end + + it "updates the method when a module is prepended after another and the method is defined later on that module" do + m_module = Module.new do + def foo + 'a' + end + end + a_class = Class.new + a_class.prepend m_module + a = a_class.new + foo = -> { a.foo } + foo.call.should == 'a' + + n_module = Module.new + a_class.prepend n_module + foo.call.should == 'a' + + n_module.module_eval do + def foo + "n" + end + end + foo.call.should == 'n' + end + + it "updates the method when a module is included in a prepended module and the method is defined later" do + a_class = Class.new + base_module = Module.new do + def foo + 'a' + end + end + a_class.prepend base_module + a = a_class.new + foo = -> { a.foo } + foo.call.should == 'a' + + m_module = Module.new + n_module = Module.new + m_module.include n_module + a_class.prepend m_module + + n_module.module_eval do + def foo + "n" + end + end + foo.call.should == 'n' + end + + it "updates the method when a new module with an included module is prepended" do + a_class = Class.new do + def foo + 'a' + end + end + + n_module = Module.new do + def foo + 'n' + end + end + + m_module = Module.new do + include n_module + end + + a = a_class.new + foo = -> { a.foo } + + foo.call.should == 'a' + + a_class.class_eval do + prepend m_module + end + + foo.call.should == 'n' + end + it "raises a TypeError when the argument is not a Module" do -> { ModuleSpecs::Basic.prepend(Class.new) }.should raise_error(TypeError) end diff --git a/spec/ruby/core/module/remove_method_spec.rb b/spec/ruby/core/module/remove_method_spec.rb index b6ae02078f..94b255df62 100644 --- a/spec/ruby/core/module/remove_method_spec.rb +++ b/spec/ruby/core/module/remove_method_spec.rb @@ -43,6 +43,28 @@ describe "Module#remove_method" do x.method_to_remove.should == 1 end + it "updates the method implementation" do + m_module = Module.new do + def foo + 'm' + end + end + + a_class = Class.new do + include m_module + + def foo + 'a' + end + end + + a = a_class.new + foo = -> { a.foo } + foo.call.should == 'a' + a_class.remove_method(:foo) + foo.call.should == 'm' + end + it "removes multiple methods with 1 call" do klass = Class.new do def method_to_remove_1; 1; end diff --git a/spec/ruby/core/objectspace/_id2ref_spec.rb b/spec/ruby/core/objectspace/_id2ref_spec.rb index 6e8828348e..c088ae2743 100644 --- a/spec/ruby/core/objectspace/_id2ref_spec.rb +++ b/spec/ruby/core/objectspace/_id2ref_spec.rb @@ -7,16 +7,43 @@ describe "ObjectSpace._id2ref" do r.should == s end - it "retrieves an Integer by object_id" do - f = 1 - r = ObjectSpace._id2ref(f.object_id) - r.should == f + it "retrieves true by object_id" do + ObjectSpace._id2ref(true.object_id).should == true + end + + it "retrieves false by object_id" do + ObjectSpace._id2ref(false.object_id).should == false + end + + it "retrieves nil by object_id" do + ObjectSpace._id2ref(nil.object_id).should == nil + end + + it "retrieves a small Integer by object_id" do + ObjectSpace._id2ref(1.object_id).should == 1 + ObjectSpace._id2ref((-42).object_id).should == -42 + end + + it "retrieves a large Integer by object_id" do + obj = 1 << 88 + ObjectSpace._id2ref(obj.object_id).should.equal?(obj) end it "retrieves a Symbol by object_id" do - s = :sym - r = ObjectSpace._id2ref(s.object_id) - r.should == s + ObjectSpace._id2ref(:sym.object_id).should.equal?(:sym) + end + + it "retrieves a String by object_id" do + obj = "str" + ObjectSpace._id2ref(obj.object_id).should.equal?(obj) + end + + it "retrieves a frozen literal String by object_id" do + ObjectSpace._id2ref("frozen string literal _id2ref".freeze.object_id).should.equal?("frozen string literal _id2ref".freeze) + end + + it "retrieves an Encoding by object_id" do + ObjectSpace._id2ref(Encoding::UTF_8.object_id).should.equal?(Encoding::UTF_8) end it 'raises RangeError when an object could not be found' do diff --git a/spec/ruby/core/objectspace/define_finalizer_spec.rb b/spec/ruby/core/objectspace/define_finalizer_spec.rb index ed021b7131..281785b0a4 100644 --- a/spec/ruby/core/objectspace/define_finalizer_spec.rb +++ b/spec/ruby/core/objectspace/define_finalizer_spec.rb @@ -4,7 +4,7 @@ require_relative 'fixtures/classes' # Why do we not test that finalizers are run by the GC? The documentation # says that finalizers are never guaranteed to be run, so we can't # spec that they are. On some implementations of Ruby the finalizers may -# run asyncronously, meaning that we can't predict when they'll run, +# run asynchronously, meaning that we can't predict when they'll run, # even if they were guaranteed to do so. Even on MRI finalizers can be # very unpredictable, due to conservative stack scanning and references # left in unused memory. diff --git a/spec/ruby/core/process/status/equal_value_spec.rb b/spec/ruby/core/process/status/equal_value_spec.rb index 444ce1775b..d85bb22214 100644 --- a/spec/ruby/core/process/status/equal_value_spec.rb +++ b/spec/ruby/core/process/status/equal_value_spec.rb @@ -2,13 +2,13 @@ require_relative '../../../spec_helper' describe "Process::Status#==" do it "returns true when compared to the integer status of an exited child" do - ruby_exe("exit(29)") + ruby_exe("exit(29)", exit_status: 29) $?.to_i.should == $? $?.should == $?.to_i end it "returns true when compared to the integer status of a terminated child" do - ruby_exe("Process.kill(:KILL, $$); exit(29)") + ruby_exe("Process.kill(:KILL, $$); exit(29)", exit_status: platform_is(:windows) ? 0 : nil) $?.to_i.should == $? $?.should == $?.to_i end diff --git a/spec/ruby/core/process/status/exited_spec.rb b/spec/ruby/core/process/status/exited_spec.rb index 0ae3f9e7ae..059cd5b1aa 100644 --- a/spec/ruby/core/process/status/exited_spec.rb +++ b/spec/ruby/core/process/status/exited_spec.rb @@ -1,9 +1,7 @@ require_relative '../../../spec_helper' describe "Process::Status#exited?" do - describe "for a child that exited normally" do - before :each do ruby_exe("exit(0)") end @@ -15,9 +13,8 @@ describe "Process::Status#exited?" do describe "for a terminated child" do - before :each do - ruby_exe("Process.kill(:KILL, $$); exit(42)") + ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : nil) end platform_is_not :windows do @@ -31,7 +28,5 @@ describe "Process::Status#exited?" do $?.exited?.should be_true end end - end - end diff --git a/spec/ruby/core/process/status/exitstatus_spec.rb b/spec/ruby/core/process/status/exitstatus_spec.rb index d6c6965b9e..3087bd619e 100644 --- a/spec/ruby/core/process/status/exitstatus_spec.rb +++ b/spec/ruby/core/process/status/exitstatus_spec.rb @@ -2,7 +2,7 @@ require_relative '../../../spec_helper' describe "Process::Status#exitstatus" do before :each do - ruby_exe("exit(42)") + ruby_exe("exit(42)", exit_status: 42) end it "returns the process exit code" do @@ -11,7 +11,7 @@ describe "Process::Status#exitstatus" do describe "for a child that raised SignalException" do before :each do - ruby_exe("Process.kill(:KILL, $$); exit(42)") + ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : nil) end platform_is_not :windows do diff --git a/spec/ruby/core/process/status/signaled_spec.rb b/spec/ruby/core/process/status/signaled_spec.rb index f23c95025f..389092a533 100644 --- a/spec/ruby/core/process/status/signaled_spec.rb +++ b/spec/ruby/core/process/status/signaled_spec.rb @@ -1,9 +1,7 @@ require_relative '../../../spec_helper' describe "Process::Status#signaled?" do - describe "for a cleanly exited child" do - before :each do ruby_exe("exit(0)") end @@ -14,9 +12,8 @@ describe "Process::Status#signaled?" do end describe "for a terminated child" do - before :each do - ruby_exe("Process.kill(:KILL, $$); exit(42)") + ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : nil) end platform_is_not :windows do @@ -30,6 +27,5 @@ describe "Process::Status#signaled?" do $?.signaled?.should be_false end end - end end diff --git a/spec/ruby/core/process/status/success_spec.rb b/spec/ruby/core/process/status/success_spec.rb index 28a1721800..c531121f08 100644 --- a/spec/ruby/core/process/status/success_spec.rb +++ b/spec/ruby/core/process/status/success_spec.rb @@ -1,9 +1,7 @@ require_relative '../../../spec_helper' describe "Process::Status#success?" do - describe "for a child that exited normally" do - before :each do ruby_exe("exit(0)") end @@ -14,9 +12,8 @@ describe "Process::Status#success?" do end describe "for a child that exited with a non zero status" do - before :each do - ruby_exe("exit(42)") + ruby_exe("exit(42)", exit_status: 42) end it "returns false" do @@ -25,27 +22,20 @@ describe "Process::Status#success?" do end describe "for a child that was terminated" do - before :each do - ruby_exe("Process.kill(:KILL, $$); exit(42)") + ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : nil) end platform_is_not :windows do - it "returns nil" do $?.success?.should be_nil end - end platform_is :windows do - it "always returns true" do $?.success?.should be_true end - end - end - end diff --git a/spec/ruby/core/process/status/termsig_spec.rb b/spec/ruby/core/process/status/termsig_spec.rb index 204708bc1b..1c87a6f455 100644 --- a/spec/ruby/core/process/status/termsig_spec.rb +++ b/spec/ruby/core/process/status/termsig_spec.rb @@ -13,7 +13,7 @@ describe "Process::Status#termsig" do describe "for a child that raised SignalException" do before :each do - ruby_exe("raise SignalException, 'SIGTERM'") + ruby_exe("raise SignalException, 'SIGTERM'", exit_status: nil) end platform_is_not :windows do @@ -25,7 +25,7 @@ describe "Process::Status#termsig" do describe "for a child that was sent a signal" do before :each do - ruby_exe("Process.kill(:KILL, $$); exit(42)") + ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : nil) end platform_is_not :windows do diff --git a/spec/ruby/core/process/status/to_i_spec.rb b/spec/ruby/core/process/status/to_i_spec.rb index a284f64f86..7cde9b915b 100644 --- a/spec/ruby/core/process/status/to_i_spec.rb +++ b/spec/ruby/core/process/status/to_i_spec.rb @@ -2,12 +2,12 @@ require_relative '../../../spec_helper' describe "Process::Status#to_i" do it "returns an integer when the child exits" do - ruby_exe('exit 48') + ruby_exe('exit 48', exit_status: 48) $?.to_i.should be_an_instance_of(Integer) end it "returns an integer when the child is signaled" do - ruby_exe('raise SignalException, "TERM"') + ruby_exe('raise SignalException, "TERM"', exit_status: platform_is(:windows) ? 3 : nil) $?.to_i.should be_an_instance_of(Integer) end end diff --git a/spec/ruby/core/range/step_spec.rb b/spec/ruby/core/range/step_spec.rb index 1c2e30742c..be4b482654 100644 --- a/spec/ruby/core/range/step_spec.rb +++ b/spec/ruby/core/range/step_spec.rb @@ -207,11 +207,17 @@ describe "Range#step" do ScratchPad.recorded.should eql([-1.0, -0.5, 0.0, 0.5]) end + it "returns Float values of 'step * n + begin < end'" do + (1.0...6.4).step(1.8) { |x| ScratchPad << x } + ScratchPad.recorded.should eql([1.0, 2.8, 4.6]) + end + ruby_version_is '3.1' do - it "returns Float values of 'step * n + begin < end'" do - (1.0...6.4).step(1.8) { |x| ScratchPad << x } + it "correctly handles values near the upper limit" do # https://bugs.ruby-lang.org/issues/16612 (1.0...55.6).step(18.2) { |x| ScratchPad << x } - ScratchPad.recorded.should eql([1.0, 2.8, 4.6, 1.0, 19.2, 37.4, 55.599999999999994]) + ScratchPad.recorded.should eql([1.0, 19.2, 37.4, 55.599999999999994]) + + (1.0...55.6).step(18.2).size.should == 4 end end @@ -459,21 +465,18 @@ describe "Range#step" do (-1.0...1.0).step(0.5).size.should == 4 end - ruby_version_is '3.1' do - it "returns the range size when there's no step_size" do - (-2..2).step.size.should == 5 - (-2.0..2.0).step.size.should == 5 - (-2..2.0).step.size.should == 5 - (-2.0..2).step.size.should == 5 - (1.0..6.4).step(1.8).size.should == 4 - (1.0..12.7).step(1.3).size.should == 10 - (-2...2).step.size.should == 4 - (-2.0...2.0).step.size.should == 4 - (-2...2.0).step.size.should == 4 - (-2.0...2).step.size.should == 4 - (1.0...6.4).step(1.8).size.should == 3 - (1.0...55.6).step(18.2).size.should == 4 - end + it "returns the range size when there's no step_size" do + (-2..2).step.size.should == 5 + (-2.0..2.0).step.size.should == 5 + (-2..2.0).step.size.should == 5 + (-2.0..2).step.size.should == 5 + (1.0..6.4).step(1.8).size.should == 4 + (1.0..12.7).step(1.3).size.should == 10 + (-2...2).step.size.should == 4 + (-2.0...2.0).step.size.should == 4 + (-2...2.0).step.size.should == 4 + (-2.0...2).step.size.should == 4 + (1.0...6.4).step(1.8).size.should == 3 end it "returns nil with begin and end are String" do diff --git a/spec/ruby/core/signal/trap_spec.rb b/spec/ruby/core/signal/trap_spec.rb index 61d39cfa93..3c78922694 100644 --- a/spec/ruby/core/signal/trap_spec.rb +++ b/spec/ruby/core/signal/trap_spec.rb @@ -254,7 +254,7 @@ describe "Signal.trap" do r.close loop { w.write("a"*1024) } RUBY - out = ruby_exe(code) + out = ruby_exe(code, exit_status: nil) status = $? out.should == "nil\n" status.should.signaled? diff --git a/spec/ruby/core/string/inspect_spec.rb b/spec/ruby/core/string/inspect_spec.rb index 9818796c83..98b5b32b61 100644 --- a/spec/ruby/core/string/inspect_spec.rb +++ b/spec/ruby/core/string/inspect_spec.rb @@ -502,5 +502,11 @@ describe "String#inspect" do "\u{3042}".encode("EUC-JP").inspect.should == '"\\x{A4A2}"' end end + + describe "and the string has both ASCII-compatible and ASCII-incompatible chars" do + it "returns a string with the non-ASCII characters replaced by \\u notation" do + "hello привет".encode("utf-16le").inspect.should == '"hello \\u043F\\u0440\\u0438\\u0432\\u0435\\u0442"' + end + end end end diff --git a/spec/ruby/core/string/rpartition_spec.rb b/spec/ruby/core/string/rpartition_spec.rb index c6428636f6..fc37f8b427 100644 --- a/spec/ruby/core/string/rpartition_spec.rb +++ b/spec/ruby/core/string/rpartition_spec.rb @@ -11,6 +11,19 @@ describe "String#rpartition with String" do "hello".rpartition("hello").should == ["", "hello", ""] end + it "returns original string if regexp doesn't match" do + "hello".rpartition("/x/").should == ["", "", "hello"] + end + + it "returns new object if doesn't match" do + str = "hello" + str.rpartition("/no_match/").last.should_not.equal?(str) + end + + it "handles multibyte string correctly" do + "ユーザ@ドメイン".rpartition(/@/).should == ["ユーザ", "@", "ドメイン"] + end + it "accepts regexp" do "hello!".rpartition(/l./).should == ["hel", "lo", "!"] end diff --git a/spec/ruby/core/string/split_spec.rb b/spec/ruby/core/string/split_spec.rb index 2ebfe1e353..e3641b33e0 100644 --- a/spec/ruby/core/string/split_spec.rb +++ b/spec/ruby/core/string/split_spec.rb @@ -461,6 +461,16 @@ describe "String#split with Regexp" do ->{ broken_str.split(/\r\n|\r|\n/) }.should raise_error(ArgumentError) end + # See https://bugs.ruby-lang.org/issues/12689 and https://github.com/jruby/jruby/issues/4868 + it "allows concurrent Regexp calls in a shared context" do + str = 'a,b,c,d,e' + + p = proc { str.split(/,/) } + results = 10.times.map { Thread.new { x = nil; 100.times { x = p.call }; x } }.map(&:value) + + results.should == [%w[a b c d e]] * 10 + end + ruby_version_is "2.6" do context "when a block is given" do it "yields each split substring with default pattern" do diff --git a/spec/ruby/core/struct/dig_spec.rb b/spec/ruby/core/struct/dig_spec.rb index 4e39e5a4ef..93a52dbbe1 100644 --- a/spec/ruby/core/struct/dig_spec.rb +++ b/spec/ruby/core/struct/dig_spec.rb @@ -10,6 +10,16 @@ describe "Struct#dig" do @instance.dig(:a, :a).should == { b: [1, 2, 3] } end + it "accepts String keys" do + @instance.dig('a', 'a').should == { b: [1, 2, 3] } + end + + it "returns the value by the index" do + instance = Struct.new(:a, :b).new(:one, :two) + instance.dig(0).should == :one + instance.dig(1).should == :two + end + it "returns the nested value specified if the sequence includes an index" do @instance.dig(:a, :a, :b, 0).should == 1 end -- cgit v1.2.3