1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
This commit is contained in:
Benoit Daloze 2020-11-13 13:17:24 +01:00
parent acbe7aa197
commit 6d05967468
27 changed files with 703 additions and 76 deletions

View file

@ -113,6 +113,9 @@ Lint/Debugger:
Exclude: Exclude:
- 'core/binding/fixtures/irb.rb' - 'core/binding/fixtures/irb.rb'
Lint/Loop:
Enabled: false
Style/Lambda: Style/Lambda:
Enabled: true Enabled: true
EnforcedStyle: literal EnforcedStyle: literal

View file

@ -76,12 +76,6 @@ Lint/LiteralInInterpolation:
- 'language/undef_spec.rb' - 'language/undef_spec.rb'
- 'library/net/ftp/connect_spec.rb' - 'library/net/ftp/connect_spec.rb'
# Offense count: 16
Lint/Loop:
Exclude:
- 'language/until_spec.rb'
- 'language/while_spec.rb'
# Offense count: 8 # Offense count: 8
# Cop supports --auto-correct. # Cop supports --auto-correct.
Lint/MultipleComparison: Lint/MultipleComparison:

View file

@ -90,7 +90,7 @@ describe "Array#flatten" do
ArraySpecs::MyArray[].flatten.should be_an_instance_of(Array) ArraySpecs::MyArray[].flatten.should be_an_instance_of(Array)
ArraySpecs::MyArray[1, 2, 3].flatten.should be_an_instance_of(Array) ArraySpecs::MyArray[1, 2, 3].flatten.should be_an_instance_of(Array)
ArraySpecs::MyArray[1, [2], 3].flatten.should be_an_instance_of(Array) ArraySpecs::MyArray[1, [2], 3].flatten.should be_an_instance_of(Array)
ArraySpecs::MyArray[1, [2, 3], 4].flatten.should == Array[1, 2, 3, 4] ArraySpecs::MyArray[1, [2, 3], 4].flatten.should == [1, 2, 3, 4]
[ArraySpecs::MyArray[1, 2, 3]].flatten.should be_an_instance_of(Array) [ArraySpecs::MyArray[1, 2, 3]].flatten.should be_an_instance_of(Array)
end end
end end

View file

@ -47,4 +47,12 @@ describe "Errno::ENOTSUP" do
it "is defined" do it "is defined" do
Errno.should have_constant(:ENOTSUP) Errno.should have_constant(:ENOTSUP)
end end
it "is the same class as Errno::EOPNOTSUPP if they represent the same errno value" do
if Errno::ENOTSUP::Errno == Errno::EOPNOTSUPP::Errno
Errno::ENOTSUP.should == Errno::EOPNOTSUPP
else
Errno::ENOTSUP.should_not == Errno::EOPNOTSUPP
end
end
end end

View file

@ -0,0 +1,17 @@
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.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.should == ""
$?.exitstatus.should == 8
end
end

View file

@ -0,0 +1,12 @@
module FiberSpecs
class NewFiberToRaise
def self.raise(*args)
fiber = Fiber.new { Fiber.yield }
fiber.resume
fiber.raise(*args)
end
end
class CustomError < StandardError; end
end

View file

@ -0,0 +1,76 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
require_relative '../../shared/kernel/raise'
ruby_version_is "2.7" do
describe "Fiber#raise" do
it_behaves_like :kernel_raise, :raise, FiberSpecs::NewFiberToRaise
end
describe "Fiber#raise" do
it 'raises RuntimeError by default' do
-> { FiberSpecs::NewFiberToRaise.raise }.should raise_error(RuntimeError)
end
it "raises FiberError if Fiber is not born" do
fiber = Fiber.new { true }
-> { fiber.raise }.should raise_error(FiberError, "cannot raise exception on unborn fiber")
end
it "raises FiberError if Fiber is dead" do
fiber = Fiber.new { true }
fiber.resume
-> { fiber.raise }.should raise_error(FiberError, /dead fiber called|attempt to resume a terminated fiber/)
end
it 'accepts error class' do
-> { FiberSpecs::NewFiberToRaise.raise FiberSpecs::CustomError }.should raise_error(FiberSpecs::CustomError)
end
it 'accepts error message' do
-> { FiberSpecs::NewFiberToRaise.raise "error message" }.should raise_error(RuntimeError, "error message")
end
it 'does not accept array of backtrace information only' do
-> { FiberSpecs::NewFiberToRaise.raise ['foo'] }.should raise_error(TypeError)
end
it 'does not accept integer' do
-> { FiberSpecs::NewFiberToRaise.raise 100 }.should raise_error(TypeError)
end
it 'accepts error class with error message' do
-> { FiberSpecs::NewFiberToRaise.raise FiberSpecs::CustomError, 'test error' }.should raise_error(FiberSpecs::CustomError, 'test error')
end
it 'accepts error class with with error message and backtrace information' do
-> {
FiberSpecs::NewFiberToRaise.raise FiberSpecs::CustomError, 'test error', ['foo', 'boo']
}.should raise_error(FiberSpecs::CustomError) { |e|
e.message.should == 'test error'
e.backtrace.should == ['foo', 'boo']
}
end
it 'does not accept only error message and backtrace information' do
-> { FiberSpecs::NewFiberToRaise.raise 'test error', ['foo', 'boo'] }.should raise_error(TypeError)
end
it "raises a FiberError if invoked from a different Thread" do
fiber = Fiber.new { Fiber.yield }
fiber.resume
Thread.new do
-> {
fiber.raise
}.should raise_error(FiberError, "fiber called across threads")
end.join
end
it "kills Fiber" do
fiber = Fiber.new { Fiber.yield :first; :second }
fiber.resume
-> { fiber.raise }.should raise_error
-> { fiber.resume }.should raise_error(FiberError, /dead fiber called|attempt to resume a terminated fiber/)
end
end
end

View file

@ -12,6 +12,16 @@ describe "File.extname" do
File.extname(".app.conf").should == ".conf" File.extname(".app.conf").should == ".conf"
end end
it "returns unfrozen strings" do
File.extname("foo.rb").frozen?.should == false
File.extname("/foo/bar.rb").frozen?.should == false
File.extname("/foo.rb/bar.c").frozen?.should == false
File.extname("bar").frozen?.should == false
File.extname(".bashrc").frozen?.should == false
File.extname("/foo.bar/baz").frozen?.should == false
File.extname(".app.conf").frozen?.should == false
end
it "returns the extension for edge cases" do it "returns the extension for edge cases" do
File.extname("").should == "" File.extname("").should == ""
File.extname(".").should == "" File.extname(".").should == ""

View file

@ -1,27 +1,5 @@
require_relative '../fixtures/classes' require_relative '../fixtures/classes'
describe :integer_comparison_coerce_rescue, shared: true do
it "rescues exception (StandardError and subclasses) raised in other#coerce and raises ArgumentError" do
b = mock("numeric with failed #coerce")
b.should_receive(:coerce).and_raise(IntegerSpecs::CoerceError)
# e.g. 1 > b
-> {
-> { 1.send(@method, b) }.should raise_error(ArgumentError, /comparison of Integer with MockObject failed/)
}.should complain(/Numerical comparison operators will no more rescue exceptions of #coerce/)
end
it "does not rescue Exception and StandardError siblings raised in other#coerce" do
[Exception, NoMemoryError].each do |exception|
b = mock("numeric with failed #coerce")
b.should_receive(:coerce).and_raise(exception)
# e.g. 1 > b
-> { 1.send(@method, b) }.should raise_error(exception)
end
end
end
describe :integer_comparison_coerce_not_rescue, shared: true do describe :integer_comparison_coerce_not_rescue, shared: true do
it "does not rescue exception raised in other#coerce" do it "does not rescue exception raised in other#coerce" do
b = mock("numeric with failed #coerce") b = mock("numeric with failed #coerce")

View file

@ -0,0 +1,57 @@
require_relative '../../spec_helper'
describe "IO#set_encoding_by_bom" do
before :each do
@name = tmp('io_set_encoding_by_bom.txt')
touch(@name)
@io = new_io(@name, 'rb')
end
after :each do
@io.close unless @io.closed?
rm_r @name
end
ruby_version_is "2.7" do
it "returns the result encoding if found BOM UTF-8 sequence" do
File.binwrite(@name, "\u{FEFF}abc")
@io.set_encoding_by_bom.should == Encoding::UTF_8
@io.external_encoding.should == Encoding::UTF_8
end
it "returns the result encoding if found BOM UTF_16LE sequence" do
File.binwrite(@name, "\xFF\xFEabc")
@io.set_encoding_by_bom.should == Encoding::UTF_16LE
@io.external_encoding.should == Encoding::UTF_16LE
end
it "returns the result encoding if found BOM UTF_16BE sequence" do
File.binwrite(@name, "\xFE\xFFabc")
@io.set_encoding_by_bom.should == Encoding::UTF_16BE
@io.external_encoding.should == Encoding::UTF_16BE
end
it "returns nil if found BOM sequence not provided" do
File.write(@name, "abc")
@io.set_encoding_by_bom.should == nil
end
it 'returns exception if io not in binary mode' do
not_binary_io = new_io(@name, 'r')
-> { not_binary_io.set_encoding_by_bom }.should raise_error(ArgumentError, 'ASCII incompatible encoding needs binmode')
ensure
not_binary_io.close
end
it 'returns exception if encoding already set' do
@io.set_encoding("utf-8")
-> { @io.set_encoding_by_bom }.should raise_error(ArgumentError, 'encoding is set to UTF-8 already')
end
end
end

View file

@ -25,7 +25,7 @@ describe "Kernel#respond_to?" do
end end
it "throws a type error if argument can't be coerced into a Symbol" do it "throws a type error if argument can't be coerced into a Symbol" do
-> { @a.respond_to?(Object.new) }.should raise_error(TypeError) -> { @a.respond_to?(Object.new) }.should raise_error(TypeError, /is not a symbol nor a string/)
end end
it "returns false if obj responds to the given protected method" do it "returns false if obj responds to the given protected method" do
@ -69,5 +69,4 @@ describe "Kernel#respond_to?" do
KernelSpecs::Foo.new.respond_to?(:bar).should == true KernelSpecs::Foo.new.respond_to?(:bar).should == true
KernelSpecs::Foo.new.respond_to?(:invalid_and_silly_method_name).should == false KernelSpecs::Foo.new.respond_to?(:invalid_and_silly_method_name).should == false
end end
end end

View file

@ -0,0 +1,220 @@
require_relative '../../spec_helper'
require_relative '../../fixtures/constants'
describe "Module#const_source_location" do
before do
@constants_fixture_path = File.expand_path('../../fixtures/constants.rb', __dir__)
end
ruby_version_is "2.7" do
describe "with dynamically assigned constants" do
it "searches a path in the immediate class or module first" do
ConstantSpecs::ClassA::CSL_CONST301 = :const301_1
ConstantSpecs::ClassA.const_source_location(:CSL_CONST301).should == [__FILE__, __LINE__ - 1]
ConstantSpecs::ModuleA::CSL_CONST301 = :const301_2
ConstantSpecs::ModuleA.const_source_location(:CSL_CONST301).should == [__FILE__, __LINE__ - 1]
ConstantSpecs::ParentA::CSL_CONST301 = :const301_3
ConstantSpecs::ParentA.const_source_location(:CSL_CONST301).should == [__FILE__, __LINE__ - 1]
ConstantSpecs::ContainerA::ChildA::CSL_CONST301 = :const301_5
ConstantSpecs::ContainerA::ChildA.const_source_location(:CSL_CONST301).should == [__FILE__, __LINE__ - 1]
end
it "searches a path in a module included in the immediate class before the superclass" do
ConstantSpecs::ParentB::CSL_CONST302 = :const302_1
ConstantSpecs::ModuleF::CSL_CONST302 = :const302_2
ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST302).should == [__FILE__, __LINE__ - 1]
end
it "searches a path in the superclass before a module included in the superclass" do
ConstantSpecs::ModuleE::CSL_CONST303 = :const303_1
ConstantSpecs::ParentB::CSL_CONST303 = :const303_2
ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST303).should == [__FILE__, __LINE__ - 1]
end
it "searches a path in a module included in the superclass" do
ConstantSpecs::ModuleA::CSL_CONST304 = :const304_1
ConstantSpecs::ModuleE::CSL_CONST304 = :const304_2
ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST304).should == [__FILE__, __LINE__ - 1]
end
it "searches a path in the superclass chain" do
ConstantSpecs::ModuleA::CSL_CONST305 = :const305
ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST305).should == [__FILE__, __LINE__ - 1]
end
it "returns path to a toplevel constant when the receiver is a Class" do
Object::CSL_CONST306 = :const306
ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST306).should == [__FILE__, __LINE__ - 1]
end
it "returns path to a toplevel constant when the receiver is a Module" do
Object::CSL_CONST308 = :const308
ConstantSpecs.const_source_location(:CSL_CONST308).should == [__FILE__, __LINE__ - 1]
ConstantSpecs::ModuleA.const_source_location(:CSL_CONST308).should == [__FILE__, __LINE__ - 2]
end
it "returns path to the updated value of a constant" do
ConstantSpecs::ClassB::CSL_CONST309 = :const309_1
ConstantSpecs::ClassB.const_source_location(:CSL_CONST309).should == [__FILE__, __LINE__ - 1]
-> {
ConstantSpecs::ClassB::CSL_CONST309 = :const309_2
}.should complain(/already initialized constant/)
ConstantSpecs::ClassB.const_source_location(:CSL_CONST309).should == [__FILE__, __LINE__ - 2]
end
end
describe "with statically assigned constants" do
it "searches location path the immediate class or module first" do
ConstantSpecs::ClassA.const_source_location(:CS_CONST10).should == [@constants_fixture_path, ConstantSpecs::ClassA::CS_CONST10_LINE]
ConstantSpecs::ModuleA.const_source_location(:CS_CONST10).should == [@constants_fixture_path, ConstantSpecs::ModuleA::CS_CONST10_LINE]
ConstantSpecs::ParentA.const_source_location(:CS_CONST10).should == [@constants_fixture_path, ConstantSpecs::ParentA::CS_CONST10_LINE]
ConstantSpecs::ContainerA.const_source_location(:CS_CONST10).should == [@constants_fixture_path, ConstantSpecs::ContainerA::CS_CONST10_LINE]
ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST10).should == [@constants_fixture_path, ConstantSpecs::ContainerA::ChildA::CS_CONST10_LINE]
end
it "searches location path a module included in the immediate class before the superclass" do
ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST15).should == [@constants_fixture_path, ConstantSpecs::ModuleC::CS_CONST15_LINE]
end
it "searches location path the superclass before a module included in the superclass" do
ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST11).should == [@constants_fixture_path, ConstantSpecs::ParentA::CS_CONST11_LINE]
end
it "searches location path a module included in the superclass" do
ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST12).should == [@constants_fixture_path, ConstantSpecs::ModuleB::CS_CONST12_LINE]
end
it "searches location path the superclass chain" do
ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST13).should == [@constants_fixture_path, ConstantSpecs::ModuleA::CS_CONST13_LINE]
end
it "returns location path a toplevel constant when the receiver is a Class" do
ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST1).should == [@constants_fixture_path, CS_CONST1_LINE]
end
it "returns location path a toplevel constant when the receiver is a Module" do
ConstantSpecs.const_source_location(:CS_CONST1).should == [@constants_fixture_path, CS_CONST1_LINE]
ConstantSpecs::ModuleA.const_source_location(:CS_CONST1).should == [@constants_fixture_path, CS_CONST1_LINE]
end
end
it "return empty path if constant defined in C code" do
Object.const_source_location(:String).should == []
end
it "accepts a String or Symbol name" do
Object.const_source_location(:CS_CONST1).should == [@constants_fixture_path, CS_CONST1_LINE]
Object.const_source_location("CS_CONST1").should == [@constants_fixture_path, CS_CONST1_LINE]
end
it "returns nil if no constant is defined in the search path" do
ConstantSpecs.const_source_location(:CS_CONSTX).should == nil
end
it "raises a NameError if the name does not start with a capital letter" do
-> { ConstantSpecs.const_source_location "name" }.should raise_error(NameError)
end
it "raises a NameError if the name starts with a non-alphabetic character" do
-> { ConstantSpecs.const_source_location "__CONSTX__" }.should raise_error(NameError)
-> { ConstantSpecs.const_source_location "@CS_CONST1" }.should raise_error(NameError)
-> { ConstantSpecs.const_source_location "!CS_CONST1" }.should raise_error(NameError)
end
it "raises a NameError if the name contains non-alphabetic characters except '_'" do
Object.const_source_location("CS_CONST1").should == [@constants_fixture_path, CS_CONST1_LINE]
-> { ConstantSpecs.const_source_location "CS_CONST1=" }.should raise_error(NameError)
-> { ConstantSpecs.const_source_location "CS_CONST1?" }.should raise_error(NameError)
end
it "calls #to_str to convert the given name to a String" do
name = mock("ClassA")
name.should_receive(:to_str).and_return("ClassA")
ConstantSpecs.const_source_location(name).should == [@constants_fixture_path, ConstantSpecs::ClassA::CS_CLASS_A_LINE]
end
it "raises a TypeError if conversion to a String by calling #to_str fails" do
name = mock('123')
-> { ConstantSpecs.const_source_location(name) }.should raise_error(TypeError)
name.should_receive(:to_str).and_return(123)
-> { ConstantSpecs.const_source_location(name) }.should raise_error(TypeError)
end
it "does not search the singleton class of a Class or Module" do
ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST14).should == nil
ConstantSpecs.const_source_location(:CS_CONST14).should == nil
end
it "does not search the containing scope" do
ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST20).should == [@constants_fixture_path, ConstantSpecs::ParentA::CS_CONST20_LINE]
ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST5) == nil
end
it "returns nil if the constant is defined in the receiver's superclass and the inherit flag is false" do
ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST4, false).should == nil
end
it "searches into the receiver superclasses if the inherit flag is true" do
ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST4, true).should == [@constants_fixture_path, ConstantSpecs::ParentA::CS_CONST4_LINE]
end
it "returns nil when the receiver is a Module, the constant is defined at toplevel and the inherit flag is false" do
ConstantSpecs::ModuleA.const_source_location(:CS_CONST1, false).should == nil
end
it "returns nil when the receiver is a Class, the constant is defined at toplevel and the inherit flag is false" do
ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST1, false).should == nil
end
it "accepts a toplevel scope qualifier" do
ConstantSpecs.const_source_location("::CS_CONST1").should == [@constants_fixture_path, CS_CONST1_LINE]
end
it "accepts a scoped constant name" do
ConstantSpecs.const_source_location("ClassA::CS_CONST10").should == [@constants_fixture_path, ConstantSpecs::ClassA::CS_CONST10_LINE]
end
it "raises a NameError if the name includes two successive scope separators" do
-> { ConstantSpecs.const_source_location("ClassA::::CS_CONST10") }.should raise_error(NameError)
end
it "raises a NameError if only '::' is passed" do
-> { ConstantSpecs.const_source_location("::") }.should raise_error(NameError)
end
it "raises a NameError if a Symbol has a toplevel scope qualifier" do
-> { ConstantSpecs.const_source_location(:'::CS_CONST1') }.should raise_error(NameError)
end
it "raises a NameError if a Symbol is a scoped constant name" do
-> { ConstantSpecs.const_source_location(:'ClassA::CS_CONST10') }.should raise_error(NameError)
end
it "does search private constants path" do
ConstantSpecs.const_source_location(:CS_PRIVATE).should == [@constants_fixture_path, ConstantSpecs::CS_PRIVATE_LINE]
end
context 'autoload' do
before :all do
ConstantSpecs.autoload :CSL_CONST1, "#{__dir__}/notexisting.rb"
@line = __LINE__ - 1
end
it 'returns the autoload location while not resolved' do
ConstantSpecs.const_source_location('CSL_CONST1').should == [__FILE__, @line]
end
it 'returns where the constant was resolved when resolved' do
file = fixture(__FILE__, 'autoload_location.rb')
ConstantSpecs.autoload :CONST_LOCATION, file
line = ConstantSpecs::CONST_LOCATION
ConstantSpecs.const_source_location('CONST_LOCATION').should == [file, line]
end
end
end
end

View file

@ -43,31 +43,31 @@ end
describe "Module#constants" do describe "Module#constants" do
it "returns an array of Symbol names of all constants defined in the module and all included modules" do it "returns an array of Symbol names of all constants defined in the module and all included modules" do
ConstantSpecs::ContainerA.constants.sort.should == [ ConstantSpecs::ContainerA.constants.sort.should == [
:CS_CONST10, :CS_CONST23, :CS_CONST24, :CS_CONST5, :ChildA :CS_CONST10, :CS_CONST10_LINE, :CS_CONST23, :CS_CONST24, :CS_CONST5, :ChildA
] ]
end end
it "returns all constants including inherited when passed true" do it "returns all constants including inherited when passed true" do
ConstantSpecs::ContainerA.constants(true).sort.should == [ ConstantSpecs::ContainerA.constants(true).sort.should == [
:CS_CONST10, :CS_CONST23, :CS_CONST24, :CS_CONST5, :ChildA :CS_CONST10, :CS_CONST10_LINE, :CS_CONST23, :CS_CONST24, :CS_CONST5, :ChildA
] ]
end end
it "returns all constants including inherited when passed some object" do it "returns all constants including inherited when passed some object" do
ConstantSpecs::ContainerA.constants(Object.new).sort.should == [ ConstantSpecs::ContainerA.constants(Object.new).sort.should == [
:CS_CONST10, :CS_CONST23, :CS_CONST24, :CS_CONST5, :ChildA :CS_CONST10, :CS_CONST10_LINE, :CS_CONST23, :CS_CONST24, :CS_CONST5, :ChildA
] ]
end end
it "doesn't returns inherited constants when passed false" do it "doesn't returns inherited constants when passed false" do
ConstantSpecs::ContainerA.constants(false).sort.should == [ ConstantSpecs::ContainerA.constants(false).sort.should == [
:CS_CONST10, :CS_CONST23, :CS_CONST5, :ChildA :CS_CONST10, :CS_CONST10_LINE, :CS_CONST23, :CS_CONST5, :ChildA
] ]
end end
it "doesn't returns inherited constants when passed nil" do it "doesn't returns inherited constants when passed nil" do
ConstantSpecs::ContainerA.constants(nil).sort.should == [ ConstantSpecs::ContainerA.constants(nil).sort.should == [
:CS_CONST10, :CS_CONST23, :CS_CONST5, :ChildA :CS_CONST10, :CS_CONST10_LINE, :CS_CONST23, :CS_CONST5, :ChildA
] ]
end end

View file

@ -0,0 +1,3 @@
module ConstantSpecs
CONST_LOCATION = __LINE__
end

View file

@ -193,9 +193,11 @@ describe "Process.exec" do
map_fd_fixture = fixture __FILE__, "map_fd.rb" map_fd_fixture = fixture __FILE__, "map_fd.rb"
cmd = <<-EOC cmd = <<-EOC
f = File.open(#{@name.inspect}, "w+") f = File.open(#{@name.inspect}, "w+")
child_fd = f.fileno + 1 File.open(#{__FILE__.inspect}, "r") do |io|
File.open(#{@child_fd_file.inspect}, "w") { |io| io.print child_fd } child_fd = io.fileno
Process.exec "#{ruby_cmd(map_fd_fixture)} \#{child_fd}", { child_fd => f } File.open(#{@child_fd_file.inspect}, "w") { |io| io.print child_fd }
Process.exec "#{ruby_cmd(map_fd_fixture)} \#{child_fd}", { child_fd => f }
end
EOC EOC
ruby_exe(cmd, escape: true) ruby_exe(cmd, escape: true)

View file

@ -706,13 +706,15 @@ describe "Process.spawn" do
end end
it "maps the key to a file descriptor in the child that inherits the file descriptor from the parent specified by the value" do it "maps the key to a file descriptor in the child that inherits the file descriptor from the parent specified by the value" do
child_fd = find_unused_fd File.open(__FILE__, "r") do |f|
args = ruby_cmd(fixture(__FILE__, "map_fd.rb"), args: [child_fd.to_s]) child_fd = f.fileno
pid = Process.spawn(*args, { child_fd => @io }) args = ruby_cmd(fixture(__FILE__, "map_fd.rb"), args: [child_fd.to_s])
Process.waitpid pid pid = Process.spawn(*args, { child_fd => @io })
@io.rewind Process.waitpid pid
@io.rewind
@io.read.should == "writing to fd: #{child_fd}" @io.read.should == "writing to fd: #{child_fd}"
end
end end
end end
end end

View file

@ -0,0 +1,170 @@
require_relative '../../spec_helper'
# These specs use Range.new instead of the literal notation so they parse fine on Ruby < 2.6
describe 'Range#minmax' do
before(:each) do
@x = mock('x')
@y = mock('y')
@x.should_receive(:<=>).with(@y).any_number_of_times.and_return(-1) # x < y
@x.should_receive(:<=>).with(@x).any_number_of_times.and_return(0) # x == x
@y.should_receive(:<=>).with(@x).any_number_of_times.and_return(1) # y > x
@y.should_receive(:<=>).with(@y).any_number_of_times.and_return(0) # y == y
end
describe 'on an inclusive range' do
ruby_version_is '2.6'...'2.7' do
it 'should try to iterate endlessly on an endless range' do
@x.should_receive(:succ).once.and_return(@y)
range = Range.new(@x, nil)
-> { range.minmax }.should raise_error(NoMethodError, /^undefined method `succ' for/)
end
end
ruby_version_is '2.7' do
it 'should raise RangeError on an endless range without iterating the range' do
@x.should_not_receive(:succ)
range = Range.new(@x, nil)
-> { range.minmax }.should raise_error(RangeError, 'cannot get the maximum of endless range')
end
it 'raises RangeError or ArgumentError on a beginless range' do
range = Range.new(nil, @x)
-> { range.minmax }.should raise_error(StandardError) { |e|
if RangeError === e
# error from #min
-> { raise e }.should raise_error(RangeError, 'cannot get the minimum of beginless range')
else
# error from #max
-> { raise e }.should raise_error(ArgumentError, 'comparison of NilClass with MockObject failed')
end
}
end
end
it 'should return begining of range if beginning and end are equal without iterating the range' do
@x.should_not_receive(:succ)
(@x..@x).minmax.should == [@x, @x]
end
it 'should return nil pair if beginning is greater than end without iterating the range' do
@y.should_not_receive(:succ)
(@y..@x).minmax.should == [nil, nil]
end
ruby_version_is ''...'2.7' do
it 'should return the minimum and maximum values for a non-numeric range by iterating the range' do
@x.should_receive(:succ).once.and_return(@y)
(@x..@y).minmax.should == [@x, @y]
end
end
ruby_version_is '2.7' do
it 'should return the minimum and maximum values for a non-numeric range without iterating the range' do
@x.should_not_receive(:succ)
(@x..@y).minmax.should == [@x, @y]
end
end
it 'should return the minimum and maximum values for a numeric range' do
(1..3).minmax.should == [1, 3]
end
ruby_version_is '2.7' do
it 'should return the minimum and maximum values for a numeric range without iterating the range' do
# We cannot set expectations on integers,
# so we "prevent" iteration by picking a value that would iterate until the spec times out.
range_end = Float::INFINITY
(1..range_end).minmax.should == [1, range_end]
end
end
it 'should return the minimum and maximum values according to the provided block by iterating the range' do
@x.should_receive(:succ).once.and_return(@y)
(@x..@y).minmax { |x, y| - (x <=> y) }.should == [@y, @x]
end
end
describe 'on an exclusive range' do
ruby_version_is '2.6'...'2.7' do
# Endless ranges introduced in 2.6
it 'should try to iterate endlessly on an endless range' do
@x.should_receive(:succ).once.and_return(@y)
range = Range.new(@x, nil, true)
-> { range.minmax }.should raise_error(NoMethodError, /^undefined method `succ' for/)
end
end
ruby_version_is '2.7' do
it 'should raise RangeError on an endless range' do
@x.should_not_receive(:succ)
range = Range.new(@x, nil, true)
-> { range.minmax }.should raise_error(RangeError, 'cannot get the maximum of endless range')
end
it 'should raise RangeError on a beginless range' do
range = Range.new(nil, @x, true)
-> { range.minmax }.should raise_error(RangeError,
/cannot get the maximum of beginless range with custom comparison method|cannot get the minimum of beginless range/)
end
end
ruby_bug "#17014", "2.7.0"..."2.8" do
it 'should return nil pair if beginning and end are equal without iterating the range' do
@x.should_not_receive(:succ)
(@x...@x).minmax.should == [nil, nil]
end
it 'should return nil pair if beginning is greater than end without iterating the range' do
@y.should_not_receive(:succ)
(@y...@x).minmax.should == [nil, nil]
end
it 'should return the minimum and maximum values for a non-numeric range by iterating the range' do
@x.should_receive(:succ).once.and_return(@y)
(@x...@y).minmax.should == [@x, @x]
end
end
it 'should return the minimum and maximum values for a numeric range' do
(1...3).minmax.should == [1, 2]
end
ruby_version_is '2.7' do
it 'should return the minimum and maximum values for a numeric range without iterating the range' do
# We cannot set expectations on integers,
# so we "prevent" iteration by picking a value that would iterate until the spec times out.
range_end = bignum_value
(1...range_end).minmax.should == [1, range_end - 1]
end
it 'raises TypeError if the end value is not an integer' do
range = (0...Float::INFINITY)
-> { range.minmax }.should raise_error(TypeError, 'cannot exclude non Integer end value')
end
end
it 'should return the minimum and maximum values according to the provided block by iterating the range' do
@x.should_receive(:succ).once.and_return(@y)
(@x...@y).minmax { |x, y| - (x <=> y) }.should == [@x, @x]
end
end
end

View file

@ -55,6 +55,10 @@ describe "String#chomp" do
$/ = "cdef" $/ = "cdef"
"abcdef".chomp.should == "ab" "abcdef".chomp.should == "ab"
end end
it "removes one trailing newline for string with invalid encoding" do
"\xa0\xa1\n".chomp.should == "\xa0\xa1"
end
end end
describe "when passed nil" do describe "when passed nil" do
@ -108,6 +112,10 @@ describe "String#chomp" do
it "returns an empty String when self is empty" do it "returns an empty String when self is empty" do
"".chomp("").should == "" "".chomp("").should == ""
end end
it "removes one trailing newline for string with invalid encoding" do
"\xa0\xa1\n".chomp("").should == "\xa0\xa1"
end
end end
describe "when passed '\\n'" do describe "when passed '\\n'" do

View file

@ -43,11 +43,11 @@ describe "Thread.list" do
end end
end end
while spawner.alive? begin
Thread.list.each { |th| Thread.list.each { |th|
th.should be_kind_of(Thread) th.should be_kind_of(Thread)
} }
end end while spawner.alive?
threads = spawner.value threads = spawner.value
threads.each(&:join) threads.each(&:join)

View file

@ -1,7 +1,7 @@
# Contains all static code examples of all constants behavior in language and # Contains all static code examples of all constants behavior in language and
# library specs. The specs include language/constants_spec.rb and the specs # library specs. The specs include language/constants_spec.rb and the specs
# for Module#const_defined?, Module#const_get, Module#const_set, # for Module#const_defined?, Module#const_get, Module#const_set, Module#remove_const,
# Module#remove_const, Module#const_missing and Module#constants. # Module#const_source_location, Module#const_missing and Module#constants.
# #
# Rather than defining a class structure for each example, a canonical set of # Rather than defining a class structure for each example, a canonical set of
# classes is used along with numerous constants, in most cases, a unique # classes is used along with numerous constants, in most cases, a unique
@ -28,14 +28,17 @@
# for completeness. No other constant of this name should be defined in the # for completeness. No other constant of this name should be defined in the
# specs. # specs.
CS_CONST1 = :const1 # only defined here CS_CONST1 = :const1 # only defined here
CS_CONST1_LINE = __LINE__ - 1
module ConstantSpecs module ConstantSpecs
# Included at toplevel # Included at toplevel
module ModuleA module ModuleA
CS_CONST10 = :const10_1 CS_CONST10 = :const10_1
CS_CONST10_LINE = __LINE__ - 1
CS_CONST12 = :const12_2 CS_CONST12 = :const12_2
CS_CONST13 = :const13 CS_CONST13 = :const13
CS_CONST13_LINE = __LINE__ - 1
CS_CONST21 = :const21_2 CS_CONST21 = :const21_2
end end
@ -44,12 +47,14 @@ module ConstantSpecs
CS_CONST10 = :const10_9 CS_CONST10 = :const10_9
CS_CONST11 = :const11_2 CS_CONST11 = :const11_2
CS_CONST12 = :const12_1 CS_CONST12 = :const12_1
CS_CONST12_LINE = __LINE__ - 1
end end
# Included in ChildA # Included in ChildA
module ModuleC module ModuleC
CS_CONST10 = :const10_4 CS_CONST10 = :const10_4
CS_CONST15 = :const15_1 CS_CONST15 = :const15_1
CS_CONST15_LINE = __LINE__ - 1
end end
# Included in ChildA metaclass # Included in ChildA metaclass
@ -75,7 +80,9 @@ module ConstantSpecs
# are run. # are run.
class ClassA class ClassA
CS_CLASS_A_LINE = __LINE__ - 1
CS_CONST10 = :const10_10 CS_CONST10 = :const10_10
CS_CONST10_LINE = __LINE__ - 1
CS_CONST16 = :const16 CS_CONST16 = :const16
CS_CONST17 = :const17_2 CS_CONST17 = :const17_2
CS_CONST22 = :const22_1 CS_CONST22 = :const22_1
@ -97,10 +104,14 @@ module ConstantSpecs
include ModuleB include ModuleB
CS_CONST4 = :const4 CS_CONST4 = :const4
CS_CONST4_LINE = __LINE__ - 1
CS_CONST10 = :const10_5 CS_CONST10 = :const10_5
CS_CONST10_LINE = __LINE__ - 1
CS_CONST11 = :const11_1 CS_CONST11 = :const11_1
CS_CONST11_LINE = __LINE__ - 1
CS_CONST15 = :const15_2 CS_CONST15 = :const15_2
CS_CONST20 = :const20_2 CS_CONST20 = :const20_2
CS_CONST20_LINE = __LINE__ - 1
CS_CONST21 = :const21_1 CS_CONST21 = :const21_1
CS_CONST22 = :const22_2 CS_CONST22 = :const22_2
@ -118,6 +129,7 @@ module ConstantSpecs
CS_CONST5 = :const5 CS_CONST5 = :const5
CS_CONST10 = :const10_2 CS_CONST10 = :const10_2
CS_CONST10_LINE = __LINE__ - 1
CS_CONST23 = :const23 CS_CONST23 = :const23
class ChildA < ParentA class ChildA < ParentA
@ -135,6 +147,7 @@ module ConstantSpecs
CS_CONST6 = :const6 CS_CONST6 = :const6
CS_CONST10 = :const10_3 CS_CONST10 = :const10_3
CS_CONST10_LINE = __LINE__ - 1
CS_CONST19 = :const19_2 CS_CONST19 = :const19_2
def self.const10; CS_CONST10; end def self.const10; CS_CONST10; end
@ -282,6 +295,7 @@ module ConstantSpecs
end end
CS_PRIVATE = :cs_private CS_PRIVATE = :cs_private
CS_PRIVATE_LINE = __LINE__ - 1
private_constant :CS_PRIVATE private_constant :CS_PRIVATE
end end

View file

@ -1254,3 +1254,25 @@ describe "The predefined global constant" do
end end
end end
end end
ruby_version_is "2.7" do
describe "$LOAD_PATH.resolve_feature_path" do
it "returns what will be loaded without actual loading, .rb file" do
extension, path = $LOAD_PATH.resolve_feature_path('set')
extension.should == :rb
path.should.end_with?('/set.rb')
end
it "returns what will be loaded without actual loading, .so file" do
require 'rbconfig'
extension, path = $LOAD_PATH.resolve_feature_path('etc')
extension.should == :so
path.should.end_with?("/etc.#{RbConfig::CONFIG['DLEXT']}")
end
it "raises LoadError if feature cannot be found" do
-> { $LOAD_PATH.resolve_feature_path('noop') }.should raise_error(LoadError)
end
end
end

View file

@ -34,16 +34,10 @@ describe 'Socket#listen' do
@server.close @server.close
end end
platform_is_not :android do it 'raises Errno::EOPNOTSUPP or Errno::EACCES' do
it 'raises Errno::EOPNOTSUPP' do -> { @server.listen(1) }.should raise_error { |e|
-> { @server.listen(1) }.should raise_error(Errno::EOPNOTSUPP) [Errno::EOPNOTSUPP, Errno::EACCES].should.include?(e.class)
end }
end
platform_is :android do
it 'raises Errno::EOPNOTSUPP or Errno::EACCES' do
-> { @server.listen(1) }.should raise_error(-> exc { Errno::EACCES === exc || Errno::EOPNOTSUPP === exc })
end
end end
end end

View file

@ -396,12 +396,20 @@ describe "C-API Kernel function" do
proc = -> x { x } proc = -> x { x }
arg_error_proc = -> *_ { raise ArgumentError, '' } arg_error_proc = -> *_ { raise ArgumentError, '' }
run_error_proc = -> *_ { raise RuntimeError, '' } run_error_proc = -> *_ { raise RuntimeError, '' }
type_error_proc = -> *_ { raise TypeError, '' } type_error_proc = -> *_ { raise Exception, 'custom error' }
@s.rb_rescue2(arg_error_proc, :no_exc, proc, :exc, ArgumentError, RuntimeError).should == :exc @s.rb_rescue2(arg_error_proc, :no_exc, proc, :exc, ArgumentError, RuntimeError).should == :exc
@s.rb_rescue2(run_error_proc, :no_exc, proc, :exc, ArgumentError, RuntimeError).should == :exc @s.rb_rescue2(run_error_proc, :no_exc, proc, :exc, ArgumentError, RuntimeError).should == :exc
-> { -> {
@s.rb_rescue2(type_error_proc, :no_exc, proc, :exc, ArgumentError, RuntimeError) @s.rb_rescue2(type_error_proc, :no_exc, proc, :exc, ArgumentError, RuntimeError)
}.should raise_error(TypeError) }.should raise_error(Exception, 'custom error')
end
ruby_bug "#17305", ""..."2.7" do
it "raises TypeError if one of the passed exceptions is not a Module" do
-> {
@s.rb_rescue2(-> *_ { raise RuntimeError, "foo" }, :no_exc, -> x { x }, :exc, Object.new, 42)
}.should raise_error(TypeError, /class or module required/)
end
end end
end end

View file

@ -135,7 +135,7 @@ describe "CApiModule" do
end end
it "returns a constant defined at toplevel" do it "returns a constant defined at toplevel" do
@m.rb_const_get(CApiModuleSpecs::A, :Fixnum).should == Fixnum @m.rb_const_get(CApiModuleSpecs::A, :Integer).should == Integer
end end
it "returns a constant defined in a superclass" do it "returns a constant defined in a superclass" do
@ -176,8 +176,8 @@ describe "CApiModule" do
end end
it "calls #const_missing if the constant is not defined in the class or ancestors" do it "calls #const_missing if the constant is not defined in the class or ancestors" do
CApiModuleSpecs::M.should_receive(:const_missing).with(:Fixnum) CApiModuleSpecs::M.should_receive(:const_missing).with(:Integer)
@m.rb_const_get_from(CApiModuleSpecs::M, :Fixnum) @m.rb_const_get_from(CApiModuleSpecs::M, :Integer)
end end
it "resolves autoload constants" do it "resolves autoload constants" do

View file

@ -62,7 +62,7 @@ describe "C-API Struct function" do
end end
describe "C-API Struct function" do describe "C-API Struct function" do
before :each do before :all do
@s = CApiStructSpecs.new @s = CApiStructSpecs.new
@struct = @s.rb_struct_define_under(CApiStructSpecs, "CAPIStructUnder", "a", "b", "c") @struct = @s.rb_struct_define_under(CApiStructSpecs, "CAPIStructUnder", "a", "b", "c")
end end

View file

@ -12,6 +12,13 @@ describe :enum_for, shared: true do
enum.map { |v| v }.should == [1,2].each { |v| v } enum.map { |v| v }.should == [1,2].each { |v| v }
end end
it "sets regexp matches in the caller" do
"wawa".send(@method, :scan, /./).map {|o| $& }.should == ["w", "a", "w", "a"]
a = []
"wawa".send(@method, :scan, /./).each {|o| a << $& }
a.should == ["w", "a", "w", "a"]
end
it "exposes multi-arg yields as an array" do it "exposes multi-arg yields as an array" do
o = Object.new o = Object.new
def o.each def o.each

View file

@ -50,20 +50,43 @@ describe :kernel_raise, shared: true do
end end
it "re-raises a previously rescued exception without overwriting the backtrace" do it "re-raises a previously rescued exception without overwriting the backtrace" do
begin # This spec is written using #backtrace and matching the line number
initial_raise_line = __LINE__; @object.raise 'raised' # from the string, as backtrace_locations is a more advanced
rescue => raised # method that is not always supported by implementations.
begin #
raise_again_line = __LINE__; @object.raise raised initial_raise_line = nil
rescue => raised_again raise_again_line = nil
# This spec is written using #backtrace and matching the line number raised_again = nil
# from the string, as backtrace_locations is a more advanced
# method that is not always supported by implementations.
raised_again.backtrace.first.should include("#{__FILE__}:#{initial_raise_line}:") if defined?(FiberSpecs::NewFiberToRaise) and @object == FiberSpecs::NewFiberToRaise
raised_again.backtrace.first.should_not include("#{__FILE__}:#{raise_again_line}:") fiber = Fiber.new do
begin
initial_raise_line = __LINE__; Fiber.yield
rescue => raised
begin
raise_again_line = __LINE__; Fiber.yield raised
rescue => raised_again
raised_again
end
end
end
fiber.resume
raised = fiber.raise 'raised'
raised_again = fiber.raise raised
else
begin
initial_raise_line = __LINE__; @object.raise 'raised'
rescue => raised
begin
raise_again_line = __LINE__; @object.raise raised
rescue => raised_again
raised_again
end
end end
end end
raised_again.backtrace.first.should include("#{__FILE__}:#{initial_raise_line}:")
raised_again.backtrace.first.should_not include("#{__FILE__}:#{raise_again_line}:")
end end
it "allows Exception, message, and backtrace parameters" do it "allows Exception, message, and backtrace parameters" do