This commit is contained in:
Andrew Konchin 2024-04-01 17:52:57 +03:00 committed by Benoit Daloze
parent 8b55aaa85c
commit 1e5949bd60
28 changed files with 719 additions and 47 deletions

View File

@ -28,6 +28,15 @@ describe "The --disable-frozen-string-literal flag causes string literals to" do
end
describe "With neither --enable-frozen-string-literal nor --disable-frozen-string-literal flag set" do
before do
# disable --enable-frozen-string-literal and --disable-frozen-string-literal passed in $RUBYOPT
@rubyopt = ENV["RUBYOPT"]
ENV["RUBYOPT"] = ""
end
after do
ENV["RUBYOPT"] = @rubyopt
end
it "produce a different object each time" do
ruby_exe(fixture(__FILE__, "freeze_flag_one_literal.rb")).chomp.should == "false"

View File

@ -7,7 +7,7 @@ ruby_version_is '3.1' do
assert_subclasses(ModuleSpecs::Parent, [ModuleSpecs::Child, ModuleSpecs::Child2])
end
it "does not return included modules" do
it "does not return included modules from the parent" do
parent = Class.new
child = Class.new(parent)
mod = Module.new
@ -16,6 +16,33 @@ ruby_version_is '3.1' do
assert_subclasses(parent, [child])
end
it "does not return included modules from the child" do
parent = Class.new
child = Class.new(parent)
mod = Module.new
parent.include(mod)
assert_subclasses(parent, [child])
end
it "does not return prepended modules from the parent" do
parent = Class.new
child = Class.new(parent)
mod = Module.new
parent.prepend(mod)
assert_subclasses(parent, [child])
end
it "does not return prepended modules from the child" do
parent = Class.new
child = Class.new(parent)
mod = Module.new
child.prepend(mod)
assert_subclasses(parent, [child])
end
it "does not return singleton classes" do
a = Class.new

View File

@ -131,4 +131,17 @@ describe "Dir#children" do
children = @dir.children.sort
children.first.encoding.should equal(Encoding::EUC_KR)
end
it "returns the same result when called repeatedly" do
@dir = Dir.open DirSpecs.mock_dir
a = []
@dir.each {|dir| a << dir}
b = []
@dir.each {|dir| b << dir}
a.sort.should == b.sort
a.sort.should == DirSpecs.expected_paths
end
end

View File

@ -86,6 +86,19 @@ describe "Dir#each_child" do
@dir.each_child { |f| f }.should == @dir
end
it "returns the same result when called repeatedly" do
@dir = Dir.open DirSpecs.mock_dir
a = []
@dir.each {|dir| a << dir}
b = []
@dir.each {|dir| b << dir}
a.sort.should == b.sort
a.sort.should == DirSpecs.expected_paths
end
describe "when no block is given" do
it "returns an Enumerator" do
@dir = Dir.new(DirSpecs.mock_dir)

View File

@ -35,6 +35,17 @@ describe "Dir#each" do
ls.should include(@dir.read)
end
it "returns the same result when called repeatedly" do
a = []
@dir.each {|dir| a << dir}
b = []
@dir.each {|dir| b << dir}
a.sort.should == b.sort
a.sort.should == DirSpecs.expected_paths
end
describe "when no block is given" do
it "returns an Enumerator" do
@dir.each.should be_an_instance_of(Enumerator)

View File

@ -0,0 +1,3 @@
# rubocop:disable Lint/Syntax
1+1=2
# rubocop:enable Lint/Syntax

View File

@ -0,0 +1,27 @@
require_relative '../../spec_helper'
ruby_version_is "3.2" do
describe "SyntaxError#path" do
it "returns the file path provided to eval" do
filename = "speccing.rb"
-> {
eval("if true", TOPLEVEL_BINDING, filename)
}.should raise_error(SyntaxError) { |e|
e.path.should == filename
}
end
it "returns the file path that raised an exception" do
expected_path = fixture(__FILE__, "syntax_error.rb")
-> {
require_relative "fixtures/syntax_error"
}.should raise_error(SyntaxError) { |e| e.path.should == expected_path }
end
it "returns nil when constructed directly" do
SyntaxError.new.path.should == nil
end
end
end

View File

@ -110,6 +110,10 @@ describe "Hash#compare_by_identity" do
@idh.keys.first.should equal foo
end
# Check `#[]=` call with a String literal.
# Don't use `#+` because with `#+` it's no longer a String literal.
#
# See https://bugs.ruby-lang.org/issues/12855
it "gives different identity for string literals" do
eval <<~RUBY
# frozen_string_literal: false

View File

@ -135,7 +135,7 @@ describe "Kernel#eval" do
it "includes file and line information in syntax error" do
expected = 'speccing.rb'
-> {
eval('if true',TOPLEVEL_BINDING, expected)
eval('if true', TOPLEVEL_BINDING, expected)
}.should raise_error(SyntaxError) { |e|
e.message.should =~ /#{expected}:1:.+/
}
@ -144,7 +144,7 @@ describe "Kernel#eval" do
it "evaluates string with given filename and negative linenumber" do
expected_file = 'speccing.rb'
-> {
eval('if true',TOPLEVEL_BINDING, expected_file, -100)
eval('if true', TOPLEVEL_BINDING, expected_file, -100)
}.should raise_error(SyntaxError) { |e|
e.message.should =~ /#{expected_file}:-100:.+/
}

View File

@ -647,7 +647,7 @@ describe :marshal_load, shared: true do
end
it "sets binmode if it is loading through StringIO stream" do
io = StringIO.new(+"\004\b:\vsymbol")
io = StringIO.new("\004\b:\vsymbol")
def io.binmode; raise "binmode"; end
-> { Marshal.load(io) }.should raise_error(RuntimeError, "binmode")
end

View File

@ -1,7 +1,61 @@
require_relative '../spec_helper'
# Should be synchronized with spec/ruby/language/optional_assignments_spec.rb
# Some specs for assignments are located in language/variables_spec.rb
describe 'Assignments' do
describe 'using =' do
describe 'evaluation order' do
it 'evaluates expressions left to right when assignment with an accessor' do
object = Object.new
def object.a=(value) end
ScratchPad.record []
(ScratchPad << :receiver; object).a = (ScratchPad << :rhs; :value)
ScratchPad.recorded.should == [:receiver, :rhs]
end
it 'evaluates expressions left to right when assignment with a #[]=' do
object = Object.new
def object.[]=(_, _) end
ScratchPad.record []
(ScratchPad << :receiver; object)[(ScratchPad << :argument; :a)] = (ScratchPad << :rhs; :value)
ScratchPad.recorded.should == [:receiver, :argument, :rhs]
end
# similar tests for evaluation order are located in language/constants_spec.rb
ruby_version_is ''...'3.2' do
it 'evaluates expressions right to left when assignment with compounded constant' do
m = Module.new
ScratchPad.record []
(ScratchPad << :module; m)::A = (ScratchPad << :rhs; :value)
ScratchPad.recorded.should == [:rhs, :module]
end
end
ruby_version_is '3.2' do
it 'evaluates expressions left to right when assignment with compounded constant' do
m = Module.new
ScratchPad.record []
(ScratchPad << :module; m)::A = (ScratchPad << :rhs; :value)
ScratchPad.recorded.should == [:module, :rhs]
end
end
it 'raises TypeError after evaluation of right-hand-side when compounded constant module is not a module' do
ScratchPad.record []
-> {
(:not_a_module)::A = (ScratchPad << :rhs; :value)
}.should raise_error(TypeError)
ScratchPad.recorded.should == [:rhs]
end
end
end
describe 'using +=' do
describe 'using an accessor' do
before do
@ -148,3 +202,328 @@ describe 'Assignments' do
end
end
end
# generic cases
describe 'Multiple assignments' do
it 'assigns multiple targets when assignment with an accessor' do
object = Object.new
class << object
attr_accessor :a, :b
end
object.a, object.b = :a, :b
object.a.should == :a
object.b.should == :b
end
it 'assigns multiple targets when assignment with a nested accessor' do
object = Object.new
class << object
attr_accessor :a, :b
end
(object.a, object.b), c = [:a, :b], nil
object.a.should == :a
object.b.should == :b
end
it 'assigns multiple targets when assignment with a #[]=' do
object = Object.new
class << object
def []=(k, v) (@h ||= {})[k] = v; end
def [](k) (@h ||= {})[k]; end
end
object[:a], object[:b] = :a, :b
object[:a].should == :a
object[:b].should == :b
end
it 'assigns multiple targets when assignment with a nested #[]=' do
object = Object.new
class << object
def []=(k, v) (@h ||= {})[k] = v; end
def [](k) (@h ||= {})[k]; end
end
(object[:a], object[:b]), c = [:v1, :v2], nil
object[:a].should == :v1
object[:b].should == :v2
end
it 'assigns multiple targets when assignment with compounded constant' do
m = Module.new
m::A, m::B = :a, :b
m::A.should == :a
m::B.should == :b
end
it 'assigns multiple targets when assignment with a nested compounded constant' do
m = Module.new
(m::A, m::B), c = [:a, :b], nil
m::A.should == :a
m::B.should == :b
end
end
describe 'Multiple assignments' do
describe 'evaluation order' do
ruby_version_is ''...'3.1' do
it 'evaluates expressions right to left when assignment with an accessor' do
object = Object.new
def object.a=(value) end
ScratchPad.record []
(ScratchPad << :a; object).a, (ScratchPad << :b; object).a = (ScratchPad << :c; :c), (ScratchPad << :d; :d)
ScratchPad.recorded.should == [:c, :d, :a, :b]
end
it 'evaluates expressions right to left when assignment with a nested accessor' do
object = Object.new
def object.a=(value) end
ScratchPad.record []
((ScratchPad << :a; object).a, foo), bar = [(ScratchPad << :b; :b)]
ScratchPad.recorded.should == [:b, :a]
end
end
ruby_version_is '3.1' do
it 'evaluates expressions left to right when assignment with an accessor' do
object = Object.new
def object.a=(value) end
ScratchPad.record []
(ScratchPad << :a; object).a, (ScratchPad << :b; object).a = (ScratchPad << :c; :c), (ScratchPad << :d; :d)
ScratchPad.recorded.should == [:a, :b, :c, :d]
end
it 'evaluates expressions left to right when assignment with a nested accessor' do
object = Object.new
def object.a=(value) end
ScratchPad.record []
((ScratchPad << :a; object).a, foo), bar = [(ScratchPad << :b; :b)]
ScratchPad.recorded.should == [:a, :b]
end
it 'evaluates expressions left to right when assignment with a deeply nested accessor' do
o = Object.new
def o.a=(value) end
def o.b=(value) end
def o.c=(value) end
def o.d=(value) end
def o.e=(value) end
def o.f=(value) end
ScratchPad.record []
(ScratchPad << :a; o).a,
((ScratchPad << :b; o).b,
((ScratchPad << :c; o).c, (ScratchPad << :d; o).d),
(ScratchPad << :e; o).e),
(ScratchPad << :f; o).f = (ScratchPad << :value; :value)
ScratchPad.recorded.should == [:a, :b, :c, :d, :e, :f, :value]
end
end
ruby_version_is ''...'3.1' do
it 'evaluates expressions right to left when assignment with a #[]=' do
object = Object.new
def object.[]=(_, _) end
ScratchPad.record []
(ScratchPad << :a; object)[(ScratchPad << :b; :b)], (ScratchPad << :c; object)[(ScratchPad << :d; :d)] = (ScratchPad << :e; :e), (ScratchPad << :f; :f)
ScratchPad.recorded.should == [:e, :f, :a, :b, :c, :d]
end
it 'evaluates expressions right to left when assignment with a nested #[]=' do
object = Object.new
def object.[]=(_, _) end
ScratchPad.record []
((ScratchPad << :a; object)[(ScratchPad << :b; :b)], foo), bar = [(ScratchPad << :c; :c)]
ScratchPad.recorded.should == [:c, :a, :b]
end
end
ruby_version_is '3.1' do
it 'evaluates expressions left to right when assignment with a #[]=' do
object = Object.new
def object.[]=(_, _) end
ScratchPad.record []
(ScratchPad << :a; object)[(ScratchPad << :b; :b)], (ScratchPad << :c; object)[(ScratchPad << :d; :d)] = (ScratchPad << :e; :e), (ScratchPad << :f; :f)
ScratchPad.recorded.should == [:a, :b, :c, :d, :e, :f]
end
it 'evaluates expressions left to right when assignment with a nested #[]=' do
object = Object.new
def object.[]=(_, _) end
ScratchPad.record []
((ScratchPad << :a; object)[(ScratchPad << :b; :b)], foo), bar = [(ScratchPad << :c; :c)]
ScratchPad.recorded.should == [:a, :b, :c]
end
it 'evaluates expressions left to right when assignment with a deeply nested #[]=' do
o = Object.new
def o.[]=(_, _) end
ScratchPad.record []
(ScratchPad << :ra; o)[(ScratchPad << :aa; :aa)],
((ScratchPad << :rb; o)[(ScratchPad << :ab; :ab)],
((ScratchPad << :rc; o)[(ScratchPad << :ac; :ac)], (ScratchPad << :rd; o)[(ScratchPad << :ad; :ad)]),
(ScratchPad << :re; o)[(ScratchPad << :ae; :ae)]),
(ScratchPad << :rf; o)[(ScratchPad << :af; :af)] = (ScratchPad << :value; :value)
ScratchPad.recorded.should == [:ra, :aa, :rb, :ab, :rc, :ac, :rd, :ad, :re, :ae, :rf, :af, :value]
end
end
ruby_version_is ''...'3.2' do
it 'evaluates expressions right to left when assignment with compounded constant' do
m = Module.new
ScratchPad.record []
(ScratchPad << :a; m)::A, (ScratchPad << :b; m)::B = (ScratchPad << :c; :c), (ScratchPad << :d; :d)
ScratchPad.recorded.should == [:c, :d, :a, :b]
end
end
ruby_version_is '3.2' do
it 'evaluates expressions left to right when assignment with compounded constant' do
m = Module.new
ScratchPad.record []
(ScratchPad << :a; m)::A, (ScratchPad << :b; m)::B = (ScratchPad << :c; :c), (ScratchPad << :d; :d)
ScratchPad.recorded.should == [:a, :b, :c, :d]
end
it 'evaluates expressions left to right when assignment with a nested compounded constant' do
m = Module.new
ScratchPad.record []
((ScratchPad << :a; m)::A, foo), bar = [(ScratchPad << :b; :b)]
ScratchPad.recorded.should == [:a, :b]
end
it 'evaluates expressions left to right when assignment with deeply nested compounded constants' do
m = Module.new
ScratchPad.record []
(ScratchPad << :a; m)::A,
((ScratchPad << :b; m)::B,
((ScratchPad << :c; m)::C, (ScratchPad << :d; m)::D),
(ScratchPad << :e; m)::E),
(ScratchPad << :f; m)::F = (ScratchPad << :value; :value)
ScratchPad.recorded.should == [:a, :b, :c, :d, :e, :f, :value]
end
end
end
context 'when assignment with method call and receiver is self' do
it 'assigns values correctly when assignment with accessor' do
object = Object.new
class << object
attr_accessor :a, :b
def assign(v1, v2)
self.a, self.b = v1, v2
end
end
object.assign :v1, :v2
object.a.should == :v1
object.b.should == :v2
end
it 'evaluates expressions right to left when assignment with a nested accessor' do
object = Object.new
class << object
attr_accessor :a, :b
def assign(v1, v2)
(self.a, self.b), c = [v1, v2], nil
end
end
object.assign :v1, :v2
object.a.should == :v1
object.b.should == :v2
end
it 'assigns values correctly when assignment with a #[]=' do
object = Object.new
class << object
def []=(key, v)
@h ||= {}
@h[key] = v
end
def [](key)
(@h || {})[key]
end
def assign(k1, v1, k2, v2)
self[k1], self[k2] = v1, v2
end
end
object.assign :k1, :v1, :k2, :v2
object[:k1].should == :v1
object[:k2].should == :v2
end
it 'assigns values correctly when assignment with a nested #[]=' do
object = Object.new
class << object
def []=(key, v)
@h ||= {}
@h[key] = v
end
def [](key)
(@h || {})[key]
end
def assign(k1, v1, k2, v2)
(self[k1], self[k2]), c = [v1, v2], nil
end
end
object.assign :k1, :v1, :k2, :v2
object[:k1].should == :v1
object[:k2].should == :v2
end
it 'assigns values correctly when assignment with compounded constant' do
m = Module.new
m.module_exec do
self::A, self::B = :v1, :v2
end
m::A.should == :v1
m::B.should == :v2
end
it 'assigns values correctly when assignment with a nested compounded constant' do
m = Module.new
m.module_exec do
(self::A, self::B), c = [:v1, :v2], nil
end
m::A.should == :v1
m::B.should == :v2
end
end
end

View File

@ -415,6 +415,19 @@ describe "The 'case'-construct" do
self.test("bar").should == false
self.test(true).should == true
end
it "warns if there are identical when clauses" do
-> {
eval <<~RUBY
case 1
when 2
:foo
when 2
:bar
end
RUBY
}.should complain(/warning: duplicated .when' clause with line \d+ is ignored/, verbose: true)
end
end
describe "The 'case'-construct with no target expression" do

View File

@ -335,7 +335,7 @@ describe "An ensure block inside 'do end' block" do
begin
raise "oops"
ensure
return caller(0, 2)
return caller(0, 2) # rubocop:disable Lint/EnsureReturn
end
end
line = __LINE__

View File

@ -305,6 +305,15 @@ describe "The if expression" do
6.times(&b)
ScratchPad.recorded.should == [4, 5, 4, 5]
end
it "warns when Integer literals are used instead of predicates" do
-> {
eval <<~RUBY
10.times { |i| ScratchPad << i if 4..5 }
RUBY
}.should complain(/warning: integer literal in flip-flop/, verbose: true)
ScratchPad.recorded.should == []
end
end
describe "when a branch syntactically does not return a value" do

View File

@ -231,9 +231,16 @@ describe "Ruby String literals" do
ruby_exe(fixture(__FILE__, "freeze_magic_comment_across_files.rb")).chomp.should == "true"
end
it "produce different objects for literals with the same content in different files if the other file doesn't have the comment" do
frozen_string_literal = "test".frozen? && "test".equal?("test")
ruby_exe(fixture(__FILE__, "freeze_magic_comment_across_files_no_comment.rb")).chomp.should == (!frozen_string_literal).to_s
guard -> { !(eval("'test'").frozen? && "test".equal?("test")) } do
it "produces different objects for literals with the same content in different files if the other file doesn't have the comment and String literals aren't frozen by default" do
ruby_exe(fixture(__FILE__, "freeze_magic_comment_across_files_no_comment.rb")).chomp.should == "true"
end
end
guard -> { eval("'test'").frozen? && "test".equal?("test") } do
it "produces the same objects for literals with the same content in different files if the other file doesn't have the comment and String literals are frozen by default" do
ruby_exe(fixture(__FILE__, "freeze_magic_comment_across_files_no_comment.rb")).chomp.should == "false"
end
end
it "produce different objects for literals with the same content in different files if they have different encodings" do

View File

@ -48,25 +48,18 @@ describe "IO#wait" do
end
it "waits for the READABLE event to be ready" do
queue = Queue.new
thread = Thread.new { queue.pop; sleep 1; @w.write('data to read') };
@r.wait(IO::READABLE, 0).should == nil
queue.push('signal');
@r.wait(IO::READABLE, 2).should_not == nil
thread.join
@w.write('data to read')
@r.wait(IO::READABLE, 0).should_not == nil
end
it "waits for the WRITABLE event to be ready" do
written_bytes = IOWaitSpec.exhaust_write_buffer(@w)
@w.wait(IO::WRITABLE, 0).should == nil
queue = Queue.new
thread = Thread.new { queue.pop; sleep 1; @r.read(written_bytes) };
queue.push('signal');
@w.wait(IO::WRITABLE, 2).should_not == nil
thread.join
@r.read(written_bytes)
@w.wait(IO::WRITABLE, 0).should_not == nil
end
it "returns nil when the READABLE event is not ready during the timeout" do
@ -89,6 +82,24 @@ describe "IO#wait" do
-> { @w.wait(-1, 0) }.should raise_error(ArgumentError, "Events must be positive integer!")
end
end
it "changes thread status to 'sleep' when waits for READABLE event" do
t = Thread.new { @r.wait(IO::READABLE, 10) }
sleep 1
t.status.should == 'sleep'
t.kill
t.join # Thread#kill doesn't wait for the thread to end
end
it "changes thread status to 'sleep' when waits for WRITABLE event" do
written_bytes = IOWaitSpec.exhaust_write_buffer(@w)
t = Thread.new { @w.wait(IO::WRITABLE, 10) }
sleep 1
t.status.should == 'sleep'
t.kill
t.join # Thread#kill doesn't wait for the thread to end
end
end
context "[timeout, mode] passed" do

View File

@ -8,7 +8,7 @@ describe "Net::HTTPResponse#inspect" do
res.inspect.should == "#<Net::HTTPUnknownResponse ??? test response readbody=false>"
res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
socket = Net::BufferedIO.new(StringIO.new(+"test body"))
socket = Net::BufferedIO.new(StringIO.new("test body"))
res.reading_body(socket, true) {}
res.inspect.should == "#<Net::HTTPUnknownResponse ??? test response readbody=true>"
end

View File

@ -5,7 +5,7 @@ require 'stringio'
describe "Net::HTTPResponse#read_body" do
before :each do
@res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
@socket = Net::BufferedIO.new(StringIO.new(+"test body"))
@socket = Net::BufferedIO.new(StringIO.new("test body"))
end
describe "when passed no arguments" do

View File

@ -5,7 +5,7 @@ require "stringio"
describe "Net::HTTPResponse#reading_body" do
before :each do
@res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
@socket = Net::BufferedIO.new(StringIO.new(+"test body"))
@socket = Net::BufferedIO.new(StringIO.new("test body"))
end
describe "when body_allowed is true" do

View File

@ -3,7 +3,7 @@ require 'stringio'
describe :net_httpresponse_body, shared: true do
before :each do
@res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
@socket = Net::BufferedIO.new(StringIO.new(+"test body"))
@socket = Net::BufferedIO.new(StringIO.new("test body"))
end
it "returns the read body" do

View File

@ -18,7 +18,37 @@ describe "BasicSocket#read_nonblock" do
it "receives data after it's ready" do
IO.select([@r], nil, nil, 2)
@r.recv_nonblock(5).should == "aaa"
@r.read_nonblock(5).should == "aaa"
end
platform_is_not :windows do
it 'returned data is binary encoded regardless of the external encoding' do
IO.select([@r], nil, nil, 2)
@r.read_nonblock(1).encoding.should == Encoding::BINARY
@w.send("bbb", 0, @r.getsockname)
@r.set_encoding(Encoding::ISO_8859_1)
IO.select([@r], nil, nil, 2)
buffer = @r.read_nonblock(3)
buffer.should == "bbb"
buffer.encoding.should == Encoding::BINARY
end
end
it 'replaces the content of the provided buffer without changing its encoding' do
buffer = "initial data".dup.force_encoding(Encoding::UTF_8)
IO.select([@r], nil, nil, 2)
@r.read_nonblock(3, buffer)
buffer.should == "aaa"
buffer.encoding.should == Encoding::UTF_8
@w.send("bbb", 0, @r.getsockname)
@r.set_encoding(Encoding::ISO_8859_1)
IO.select([@r], nil, nil, 2)
@r.read_nonblock(3, buffer)
buffer.should == "bbb"
buffer.encoding.should == Encoding::UTF_8
end
platform_is :linux do

View File

@ -0,0 +1,47 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
describe "BasicSocket#read" do
SocketSpecs.each_ip_protocol do |family, ip_address|
before :each do
@r = Socket.new(family, :DGRAM)
@w = Socket.new(family, :DGRAM)
@r.bind(Socket.pack_sockaddr_in(0, ip_address))
@w.send("aaa", 0, @r.getsockname)
end
after :each do
@r.close unless @r.closed?
@w.close unless @w.closed?
end
it "receives data after it's ready" do
@r.read(3).should == "aaa"
end
it 'returned data is binary encoded regardless of the external encoding' do
@r.read(3).encoding.should == Encoding::BINARY
@w.send("bbb", 0, @r.getsockname)
@r.set_encoding(Encoding::UTF_8)
buffer = @r.read(3)
buffer.should == "bbb"
buffer.encoding.should == Encoding::BINARY
end
it 'replaces the content of the provided buffer without changing its encoding' do
buffer = "initial data".dup.force_encoding(Encoding::UTF_8)
@r.read(3, buffer)
buffer.should == "aaa"
buffer.encoding.should == Encoding::UTF_8
@w.send("bbb", 0, @r.getsockname)
@r.set_encoding(Encoding::ISO_8859_1)
@r.read(3, buffer)
buffer.should == "bbb"
buffer.encoding.should == Encoding::UTF_8
end
end
end

View File

@ -3,6 +3,6 @@ require_relative 'fixtures/classes'
describe "StringIO#fcntl" do
it "raises a NotImplementedError" do
-> { StringIO.new(+"boom").fcntl }.should raise_error(NotImplementedError)
-> { StringIO.new("boom").fcntl }.should raise_error(NotImplementedError)
end
end

View File

@ -172,7 +172,7 @@ end
# NOTE: Synchronise with core/io/new_spec.rb (core/io/shared/new.rb)
describe "StringIO#initialize when passed keyword arguments" do
it "sets the mode based on the passed :mode option" do
io = StringIO.new(+"example", "r")
io = StringIO.new("example", "r")
io.closed_read?.should be_false
io.closed_write?.should be_true
end

View File

@ -33,7 +33,7 @@ end
describe "StringIO#read_nonblock" do
it "accepts an exception option" do
stringio = StringIO.new(+'foo')
stringio = StringIO.new('foo')
stringio.read_nonblock(3, exception: false).should == 'foo'
end

View File

@ -3,11 +3,11 @@ require_relative 'fixtures/classes'
describe "StringIO#reopen when passed [Object, Integer]" do
before :each do
@io = StringIO.new(+"example")
@io = StringIO.new("example")
end
it "reopens self with the passed Object in the passed mode" do
@io.reopen(+"reopened", IO::RDONLY)
@io.reopen("reopened", IO::RDONLY)
@io.closed_read?.should be_false
@io.closed_write?.should be_true
@io.string.should == "reopened"
@ -51,11 +51,11 @@ end
describe "StringIO#reopen when passed [Object, Object]" do
before :each do
@io = StringIO.new(+"example")
@io = StringIO.new("example")
end
it "reopens self with the passed Object in the passed mode" do
@io.reopen(+"reopened", "r")
@io.reopen("reopened", "r")
@io.closed_read?.should be_false
@io.closed_write?.should be_true
@io.string.should == "reopened"
@ -83,7 +83,7 @@ describe "StringIO#reopen when passed [Object, Object]" do
it "tries to convert the passed Object to a String using #to_str" do
obj = mock("to_str")
obj.should_receive(:to_str).and_return(+"to_str")
obj.should_receive(:to_str).and_return("to_str")
@io.reopen(obj, "r")
@io.string.should == "to_str"
end
@ -107,7 +107,7 @@ describe "StringIO#reopen when passed [Object, Object]" do
it "tries to convert the passed mode Object to an Integer using #to_str" do
obj = mock("to_str")
obj.should_receive(:to_str).and_return("r")
@io.reopen(+"reopened", obj)
@io.reopen("reopened", obj)
@io.closed_read?.should be_false
@io.closed_write?.should be_true
@io.string.should == "reopened"
@ -128,7 +128,7 @@ end
describe "StringIO#reopen when passed [String]" do
before :each do
@io = StringIO.new(+"example")
@io = StringIO.new("example")
end
it "reopens self with the passed String in read-write mode" do
@ -157,7 +157,7 @@ end
describe "StringIO#reopen when passed [Object]" do
before :each do
@io = StringIO.new(+"example")
@io = StringIO.new("example")
end
it "raises a TypeError when passed an Object that can't be converted to a StringIO" do
@ -180,7 +180,7 @@ end
describe "StringIO#reopen when passed no arguments" do
before :each do
@io = StringIO.new(+"example\nsecond line")
@io = StringIO.new("example\nsecond line")
end
it "resets self's mode to read-write" do
@ -208,7 +208,7 @@ end
# for details.
describe "StringIO#reopen" do
before :each do
@io = StringIO.new(+'hello','a')
@io = StringIO.new(+'hello', 'a')
end
# TODO: find out if this is really a bug

View File

@ -8,7 +8,12 @@ extern "C" {
VALUE registered_tagged_value;
VALUE registered_reference_value;
VALUE registered_before_rb_gc_register_address;
VALUE registered_before_rb_global_variable;
VALUE registered_before_rb_global_variable_string;
VALUE registered_before_rb_global_variable_bignum;
VALUE registered_before_rb_global_variable_float;
VALUE registered_after_rb_global_variable_string;
VALUE registered_after_rb_global_variable_bignum;
VALUE registered_after_rb_global_variable_float;
VALUE rb_gc_register_address_outside_init;
static VALUE registered_tagged_address(VALUE self) {
@ -23,8 +28,28 @@ static VALUE get_registered_before_rb_gc_register_address(VALUE self) {
return registered_before_rb_gc_register_address;
}
static VALUE get_registered_before_rb_global_variable(VALUE self) {
return registered_before_rb_global_variable;
static VALUE get_registered_before_rb_global_variable_string(VALUE self) {
return registered_before_rb_global_variable_string;
}
static VALUE get_registered_before_rb_global_variable_bignum(VALUE self) {
return registered_before_rb_global_variable_bignum;
}
static VALUE get_registered_before_rb_global_variable_float(VALUE self) {
return registered_before_rb_global_variable_float;
}
static VALUE get_registered_after_rb_global_variable_string(VALUE self) {
return registered_after_rb_global_variable_string;
}
static VALUE get_registered_after_rb_global_variable_bignum(VALUE self) {
return registered_after_rb_global_variable_bignum;
}
static VALUE get_registered_after_rb_global_variable_float(VALUE self) {
return registered_after_rb_global_variable_float;
}
static VALUE gc_spec_rb_gc_register_address(VALUE self) {
@ -71,17 +96,34 @@ void Init_gc_spec(void) {
rb_gc_register_address(&registered_tagged_value);
rb_gc_register_address(&registered_reference_value);
rb_gc_register_address(&registered_before_rb_gc_register_address);
rb_global_variable(&registered_before_rb_global_variable);
rb_global_variable(&registered_before_rb_global_variable_string);
rb_global_variable(&registered_before_rb_global_variable_bignum);
rb_global_variable(&registered_before_rb_global_variable_float);
registered_tagged_value = INT2NUM(10);
registered_reference_value = rb_str_new2("Globally registered data");
registered_before_rb_gc_register_address = rb_str_new_cstr("registered before rb_gc_register_address()");
registered_before_rb_global_variable = rb_str_new_cstr("registered before rb_global_variable()");
registered_before_rb_global_variable_string = rb_str_new_cstr("registered before rb_global_variable()");
registered_before_rb_global_variable_bignum = LL2NUM(INT64_MAX);
registered_before_rb_global_variable_float = DBL2NUM(3.14);
registered_after_rb_global_variable_string = rb_str_new_cstr("registered after rb_global_variable()");
rb_global_variable(&registered_after_rb_global_variable_string);
registered_after_rb_global_variable_bignum = LL2NUM(INT64_MAX);
rb_global_variable(&registered_after_rb_global_variable_bignum);
registered_after_rb_global_variable_float = DBL2NUM(6.28);
rb_global_variable(&registered_after_rb_global_variable_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);
rb_define_method(cls, "registered_before_rb_global_variable", get_registered_before_rb_global_variable, 0);
rb_define_method(cls, "registered_before_rb_global_variable_string", get_registered_before_rb_global_variable_string, 0);
rb_define_method(cls, "registered_before_rb_global_variable_bignum", get_registered_before_rb_global_variable_bignum, 0);
rb_define_method(cls, "registered_before_rb_global_variable_float", get_registered_before_rb_global_variable_float, 0);
rb_define_method(cls, "registered_after_rb_global_variable_string", get_registered_after_rb_global_variable_string, 0);
rb_define_method(cls, "registered_after_rb_global_variable_bignum", get_registered_after_rb_global_variable_bignum, 0);
rb_define_method(cls, "registered_after_rb_global_variable_float", get_registered_after_rb_global_variable_float, 0);
rb_define_method(cls, "rb_gc_register_address", gc_spec_rb_gc_register_address, 0);
rb_define_method(cls, "rb_gc_unregister_address", gc_spec_rb_gc_unregister_address, 0);
rb_define_method(cls, "rb_gc_enable", gc_spec_rb_gc_enable, 0);

View File

@ -27,9 +27,36 @@ describe "CApiGCSpecs" do
end
describe "rb_global_variable" do
it "keeps the value alive even if the value is assigned after rb_global_variable() is called" do
before :all do
GC.start
@f.registered_before_rb_global_variable.should == "registered before rb_global_variable()"
end
describe "keeps the value alive even if the value is assigned after rb_global_variable() is called" do
it "for a string" do
@f.registered_before_rb_global_variable_string.should == "registered before rb_global_variable()"
end
it "for a bignum" do
@f.registered_before_rb_global_variable_bignum.should == 2**63 - 1
end
it "for a Float" do
@f.registered_before_rb_global_variable_float.should == 3.14
end
end
describe "keeps the value alive when the value is assigned before rb_global_variable() is called" do
it "for a string" do
@f.registered_after_rb_global_variable_string.should == "registered after rb_global_variable()"
end
it "for a bignum" do
@f.registered_after_rb_global_variable_bignum.should == 2**63 - 1
end
it "for a Float" do
@f.registered_after_rb_global_variable_float.should == 6.28
end
end
end