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:
- 'core/binding/fixtures/irb.rb'
Lint/Loop:
Enabled: false
Style/Lambda:
Enabled: true
EnforcedStyle: literal

View file

@ -76,12 +76,6 @@ Lint/LiteralInInterpolation:
- 'language/undef_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
# Cop supports --auto-correct.
Lint/MultipleComparison:

View file

@ -90,7 +90,7 @@ describe "Array#flatten" do
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], 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)
end
end

View file

@ -47,4 +47,12 @@ describe "Errno::ENOTSUP" do
it "is defined" do
Errno.should have_constant(:ENOTSUP)
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

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"
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
File.extname("").should == ""
File.extname(".").should == ""

View file

@ -1,27 +1,5 @@
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
it "does not rescue exception raised in other#coerce" do
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
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
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?(:invalid_and_silly_method_name).should == false
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
it "returns an array of Symbol names of all constants defined in the module and all included modules" do
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
it "returns all constants including inherited when passed true" do
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
it "returns all constants including inherited when passed some object" do
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
it "doesn't returns inherited constants when passed false" do
ConstantSpecs::ContainerA.constants(false).sort.should == [
:CS_CONST10, :CS_CONST23, :CS_CONST5, :ChildA
:CS_CONST10, :CS_CONST10_LINE, :CS_CONST23, :CS_CONST5, :ChildA
]
end
it "doesn't returns inherited constants when passed nil" do
ConstantSpecs::ContainerA.constants(nil).sort.should == [
:CS_CONST10, :CS_CONST23, :CS_CONST5, :ChildA
:CS_CONST10, :CS_CONST10_LINE, :CS_CONST23, :CS_CONST5, :ChildA
]
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"
cmd = <<-EOC
f = File.open(#{@name.inspect}, "w+")
child_fd = f.fileno + 1
File.open(#{@child_fd_file.inspect}, "w") { |io| io.print child_fd }
Process.exec "#{ruby_cmd(map_fd_fixture)} \#{child_fd}", { child_fd => f }
File.open(#{__FILE__.inspect}, "r") do |io|
child_fd = io.fileno
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
ruby_exe(cmd, escape: true)

View file

@ -706,13 +706,15 @@ describe "Process.spawn" do
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
child_fd = find_unused_fd
args = ruby_cmd(fixture(__FILE__, "map_fd.rb"), args: [child_fd.to_s])
pid = Process.spawn(*args, { child_fd => @io })
Process.waitpid pid
@io.rewind
File.open(__FILE__, "r") do |f|
child_fd = f.fileno
args = ruby_cmd(fixture(__FILE__, "map_fd.rb"), args: [child_fd.to_s])
pid = Process.spawn(*args, { child_fd => @io })
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

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

View file

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

View file

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

View file

@ -1254,3 +1254,25 @@ describe "The predefined global constant" do
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
end
platform_is_not :android do
it 'raises Errno::EOPNOTSUPP' do
-> { @server.listen(1) }.should raise_error(Errno::EOPNOTSUPP)
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
it 'raises Errno::EOPNOTSUPP or Errno::EACCES' do
-> { @server.listen(1) }.should raise_error { |e|
[Errno::EOPNOTSUPP, Errno::EACCES].should.include?(e.class)
}
end
end

View file

@ -396,12 +396,20 @@ describe "C-API Kernel function" do
proc = -> x { x }
arg_error_proc = -> *_ { raise ArgumentError, '' }
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(run_error_proc, :no_exc, proc, :exc, ArgumentError, RuntimeError).should == :exc
-> {
@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

View file

@ -135,7 +135,7 @@ describe "CApiModule" do
end
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
it "returns a constant defined in a superclass" do
@ -176,8 +176,8 @@ describe "CApiModule" do
end
it "calls #const_missing if the constant is not defined in the class or ancestors" do
CApiModuleSpecs::M.should_receive(:const_missing).with(:Fixnum)
@m.rb_const_get_from(CApiModuleSpecs::M, :Fixnum)
CApiModuleSpecs::M.should_receive(:const_missing).with(:Integer)
@m.rb_const_get_from(CApiModuleSpecs::M, :Integer)
end
it "resolves autoload constants" do

View file

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

View file

@ -12,6 +12,13 @@ describe :enum_for, shared: true do
enum.map { |v| v }.should == [1,2].each { |v| v }
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
o = Object.new
def o.each

View file

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