From 20aa33e388131a0e8b721ec575882513d6a7435f Mon Sep 17 00:00:00 2001 From: Andrew Konchin Date: Thu, 9 May 2024 20:35:01 +0300 Subject: [PATCH] Update to ruby/spec@6b04c1d --- spec/ruby/core/binding/dup_spec.rb | 17 +++++++ spec/ruby/core/enumerator/next_values_spec.rb | 8 +++- spec/ruby/core/enumerator/peek_values_spec.rb | 8 +++- spec/ruby/core/io/pread_spec.rb | 9 +++- spec/ruby/core/io/read_spec.rb | 15 ++++++ spec/ruby/core/io/readpartial_spec.rb | 3 +- spec/ruby/core/io/sysread_spec.rb | 9 +++- spec/ruby/core/module/include_spec.rb | 28 +++++++++++ spec/ruby/core/module/prepend_spec.rb | 48 +++++++++++++++++++ .../core/warning/performance_warning_spec.rb | 28 +++++++++++ spec/ruby/language/break_spec.rb | 19 ++++++++ spec/ruby/language/execution_spec.rb | 4 +- spec/ruby/language/hash_spec.rb | 32 +++++++++++++ spec/ruby/language/keyword_arguments_spec.rb | 28 +++++++++++ .../language/regexp/back-references_spec.rb | 9 ++++ spec/ruby/language/retry_spec.rb | 5 +- spec/ruby/language/yield_spec.rb | 12 +++++ .../library/{ => date}/time/to_date_spec.rb | 2 +- .../{ => datetime}/time/to_datetime_spec.rb | 2 +- .../socket/basicsocket/recv_nonblock_spec.rb | 16 +++++-- .../library/socket/basicsocket/recv_spec.rb | 22 +++++++-- .../socket/socket/recvfrom_nonblock_spec.rb | 21 ++++++++ .../udpsocket/recvfrom_nonblock_spec.rb | 9 ++++ .../socket/unixsocket/recvfrom_spec.rb | 23 +++++++++ spec/ruby/library/stringio/shared/read.rb | 20 +++++++- spec/ruby/optional/capi/class_spec.rb | 12 +++++ spec/ruby/optional/capi/ext/class_spec.c | 5 ++ spec/ruby/optional/capi/ext/gc_spec.c | 10 ++++ spec/ruby/optional/capi/ext/object_spec.c | 16 +++---- spec/ruby/optional/capi/gc_spec.rb | 4 ++ spec/ruby/shared/kernel/at_exit.rb | 6 +++ 31 files changed, 425 insertions(+), 25 deletions(-) create mode 100644 spec/ruby/core/warning/performance_warning_spec.rb rename spec/ruby/library/{ => date}/time/to_date_spec.rb (97%) rename spec/ruby/library/{ => datetime}/time/to_datetime_spec.rb (97%) diff --git a/spec/ruby/core/binding/dup_spec.rb b/spec/ruby/core/binding/dup_spec.rb index 55fac6e3332a84..4eff66bd9a4cc9 100644 --- a/spec/ruby/core/binding/dup_spec.rb +++ b/spec/ruby/core/binding/dup_spec.rb @@ -10,4 +10,21 @@ bind.frozen?.should == true bind.dup.frozen?.should == false end + + it "retains original binding variables but the list is distinct" do + bind1 = binding + eval "a = 1", bind1 + + bind2 = bind1.dup + eval("a = 2", bind2) + eval("a", bind1).should == 2 + eval("a", bind2).should == 2 + + eval("b = 2", bind2) + -> { eval("b", bind1) }.should raise_error(NameError) + eval("b", bind2).should == 2 + + bind1.local_variables.sort.should == [:a, :bind1, :bind2] + bind2.local_variables.sort.should == [:a, :b, :bind1, :bind2] + end end diff --git a/spec/ruby/core/enumerator/next_values_spec.rb b/spec/ruby/core/enumerator/next_values_spec.rb index 201b5d323ffbf8..2202700c588832 100644 --- a/spec/ruby/core/enumerator/next_values_spec.rb +++ b/spec/ruby/core/enumerator/next_values_spec.rb @@ -11,6 +11,7 @@ def o.each yield :e1, :e2, :e3 yield nil yield + yield [:f1, :f2] end @e = o.to_enum @@ -48,8 +49,13 @@ def o.each @e.next_values.should == [] end - it "raises StopIteration if called on a finished enumerator" do + it "returns an array of array if yield is called with an array" do 7.times { @e.next } + @e.next_values.should == [[:f1, :f2]] + end + + it "raises StopIteration if called on a finished enumerator" do + 8.times { @e.next } -> { @e.next_values }.should raise_error(StopIteration) end end diff --git a/spec/ruby/core/enumerator/peek_values_spec.rb b/spec/ruby/core/enumerator/peek_values_spec.rb index 7865546515d460..8b84fc8afcde8f 100644 --- a/spec/ruby/core/enumerator/peek_values_spec.rb +++ b/spec/ruby/core/enumerator/peek_values_spec.rb @@ -11,6 +11,7 @@ def o.each yield :e1, :e2, :e3 yield nil yield + yield [:f1, :f2] end @e = o.to_enum @@ -50,8 +51,13 @@ def o.each @e.peek_values.should == [] end - it "raises StopIteration if called on a finished enumerator" do + it "returns an array of array if yield is called with an array" do 7.times { @e.next } + @e.peek_values.should == [[:f1, :f2]] + end + + it "raises StopIteration if called on a finished enumerator" do + 8.times { @e.next } -> { @e.peek_values }.should raise_error(StopIteration) end end diff --git a/spec/ruby/core/io/pread_spec.rb b/spec/ruby/core/io/pread_spec.rb index 28afc80e5c614f..6d93b432c2636d 100644 --- a/spec/ruby/core/io/pread_spec.rb +++ b/spec/ruby/core/io/pread_spec.rb @@ -22,7 +22,7 @@ it "accepts a length, an offset, and an output buffer" do buffer = +"foo" - @file.pread(3, 4, buffer) + @file.pread(3, 4, buffer).should.equal?(buffer) buffer.should == "567" end @@ -38,6 +38,13 @@ buffer.should == "12345" end + it "preserves the encoding of the given buffer" do + buffer = ''.encode(Encoding::ISO_8859_1) + @file.pread(10, 0, buffer) + + buffer.encoding.should == Encoding::ISO_8859_1 + end + it "does not advance the file pointer" do @file.pread(4, 0).should == "1234" @file.read.should == "1234567890" diff --git a/spec/ruby/core/io/read_spec.rb b/spec/ruby/core/io/read_spec.rb index eb3652e692a581..8741d9f0179a85 100644 --- a/spec/ruby/core/io/read_spec.rb +++ b/spec/ruby/core/io/read_spec.rb @@ -376,6 +376,21 @@ buf.should == @contents[0..4] end + it "preserves the encoding of the given buffer" do + buffer = ''.encode(Encoding::ISO_8859_1) + @io.read(10, buffer) + + buffer.encoding.should == Encoding::ISO_8859_1 + end + + # https://bugs.ruby-lang.org/issues/20416 + it "does not preserve the encoding of the given buffer when max length is not provided" do + buffer = ''.encode(Encoding::ISO_8859_1) + @io.read(nil, buffer) + + buffer.encoding.should_not == Encoding::ISO_8859_1 + end + it "returns the given buffer" do buf = +"" diff --git a/spec/ruby/core/io/readpartial_spec.rb b/spec/ruby/core/io/readpartial_spec.rb index 0060beb54504a5..0852f20b2da83b 100644 --- a/spec/ruby/core/io/readpartial_spec.rb +++ b/spec/ruby/core/io/readpartial_spec.rb @@ -62,7 +62,7 @@ buffer = +"existing content" @wr.write("hello world") @wr.close - @rd.readpartial(11, buffer) + @rd.readpartial(11, buffer).should.equal?(buffer) buffer.should == "hello world" end @@ -106,6 +106,7 @@ @wr.write("abc") @wr.close @rd.readpartial(10, buffer) + buffer.encoding.should == Encoding::ISO_8859_1 end end diff --git a/spec/ruby/core/io/sysread_spec.rb b/spec/ruby/core/io/sysread_spec.rb index 003bb9eb94911a..8851214283ca54 100644 --- a/spec/ruby/core/io/sysread_spec.rb +++ b/spec/ruby/core/io/sysread_spec.rb @@ -97,7 +97,7 @@ it "discards the existing buffer content upon successful read" do buffer = +"existing content" - @file.sysread(11, buffer) + @file.sysread(11, buffer).should.equal?(buffer) buffer.should == "01234567890" end @@ -107,6 +107,13 @@ -> { @file.sysread(1, buffer) }.should raise_error(EOFError) buffer.should be_empty end + + it "preserves the encoding of the given buffer" do + buffer = ''.encode(Encoding::ISO_8859_1) + string = @file.sysread(10, buffer) + + buffer.encoding.should == Encoding::ISO_8859_1 + end end describe "IO#sysread" do diff --git a/spec/ruby/core/module/include_spec.rb b/spec/ruby/core/module/include_spec.rb index c073bc31ca0eea..78f6b410317142 100644 --- a/spec/ruby/core/module/include_spec.rb +++ b/spec/ruby/core/module/include_spec.rb @@ -47,6 +47,34 @@ def self.append_features(mod) -> { ModuleSpecs::SubclassSpec.include(ModuleSpecs::Subclass.new) }.should_not raise_error(TypeError) end + ruby_version_is ""..."3.2" do + it "raises ArgumentError when the argument is a refinement" do + refinement = nil + + Module.new do + refine String do + refinement = self + end + end + + -> { ModuleSpecs::Basic.include(refinement) }.should raise_error(ArgumentError, "refinement module is not allowed") + end + end + + ruby_version_is "3.2" do + it "raises a TypeError when the argument is a refinement" do + refinement = nil + + Module.new do + refine String do + refinement = self + end + end + + -> { ModuleSpecs::Basic.include(refinement) }.should raise_error(TypeError, "Cannot include refinement") + end + end + it "imports constants to modules and classes" do ModuleSpecs::A.constants.should include(:CONSTANT_A) ModuleSpecs::B.constants.should include(:CONSTANT_A, :CONSTANT_B) diff --git a/spec/ruby/core/module/prepend_spec.rb b/spec/ruby/core/module/prepend_spec.rb index c90fa9700ec3b4..b40d12f0deba2d 100644 --- a/spec/ruby/core/module/prepend_spec.rb +++ b/spec/ruby/core/module/prepend_spec.rb @@ -75,6 +75,26 @@ def foo foo.call.should == 'm' end + it "updates the optimized method when a prepended module is updated" do + out = ruby_exe(<<~RUBY) + module M; end + class Integer + prepend M + end + l = -> { 1 + 2 } + p l.call + M.module_eval do + def +(o) + $called = true + super(o) + end + end + p l.call + p $called + RUBY + out.should == "3\n3\ntrue\n" + 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 @@ -415,6 +435,34 @@ module M -> { ModuleSpecs::SubclassSpec.prepend(ModuleSpecs::Subclass.new) }.should_not raise_error(TypeError) end + ruby_version_is ""..."3.2" do + it "raises ArgumentError when the argument is a refinement" do + refinement = nil + + Module.new do + refine String do + refinement = self + end + end + + -> { ModuleSpecs::Basic.prepend(refinement) }.should raise_error(ArgumentError, "refinement module is not allowed") + end + end + + ruby_version_is "3.2" do + it "raises a TypeError when the argument is a refinement" do + refinement = nil + + Module.new do + refine String do + refinement = self + end + end + + -> { ModuleSpecs::Basic.prepend(refinement) }.should raise_error(TypeError, "Cannot prepend refinement") + end + end + it "imports constants" do m1 = Module.new m1::MY_CONSTANT = 1 diff --git a/spec/ruby/core/warning/performance_warning_spec.rb b/spec/ruby/core/warning/performance_warning_spec.rb new file mode 100644 index 00000000000000..ab0badcd3d7f33 --- /dev/null +++ b/spec/ruby/core/warning/performance_warning_spec.rb @@ -0,0 +1,28 @@ +require_relative '../../spec_helper' + + +describe "Performance warnings" do + guard -> { ruby_version_is("3.4") || RUBY_ENGINE == "truffleruby" } do + # Optimising Integer, Float or Symbol methods is kind of implementation detail + # but multiple implementations do so. So it seems reasonable to have a test case + # for at least one such common method. + # See https://bugs.ruby-lang.org/issues/20429 + context "when redefined optimised methods" do + it "emits performance warning for redefining Integer#+" do + code = <<~CODE + Warning[:performance] = true + + class Integer + ORIG_METHOD = instance_method(:+) + + def +(...) + ORIG_METHOD.bind(self).call(...) + end + end + CODE + + ruby_exe(code, args: "2>&1").should.include?("warning: Redefining 'Integer#+' disables interpreter and JIT optimizations") + end + end + end +end diff --git a/spec/ruby/language/break_spec.rb b/spec/ruby/language/break_spec.rb index e725e77e80d0b3..7e5b6fb32859c2 100644 --- a/spec/ruby/language/break_spec.rb +++ b/spec/ruby/language/break_spec.rb @@ -252,6 +252,25 @@ def mid(&b) end end +describe "The break statement in a method" do + it "is invalid and raises a SyntaxError" do + -> { + eval("def m; break; end") + }.should raise_error(SyntaxError) + end +end + +describe "The break statement in a module literal" do + it "is invalid and raises a SyntaxError" do + code = <<~RUBY + module BreakSpecs:ModuleWithBreak + break + end + RUBY + + -> { eval(code) }.should raise_error(SyntaxError) + end +end # TODO: Rewrite all the specs from here to the end of the file in the style # above. diff --git a/spec/ruby/language/execution_spec.rb b/spec/ruby/language/execution_spec.rb index ef1de38899809d..51bcde62e8c745 100644 --- a/spec/ruby/language/execution_spec.rb +++ b/spec/ruby/language/execution_spec.rb @@ -38,7 +38,7 @@ 2.times do runner.instance_exec do - `test #{:command}` + `test #{:command}` # rubocop:disable Lint/LiteralInInterpolation end end @@ -84,7 +84,7 @@ 2.times do runner.instance_exec do - %x{test #{:command}} + %x{test #{:command}} # rubocop:disable Lint/LiteralInInterpolation end end diff --git a/spec/ruby/language/hash_spec.rb b/spec/ruby/language/hash_spec.rb index a7631fb0d6b6fb..068ac0f39c6a5f 100644 --- a/spec/ruby/language/hash_spec.rb +++ b/spec/ruby/language/hash_spec.rb @@ -86,6 +86,30 @@ -> { eval("{:a ==> 1}") }.should raise_error(SyntaxError) end + it "recognizes '!' at the end of the key" do + eval("{:a! =>1}").should == {:"a!" => 1} + eval("{:a! => 1}").should == {:"a!" => 1} + + eval("{a!:1}").should == {:"a!" => 1} + eval("{a!: 1}").should == {:"a!" => 1} + end + + it "raises a SyntaxError if there is no space between `!` and `=>`" do + -> { eval("{:a!=> 1}") }.should raise_error(SyntaxError) + end + + it "recognizes '?' at the end of the key" do + eval("{:a? =>1}").should == {:"a?" => 1} + eval("{:a? => 1}").should == {:"a?" => 1} + + eval("{a?:1}").should == {:"a?" => 1} + eval("{a?: 1}").should == {:"a?" => 1} + end + + it "raises a SyntaxError if there is no space between `?` and `=>`" do + -> { eval("{:a?=> 1}") }.should raise_error(SyntaxError) + end + it "constructs a new hash with the given elements" do {foo: 123}.should == {foo: 123} h = {rbx: :cool, specs: 'fail_sometimes'} @@ -271,6 +295,14 @@ def foo(val) a.new.foo(1).should == {bar: "baz", val: 1} end + + it "raises a SyntaxError when the hash key ends with `!`" do + -> { eval("{a!:}") }.should raise_error(SyntaxError, /identifier a! is not valid to get/) + end + + it "raises a SyntaxError when the hash key ends with `?`" do + -> { eval("{a?:}") }.should raise_error(SyntaxError, /identifier a\? is not valid to get/) + end end end end diff --git a/spec/ruby/language/keyword_arguments_spec.rb b/spec/ruby/language/keyword_arguments_spec.rb index ffb5b1fab06cc4..8668799d26cd1e 100644 --- a/spec/ruby/language/keyword_arguments_spec.rb +++ b/spec/ruby/language/keyword_arguments_spec.rb @@ -395,4 +395,32 @@ def n(*args) # Note the missing ruby2_keywords here end end end + + context "in define_method(name, &proc)" do + # This tests that a free-standing proc used in define_method and converted to ruby2_keywords adopts that logic. + # See jruby/jruby#8119 for a case where aggressive JIT optimization broke later ruby2_keywords changes. + it "works with ruby2_keywords" do + m = Class.new do + def bar(a, foo: nil) + [a, foo] + end + + # define_method and ruby2_keywords using send to avoid peephole optimizations + def self.setup + pr = make_proc + send :define_method, :foo, &pr + send :ruby2_keywords, :foo + end + + # create proc in isolated method to force jit compilation on some implementations + def self.make_proc + proc { |a, *args| bar(a, *args) } + end + end + + m.setup + + m.new.foo(1, foo:2).should == [1, 2] + end + end end diff --git a/spec/ruby/language/regexp/back-references_spec.rb b/spec/ruby/language/regexp/back-references_spec.rb index 26750c20c59a86..627c8daacefa42 100644 --- a/spec/ruby/language/regexp/back-references_spec.rb +++ b/spec/ruby/language/regexp/back-references_spec.rb @@ -22,6 +22,15 @@ $10.should == "0" end + it "returns nil for numbered variable with too large index" do + -> { + eval(<<~CODE).should == nil + "a" =~ /(.)/ + eval('$4294967296') + CODE + }.should complain(/warning: ('|`)\$4294967296' is too big for a number variable, always nil/) + end + it "will not clobber capture variables across threads" do cap1, cap2, cap3 = nil "foo" =~ /(o+)/ diff --git a/spec/ruby/language/retry_spec.rb b/spec/ruby/language/retry_spec.rb index ee5377946f7ef9..669d5f0ff51904 100644 --- a/spec/ruby/language/retry_spec.rb +++ b/spec/ruby/language/retry_spec.rb @@ -31,8 +31,11 @@ results.should == [1, 2, 3, 1, 2, 4, 5, 6, 4, 5] end - it "raises a SyntaxError when used outside of a begin statement" do + it "raises a SyntaxError when used outside of a rescue statement" do -> { eval 'retry' }.should raise_error(SyntaxError) + -> { eval 'begin; retry; end' }.should raise_error(SyntaxError) + -> { eval 'def m; retry; end' }.should raise_error(SyntaxError) + -> { eval 'module RetrySpecs; retry; end' }.should raise_error(SyntaxError) end end diff --git a/spec/ruby/language/yield_spec.rb b/spec/ruby/language/yield_spec.rb index 5283517636d202..e125cf8e738bea 100644 --- a/spec/ruby/language/yield_spec.rb +++ b/spec/ruby/language/yield_spec.rb @@ -206,3 +206,15 @@ class << Object.new -> { eval(code) }.should raise_error(SyntaxError, /Invalid yield/) end end + +describe "Using yield in a module literal" do + it 'raises a SyntaxError' do + code = <<~RUBY + module YieldSpecs::ModuleWithYield + yield + end + RUBY + + -> { eval(code) }.should raise_error(SyntaxError, /Invalid yield/) + end +end diff --git a/spec/ruby/library/time/to_date_spec.rb b/spec/ruby/library/date/time/to_date_spec.rb similarity index 97% rename from spec/ruby/library/time/to_date_spec.rb rename to spec/ruby/library/date/time/to_date_spec.rb index baeafe0847a7d2..f9132da2890e92 100644 --- a/spec/ruby/library/time/to_date_spec.rb +++ b/spec/ruby/library/date/time/to_date_spec.rb @@ -1,5 +1,5 @@ -require_relative '../../spec_helper' +require_relative '../../../spec_helper' require 'time' describe "Time#to_date" do diff --git a/spec/ruby/library/time/to_datetime_spec.rb b/spec/ruby/library/datetime/time/to_datetime_spec.rb similarity index 97% rename from spec/ruby/library/time/to_datetime_spec.rb rename to spec/ruby/library/datetime/time/to_datetime_spec.rb index 9c44f38e5c2ff1..1125dbe851c8fa 100644 --- a/spec/ruby/library/time/to_datetime_spec.rb +++ b/spec/ruby/library/datetime/time/to_datetime_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../spec_helper' +require_relative '../../../spec_helper' require 'time' require 'date' date_version = defined?(Date::VERSION) ? Date::VERSION : '3.1.0' diff --git a/spec/ruby/library/socket/basicsocket/recv_nonblock_spec.rb b/spec/ruby/library/socket/basicsocket/recv_nonblock_spec.rb index 17c846054df17a..df42c116fb33f1 100644 --- a/spec/ruby/library/socket/basicsocket/recv_nonblock_spec.rb +++ b/spec/ruby/library/socket/basicsocket/recv_nonblock_spec.rb @@ -52,9 +52,19 @@ @s2.send("data", 0, @s1.getsockname) IO.select([@s1], nil, nil, 2) - buf = +"foo" - @s1.recv_nonblock(5, 0, buf) - buf.should == "data" + buffer = +"foo" + @s1.recv_nonblock(5, 0, buffer).should.equal?(buffer) + buffer.should == "data" + end + + it "preserves the encoding of the given buffer" do + @s1.bind(Socket.pack_sockaddr_in(0, ip_address)) + @s2.send("data", 0, @s1.getsockname) + IO.select([@s1], nil, nil, 2) + + buffer = ''.encode(Encoding::ISO_8859_1) + @s1.recv_nonblock(5, 0, buffer) + buffer.encoding.should == Encoding::ISO_8859_1 end it "does not block if there's no data available" do diff --git a/spec/ruby/library/socket/basicsocket/recv_spec.rb b/spec/ruby/library/socket/basicsocket/recv_spec.rb index 9fe8c52f9a5233..e82a357d3dfd35 100644 --- a/spec/ruby/library/socket/basicsocket/recv_spec.rb +++ b/spec/ruby/library/socket/basicsocket/recv_spec.rb @@ -100,13 +100,29 @@ socket.write("data") client = @server.accept - buf = +"foo" + buffer = +"foo" begin - client.recv(4, 0, buf) + client.recv(4, 0, buffer).should.equal?(buffer) ensure client.close end - buf.should == "data" + buffer.should == "data" + + socket.close + end + + it "preserves the encoding of the given buffer" do + socket = TCPSocket.new('127.0.0.1', @port) + socket.write("data") + + client = @server.accept + buffer = ''.encode(Encoding::ISO_8859_1) + begin + client.recv(4, 0, buffer) + ensure + client.close + end + buffer.encoding.should == Encoding::ISO_8859_1 socket.close end diff --git a/spec/ruby/library/socket/socket/recvfrom_nonblock_spec.rb b/spec/ruby/library/socket/socket/recvfrom_nonblock_spec.rb index 94f58ac49f4ac6..5596f91bb86b07 100644 --- a/spec/ruby/library/socket/socket/recvfrom_nonblock_spec.rb +++ b/spec/ruby/library/socket/socket/recvfrom_nonblock_spec.rb @@ -52,6 +52,27 @@ end end + it "allows an output buffer as third argument" do + @client.write('hello') + + IO.select([@server]) + buffer = +'' + message, = @server.recvfrom_nonblock(5, 0, buffer) + + message.should.equal?(buffer) + buffer.should == 'hello' + end + + it "preserves the encoding of the given buffer" do + @client.write('hello') + + IO.select([@server]) + buffer = ''.encode(Encoding::ISO_8859_1) + @server.recvfrom_nonblock(5, 0, buffer) + + buffer.encoding.should == Encoding::ISO_8859_1 + end + describe 'the returned data' do it 'is the same as the sent data' do 5.times do diff --git a/spec/ruby/library/socket/udpsocket/recvfrom_nonblock_spec.rb b/spec/ruby/library/socket/udpsocket/recvfrom_nonblock_spec.rb index 650a061221b8c1..b8040995897c34 100644 --- a/spec/ruby/library/socket/udpsocket/recvfrom_nonblock_spec.rb +++ b/spec/ruby/library/socket/udpsocket/recvfrom_nonblock_spec.rb @@ -58,6 +58,15 @@ buffer.should == 'h' end + it "preserves the encoding of the given buffer" do + buffer = ''.encode(Encoding::ISO_8859_1) + IO.select([@server]) + message, = @server.recvfrom_nonblock(1, 0, buffer) + + message.should.equal?(buffer) + buffer.encoding.should == Encoding::ISO_8859_1 + end + describe 'the returned Array' do before do IO.select([@server]) diff --git a/spec/ruby/library/socket/unixsocket/recvfrom_spec.rb b/spec/ruby/library/socket/unixsocket/recvfrom_spec.rb index fedf74bb2fa2ac..d849fdc302646b 100644 --- a/spec/ruby/library/socket/unixsocket/recvfrom_spec.rb +++ b/spec/ruby/library/socket/unixsocket/recvfrom_spec.rb @@ -31,6 +31,29 @@ sock.close end + it "allows an output buffer as third argument" do + buffer = +'' + + @client.send("foobar", 0) + sock = @server.accept + message, = sock.recvfrom(6, 0, buffer) + sock.close + + message.should.equal?(buffer) + buffer.should == "foobar" + end + + it "preserves the encoding of the given buffer" do + buffer = ''.encode(Encoding::ISO_8859_1) + + @client.send("foobar", 0) + sock = @server.accept + sock.recvfrom(6, 0, buffer) + sock.close + + buffer.encoding.should == Encoding::ISO_8859_1 + end + it "uses different message options" do @client.send("foobar", Socket::MSG_PEEK) sock = @server.accept diff --git a/spec/ruby/library/stringio/shared/read.rb b/spec/ruby/library/stringio/shared/read.rb index e3840786d902fa..8ef6ec273427a1 100644 --- a/spec/ruby/library/stringio/shared/read.rb +++ b/spec/ruby/library/stringio/shared/read.rb @@ -11,10 +11,28 @@ end it "reads length bytes and writes them to the buffer String" do - @io.send(@method, 7, buffer = +"") + @io.send(@method, 7, buffer = +"").should.equal?(buffer) buffer.should == "example" end + ruby_version_is ""..."3.4" do + it "does not preserve the encoding of the given buffer" do + buffer = ''.encode(Encoding::ISO_8859_1) + @io.send(@method, 7, buffer) + + buffer.encoding.should_not == Encoding::ISO_8859_1 + end + end + + ruby_version_is "3.4" do + it "preserves the encoding of the given buffer" do + buffer = ''.encode(Encoding::ISO_8859_1) + @io.send(@method, 7, buffer) + + buffer.encoding.should == Encoding::ISO_8859_1 + end + end + it "tries to convert the passed buffer Object to a String using #to_str" do obj = mock("to_str") obj.should_receive(:to_str).and_return(buffer = +"") diff --git a/spec/ruby/optional/capi/class_spec.rb b/spec/ruby/optional/capi/class_spec.rb index d0a9913570ddb2..a231245ebe8158 100644 --- a/spec/ruby/optional/capi/class_spec.rb +++ b/spec/ruby/optional/capi/class_spec.rb @@ -487,4 +487,16 @@ def obj.some_method() end @s.rb_class_real(0).should == 0 end end + + describe "rb_class_get_superclass" do + it "returns parent class for a provided class" do + a = Class.new + @s.rb_class_get_superclass(Class.new(a)).should == a + end + + it "returns false when there is no parent class" do + @s.rb_class_get_superclass(BasicObject).should == false + @s.rb_class_get_superclass(Module.new).should == false + end + end end diff --git a/spec/ruby/optional/capi/ext/class_spec.c b/spec/ruby/optional/capi/ext/class_spec.c index f376534924cf1c..c13f02ecf23c79 100644 --- a/spec/ruby/optional/capi/ext/class_spec.c +++ b/spec/ruby/optional/capi/ext/class_spec.c @@ -79,6 +79,10 @@ static VALUE class_spec_rb_class_real(VALUE self, VALUE object) { } } +static VALUE class_spec_rb_class_get_superclass(VALUE self, VALUE klass) { + return rb_class_get_superclass(klass); +} + static VALUE class_spec_rb_class_superclass(VALUE self, VALUE klass) { return rb_class_superclass(klass); } @@ -160,6 +164,7 @@ void Init_class_spec(void) { rb_define_method(cls, "rb_class_new_instance_kw", class_spec_rb_class_new_instance_kw, 2); #endif rb_define_method(cls, "rb_class_real", class_spec_rb_class_real, 1); + rb_define_method(cls, "rb_class_get_superclass", class_spec_rb_class_get_superclass, 1); rb_define_method(cls, "rb_class_superclass", class_spec_rb_class_superclass, 1); rb_define_method(cls, "rb_cvar_defined", class_spec_cvar_defined, 2); rb_define_method(cls, "rb_cvar_get", class_spec_cvar_get, 2); diff --git a/spec/ruby/optional/capi/ext/gc_spec.c b/spec/ruby/optional/capi/ext/gc_spec.c index 1392bc6ee668da..2637ad27ac570a 100644 --- a/spec/ruby/optional/capi/ext/gc_spec.c +++ b/spec/ruby/optional/capi/ext/gc_spec.c @@ -16,6 +16,8 @@ VALUE registered_after_rb_global_variable_bignum; VALUE registered_after_rb_global_variable_float; VALUE rb_gc_register_address_outside_init; +VALUE rb_gc_register_mark_object_not_referenced_float; + static VALUE registered_tagged_address(VALUE self) { return registered_tagged_value; } @@ -90,6 +92,10 @@ static VALUE gc_spec_rb_gc_register_mark_object(VALUE self, VALUE obj) { return Qnil; } +static VALUE gc_spec_rb_gc_register_mark_object_not_referenced_float(VALUE self) { + return rb_gc_register_mark_object_not_referenced_float; +} + void Init_gc_spec(void) { VALUE cls = rb_define_class("CApiGCSpecs", rb_cObject); @@ -115,6 +121,9 @@ void Init_gc_spec(void) { registered_after_rb_global_variable_float = DBL2NUM(6.28); rb_global_variable(®istered_after_rb_global_variable_float); + rb_gc_register_mark_object_not_referenced_float = DBL2NUM(1.61); + rb_gc_register_mark_object(rb_gc_register_mark_object_not_referenced_float); + rb_define_method(cls, "registered_tagged_address", registered_tagged_address, 0); rb_define_method(cls, "registered_reference_address", registered_reference_address, 0); rb_define_method(cls, "registered_before_rb_gc_register_address", get_registered_before_rb_gc_register_address, 0); @@ -131,6 +140,7 @@ void Init_gc_spec(void) { rb_define_method(cls, "rb_gc", gc_spec_rb_gc, 0); rb_define_method(cls, "rb_gc_adjust_memory_usage", gc_spec_rb_gc_adjust_memory_usage, 1); rb_define_method(cls, "rb_gc_register_mark_object", gc_spec_rb_gc_register_mark_object, 1); + rb_define_method(cls, "rb_gc_register_mark_object_not_referenced_float", gc_spec_rb_gc_register_mark_object_not_referenced_float, 0); rb_define_method(cls, "rb_gc_latest_gc_info", gc_spec_rb_gc_latest_gc_info, 1); } diff --git a/spec/ruby/optional/capi/ext/object_spec.c b/spec/ruby/optional/capi/ext/object_spec.c index 8aa98cc5ce24c1..aa60662e1e3bb2 100644 --- a/spec/ruby/optional/capi/ext/object_spec.c +++ b/spec/ruby/optional/capi/ext/object_spec.c @@ -390,22 +390,22 @@ static VALUE speced_allocator(VALUE klass) { return instance; } -static VALUE define_alloc_func(VALUE self, VALUE klass) { +static VALUE object_spec_rb_define_alloc_func(VALUE self, VALUE klass) { rb_define_alloc_func(klass, speced_allocator); return Qnil; } -static VALUE undef_alloc_func(VALUE self, VALUE klass) { +static VALUE object_spec_rb_undef_alloc_func(VALUE self, VALUE klass) { rb_undef_alloc_func(klass); return Qnil; } -static VALUE speced_allocator_p(VALUE self, VALUE klass) { +static VALUE object_spec_speced_allocator_p(VALUE self, VALUE klass) { rb_alloc_func_t allocator = rb_get_alloc_func(klass); return (allocator == speced_allocator) ? Qtrue : Qfalse; } -static VALUE custom_alloc_func_p(VALUE self, VALUE klass) { +static VALUE object_spec_custom_alloc_func_p(VALUE self, VALUE klass) { rb_alloc_func_t allocator = rb_get_alloc_func(klass); return allocator ? Qtrue : Qfalse; } @@ -485,10 +485,10 @@ void Init_object_spec(void) { rb_define_method(cls, "rb_ivar_defined", object_spec_rb_ivar_defined, 2); rb_define_method(cls, "rb_copy_generic_ivar", object_spec_rb_copy_generic_ivar, 2); rb_define_method(cls, "rb_free_generic_ivar", object_spec_rb_free_generic_ivar, 1); - rb_define_method(cls, "rb_define_alloc_func", define_alloc_func, 1); - rb_define_method(cls, "rb_undef_alloc_func", undef_alloc_func, 1); - rb_define_method(cls, "speced_allocator?", speced_allocator_p, 1); - rb_define_method(cls, "custom_alloc_func?", custom_alloc_func_p, 1); + rb_define_method(cls, "rb_define_alloc_func", object_spec_rb_define_alloc_func, 1); + rb_define_method(cls, "rb_undef_alloc_func", object_spec_rb_undef_alloc_func, 1); + rb_define_method(cls, "speced_allocator?", object_spec_speced_allocator_p, 1); + rb_define_method(cls, "custom_alloc_func?", object_spec_custom_alloc_func_p, 1); rb_define_method(cls, "not_implemented_method", rb_f_notimplement, -1); rb_define_method(cls, "rb_ivar_foreach", object_spec_rb_ivar_foreach, 1); } diff --git a/spec/ruby/optional/capi/gc_spec.rb b/spec/ruby/optional/capi/gc_spec.rb index aaced56483a0cc..d9661328ab39a0 100644 --- a/spec/ruby/optional/capi/gc_spec.rb +++ b/spec/ruby/optional/capi/gc_spec.rb @@ -108,6 +108,10 @@ it "can be called with an object" do @f.rb_gc_register_mark_object(Object.new).should be_nil end + + it "keeps the value alive even if the value is not referenced by any Ruby object" do + @f.rb_gc_register_mark_object_not_referenced_float.should == 1.61 + end end describe "rb_gc_latest_gc_info" do diff --git a/spec/ruby/shared/kernel/at_exit.rb b/spec/ruby/shared/kernel/at_exit.rb index 16d41cb01c93b1..29db79bb391428 100644 --- a/spec/ruby/shared/kernel/at_exit.rb +++ b/spec/ruby/shared/kernel/at_exit.rb @@ -30,6 +30,12 @@ result.lines.should.include?("The exception matches: true (message=foo)\n") end + it "gives access to an exception raised in a previous handler" do + code = "#{@method} { print '$!.message = ' + $!.message }; #{@method} { raise 'foo' }" + result = ruby_exe(code, args: "2>&1", exit_status: 1) + result.lines.should.include?("$!.message = foo") + end + it "both exceptions in a handler and in the main script are printed" do code = "#{@method} { raise 'at_exit_error' }; raise 'main_script_error'" result = ruby_exe(code, args: "2>&1", exit_status: 1)