Update to ruby/spec@fd6eddd
This commit is contained in:
parent
44736a6b7a
commit
95d9fe9538
@ -95,6 +95,7 @@ Lint/UnreachableCode:
|
|||||||
- 'core/kernel/raise_spec.rb'
|
- 'core/kernel/raise_spec.rb'
|
||||||
- 'core/kernel/throw_spec.rb'
|
- 'core/kernel/throw_spec.rb'
|
||||||
- 'language/break_spec.rb'
|
- 'language/break_spec.rb'
|
||||||
|
- 'language/optional_assignments_spec.rb'
|
||||||
- 'language/fixtures/break.rb'
|
- 'language/fixtures/break.rb'
|
||||||
- 'language/fixtures/break_lambda_toplevel.rb'
|
- 'language/fixtures/break_lambda_toplevel.rb'
|
||||||
- 'language/fixtures/break_lambda_toplevel_block.rb'
|
- 'language/fixtures/break_lambda_toplevel_block.rb'
|
||||||
|
@ -35,6 +35,11 @@ describe "Enumerable#chunk" do
|
|||||||
result.should == [[:_alone, [1]], [false, [2, 3, 2]], [:_alone, [1]]]
|
result.should == [[:_alone, [1]], [false, [2, 3, 2]], [:_alone, [1]]]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "yields Arrays as a single argument to a rest argument" do
|
||||||
|
e = EnumerableSpecs::Numerous.new([1, 2])
|
||||||
|
result = e.chunk { |*x| x.should == [[1,2]] }.to_a
|
||||||
|
end
|
||||||
|
|
||||||
it "does not return elements for which the block returns :_separator" do
|
it "does not return elements for which the block returns :_separator" do
|
||||||
e = EnumerableSpecs::Numerous.new(1, 2, 3, 3, 2, 1)
|
e = EnumerableSpecs::Numerous.new(1, 2, 3, 3, 2, 1)
|
||||||
result = e.chunk { |x| x == 2 ? :_separator : 1 }.to_a
|
result = e.chunk { |x| x == 2 ? :_separator : 1 }.to_a
|
||||||
|
@ -29,7 +29,23 @@ describe "rescuing Interrupt" do
|
|||||||
sleep
|
sleep
|
||||||
rescue Interrupt => e
|
rescue Interrupt => e
|
||||||
e.signo.should == Signal.list["INT"]
|
e.signo.should == Signal.list["INT"]
|
||||||
e.signm.should == ""
|
["", "Interrupt"].should.include?(e.message)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "Interrupt" do
|
||||||
|
# This spec is basically the same as above,
|
||||||
|
# but it does not rely on Signal.trap(:INT, :SIG_DFL) which can be tricky
|
||||||
|
it "is raised on the main Thread by the default SIGINT handler" do
|
||||||
|
out = ruby_exe(<<-'RUBY', args: "2>&1")
|
||||||
|
begin
|
||||||
|
Process.kill :INT, Process.pid
|
||||||
|
sleep
|
||||||
|
rescue Interrupt => e
|
||||||
|
puts "Interrupt: #{e.signo}"
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
out.should == "Interrupt: #{Signal.list["INT"]}\n"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
@ -14,10 +14,8 @@ describe "StopIteration#result" do
|
|||||||
it "returns the method-returned-object from an Enumerator" do
|
it "returns the method-returned-object from an Enumerator" do
|
||||||
@enum.next
|
@enum.next
|
||||||
@enum.next
|
@enum.next
|
||||||
-> { @enum.next }.should(
|
-> { @enum.next }.should raise_error(StopIteration) { |error|
|
||||||
raise_error(StopIteration) do |error|
|
|
||||||
error.result.should equal(:method_returned)
|
error.result.should equal(:method_returned)
|
||||||
end
|
}
|
||||||
)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,16 +1,40 @@
|
|||||||
require_relative '../../spec_helper'
|
require_relative '../../spec_helper'
|
||||||
|
|
||||||
describe "GC.stat" do
|
describe "GC.stat" do
|
||||||
it "supports access by key" do
|
|
||||||
keys = [:heap_free_slots, :total_allocated_objects, :count]
|
|
||||||
keys.each do |key|
|
|
||||||
GC.stat(key).should be_kind_of(Integer)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it "returns hash of values" do
|
it "returns hash of values" do
|
||||||
stat = GC.stat
|
stat = GC.stat
|
||||||
stat.should be_kind_of(Hash)
|
stat.should be_kind_of(Hash)
|
||||||
stat.keys.should include(:count)
|
stat.keys.should include(:count)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "can return a single value" do
|
||||||
|
GC.stat(:count).should be_kind_of(Integer)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "increases count after GC is run" do
|
||||||
|
count = GC.stat(:count)
|
||||||
|
GC.start
|
||||||
|
GC.stat(:count).should > count
|
||||||
|
end
|
||||||
|
|
||||||
|
it "increases major_gc_count after GC is run" do
|
||||||
|
count = GC.stat(:major_gc_count)
|
||||||
|
GC.start
|
||||||
|
GC.stat(:major_gc_count).should > count
|
||||||
|
end
|
||||||
|
|
||||||
|
it "provides some number for count" do
|
||||||
|
GC.stat(:count).should be_kind_of(Integer)
|
||||||
|
GC.stat[:count].should be_kind_of(Integer)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "provides some number for heap_free_slots" do
|
||||||
|
GC.stat(:heap_free_slots).should be_kind_of(Integer)
|
||||||
|
GC.stat[:heap_free_slots].should be_kind_of(Integer)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "provides some number for total_allocated_objects" do
|
||||||
|
GC.stat(:total_allocated_objects).should be_kind_of(Integer)
|
||||||
|
GC.stat[:total_allocated_objects].should be_kind_of(Integer)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -27,6 +27,27 @@ describe "Kernel#raise" do
|
|||||||
|
|
||||||
ScratchPad.recorded.should be_nil
|
ScratchPad.recorded.should be_nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.6" do
|
||||||
|
it "accepts a cause keyword argument that sets the cause" do
|
||||||
|
cause = StandardError.new
|
||||||
|
-> { raise("error", cause: cause) }.should raise_error(RuntimeError) { |e| e.cause.should == cause }
|
||||||
|
end
|
||||||
|
|
||||||
|
it "accepts a cause keyword argument that overrides the last exception" do
|
||||||
|
begin
|
||||||
|
raise "first raise"
|
||||||
|
rescue => ignored
|
||||||
|
cause = StandardError.new
|
||||||
|
-> { raise("error", cause: cause) }.should raise_error(RuntimeError) { |e| e.cause.should == cause }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises an ArgumentError when only cause is given" do
|
||||||
|
cause = StandardError.new
|
||||||
|
-> { raise(cause: cause) }.should raise_error(ArgumentError)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "Kernel#raise" do
|
describe "Kernel#raise" do
|
||||||
|
@ -22,6 +22,12 @@ describe "Kernel#sleep" do
|
|||||||
sleep(Rational(1, 999)).should >= 0
|
sleep(Rational(1, 999)).should >= 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "accepts any Object that reponds to divmod" do
|
||||||
|
o = Object.new
|
||||||
|
def o.divmod(*); [0, 0.001]; end
|
||||||
|
sleep(o).should >= 0
|
||||||
|
end
|
||||||
|
|
||||||
it "raises an ArgumentError when passed a negative duration" do
|
it "raises an ArgumentError when passed a negative duration" do
|
||||||
-> { sleep(-0.1) }.should raise_error(ArgumentError)
|
-> { sleep(-0.1) }.should raise_error(ArgumentError)
|
||||||
-> { sleep(-1) }.should raise_error(ArgumentError)
|
-> { sleep(-1) }.should raise_error(ArgumentError)
|
||||||
|
@ -1,12 +1,9 @@
|
|||||||
require_relative '../../spec_helper'
|
require_relative '../../spec_helper'
|
||||||
require_relative 'fixtures/classes'
|
|
||||||
|
|
||||||
describe "Kernel#trap" do
|
describe "Kernel#trap" do
|
||||||
it "is a private method" do
|
it "is a private method" do
|
||||||
Kernel.should have_private_instance_method(:trap)
|
Kernel.should have_private_instance_method(:trap)
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
describe "Kernel.trap" do
|
# Behaviour is specified for Signal.trap
|
||||||
it "needs to be reviewed for spec completeness"
|
|
||||||
end
|
end
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
require_relative '../../spec_helper'
|
require_relative '../../spec_helper'
|
||||||
|
|
||||||
platform_is_not :windows do
|
|
||||||
describe "Signal.trap" do
|
describe "Signal.trap" do
|
||||||
|
platform_is_not :windows do
|
||||||
before :each do
|
before :each do
|
||||||
ScratchPad.clear
|
ScratchPad.clear
|
||||||
@proc = -> {}
|
@proc = -> {}
|
||||||
@saved_trap = Signal.trap(:HUP, @proc)
|
@saved_trap = Signal.trap(:HUP, @proc)
|
||||||
|
@hup_number = Signal.list["HUP"]
|
||||||
end
|
end
|
||||||
|
|
||||||
after :each do
|
after :each do
|
||||||
@ -16,10 +17,11 @@ platform_is_not :windows do
|
|||||||
Signal.trap(:HUP, @saved_trap).should equal(@proc)
|
Signal.trap(:HUP, @saved_trap).should equal(@proc)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "accepts a block in place of a proc/command argument" do
|
it "accepts a block" do
|
||||||
done = false
|
done = false
|
||||||
|
|
||||||
Signal.trap(:HUP) do
|
Signal.trap(:HUP) do |signo|
|
||||||
|
signo.should == @hup_number
|
||||||
ScratchPad.record :block_trap
|
ScratchPad.record :block_trap
|
||||||
done = true
|
done = true
|
||||||
end
|
end
|
||||||
@ -30,6 +32,94 @@ platform_is_not :windows do
|
|||||||
ScratchPad.recorded.should == :block_trap
|
ScratchPad.recorded.should == :block_trap
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "accepts a proc" do
|
||||||
|
done = false
|
||||||
|
|
||||||
|
handler = -> signo {
|
||||||
|
signo.should == @hup_number
|
||||||
|
ScratchPad.record :proc_trap
|
||||||
|
done = true
|
||||||
|
}
|
||||||
|
|
||||||
|
Signal.trap(:HUP, handler)
|
||||||
|
|
||||||
|
Process.kill :HUP, Process.pid
|
||||||
|
Thread.pass until done
|
||||||
|
|
||||||
|
ScratchPad.recorded.should == :proc_trap
|
||||||
|
end
|
||||||
|
|
||||||
|
it "accepts a method" do
|
||||||
|
done = false
|
||||||
|
|
||||||
|
handler_class = Class.new
|
||||||
|
hup_number = @hup_number
|
||||||
|
|
||||||
|
handler_class.define_method :handler_method do |signo|
|
||||||
|
signo.should == hup_number
|
||||||
|
ScratchPad.record :method_trap
|
||||||
|
done = true
|
||||||
|
end
|
||||||
|
|
||||||
|
handler_method = handler_class.new.method(:handler_method)
|
||||||
|
|
||||||
|
Signal.trap(:HUP, handler_method)
|
||||||
|
|
||||||
|
Process.kill :HUP, Process.pid
|
||||||
|
Thread.pass until done
|
||||||
|
|
||||||
|
ScratchPad.recorded.should == :method_trap
|
||||||
|
end
|
||||||
|
|
||||||
|
it "accepts anything you can call" do
|
||||||
|
done = false
|
||||||
|
|
||||||
|
callable = Object.new
|
||||||
|
hup_number = @hup_number
|
||||||
|
|
||||||
|
callable.singleton_class.define_method :call do |signo|
|
||||||
|
signo.should == hup_number
|
||||||
|
ScratchPad.record :callable_trap
|
||||||
|
done = true
|
||||||
|
end
|
||||||
|
|
||||||
|
Signal.trap(:HUP, callable)
|
||||||
|
|
||||||
|
Process.kill :HUP, Process.pid
|
||||||
|
Thread.pass until done
|
||||||
|
|
||||||
|
ScratchPad.recorded.should == :callable_trap
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises an exception for a non-callable at the point of use" do
|
||||||
|
not_callable = Object.new
|
||||||
|
Signal.trap(:HUP, not_callable)
|
||||||
|
-> {
|
||||||
|
Process.kill :HUP, Process.pid
|
||||||
|
loop { Thread.pass }
|
||||||
|
}.should raise_error(NoMethodError)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "accepts a non-callable that becomes callable when used" do
|
||||||
|
done = false
|
||||||
|
|
||||||
|
late_callable = Object.new
|
||||||
|
hup_number = @hup_number
|
||||||
|
|
||||||
|
Signal.trap(:HUP, late_callable)
|
||||||
|
|
||||||
|
late_callable.singleton_class.define_method :call do |signo|
|
||||||
|
signo.should == hup_number
|
||||||
|
ScratchPad.record :late_callable_trap
|
||||||
|
done = true
|
||||||
|
end
|
||||||
|
|
||||||
|
Process.kill :HUP, Process.pid
|
||||||
|
Thread.pass until done
|
||||||
|
|
||||||
|
ScratchPad.recorded.should == :late_callable_trap
|
||||||
|
end
|
||||||
|
|
||||||
it "is possible to create a new Thread when the handler runs" do
|
it "is possible to create a new Thread when the handler runs" do
|
||||||
done = false
|
done = false
|
||||||
|
|
||||||
@ -130,14 +220,12 @@ platform_is_not :windows do
|
|||||||
Signal.trap :HUP, @proc
|
Signal.trap :HUP, @proc
|
||||||
Signal.trap(:HUP, @saved_trap).should equal(@proc)
|
Signal.trap(:HUP, @saved_trap).should equal(@proc)
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
describe "Signal.trap" do
|
|
||||||
# See man 2 signal
|
# See man 2 signal
|
||||||
%w[KILL STOP].each do |signal|
|
%w[KILL STOP].each do |signal|
|
||||||
it "raises ArgumentError or Errno::EINVAL for SIG#{signal}" do
|
it "raises ArgumentError or Errno::EINVAL for SIG#{signal}" do
|
||||||
-> {
|
-> {
|
||||||
trap(signal, -> {})
|
Signal.trap(signal, -> {})
|
||||||
}.should raise_error(StandardError) { |e|
|
}.should raise_error(StandardError) { |e|
|
||||||
[ArgumentError, Errno::EINVAL].should include(e.class)
|
[ArgumentError, Errno::EINVAL].should include(e.class)
|
||||||
e.message.should =~ /Invalid argument|Signal already used by VM or OS/
|
e.message.should =~ /Invalid argument|Signal already used by VM or OS/
|
||||||
@ -152,7 +240,7 @@ platform_is_not :windows do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it "returns 'DEFAULT' for the initial SIGINT handler" do
|
it "returns 'DEFAULT' for the initial SIGINT handler" do
|
||||||
ruby_exe('print trap(:INT) { abort }').should == 'DEFAULT'
|
ruby_exe("print Signal.trap(:INT) { abort }").should == 'DEFAULT'
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns SYSTEM_DEFAULT if passed DEFAULT and no handler was ever set" do
|
it "returns SYSTEM_DEFAULT if passed DEFAULT and no handler was ever set" do
|
||||||
@ -174,23 +262,22 @@ platform_is_not :windows do
|
|||||||
Signal.signame(status.termsig).should == "PIPE"
|
Signal.signame(status.termsig).should == "PIPE"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
describe "Signal.trap" do
|
|
||||||
describe "the special EXIT signal code" do
|
describe "the special EXIT signal code" do
|
||||||
it "accepts the EXIT code" do
|
it "accepts the EXIT code" do
|
||||||
code = "trap(:EXIT, proc { print 1 })"
|
code = "Signal.trap(:EXIT, proc { print 1 })"
|
||||||
ruby_exe(code).should == "1"
|
ruby_exe(code).should == "1"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "runs the proc before at_exit handlers" do
|
it "runs the proc before at_exit handlers" do
|
||||||
code = "at_exit {print 1}; trap(:EXIT, proc {print 2}); at_exit {print 3}"
|
code = "at_exit {print 1}; Signal.trap(:EXIT, proc {print 2}); at_exit {print 3}"
|
||||||
ruby_exe(code).should == "231"
|
ruby_exe(code).should == "231"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "can unset the handler" do
|
it "can unset the handler" do
|
||||||
code = "trap(:EXIT, proc { print 1 }); trap(:EXIT, 'DEFAULT')"
|
code = "Signal.trap(:EXIT, proc { print 1 }); Signal.trap(:EXIT, 'DEFAULT')"
|
||||||
ruby_exe(code).should == ""
|
ruby_exe(code).should == ""
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -38,6 +38,20 @@ describe "Time.at" do
|
|||||||
Time.at(BigDecimal('1.1')).to_f.should == 1.1
|
Time.at(BigDecimal('1.1')).to_f.should == 1.1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "passed Rational" do
|
||||||
|
it "returns Time with correct microseconds" do
|
||||||
|
t = Time.at(Rational(1_486_570_508_539_759, 1_000_000))
|
||||||
|
t.usec.should == 539_759
|
||||||
|
t.nsec.should == 539_759_000
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns Time with correct nanoseconds" do
|
||||||
|
t = Time.at(Rational(1_486_570_508_539_759_123, 1_000_000_000))
|
||||||
|
t.usec.should == 539_759
|
||||||
|
t.nsec.should == 539_759_123
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "passed Time" do
|
describe "passed Time" do
|
||||||
|
@ -381,52 +381,6 @@ describe "Constant resolution within methods" do
|
|||||||
ConstantSpecs::ClassA.constx.should == :CS_CONSTX
|
ConstantSpecs::ClassA.constx.should == :CS_CONSTX
|
||||||
ConstantSpecs::ClassA.new.constx.should == :CS_CONSTX
|
ConstantSpecs::ClassA.new.constx.should == :CS_CONSTX
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "with ||=" do
|
|
||||||
it "assigns a scoped constant if previously undefined" do
|
|
||||||
ConstantSpecs.should_not have_constant(:OpAssignUndefined)
|
|
||||||
module ConstantSpecs
|
|
||||||
OpAssignUndefined ||= 42
|
|
||||||
end
|
|
||||||
ConstantSpecs::OpAssignUndefined.should == 42
|
|
||||||
ConstantSpecs::OpAssignUndefinedOutside ||= 42
|
|
||||||
ConstantSpecs::OpAssignUndefinedOutside.should == 42
|
|
||||||
ConstantSpecs.send(:remove_const, :OpAssignUndefined)
|
|
||||||
ConstantSpecs.send(:remove_const, :OpAssignUndefinedOutside)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "assigns a global constant if previously undefined" do
|
|
||||||
OpAssignGlobalUndefined ||= 42
|
|
||||||
::OpAssignGlobalUndefinedExplicitScope ||= 42
|
|
||||||
OpAssignGlobalUndefined.should == 42
|
|
||||||
::OpAssignGlobalUndefinedExplicitScope.should == 42
|
|
||||||
Object.send :remove_const, :OpAssignGlobalUndefined
|
|
||||||
Object.send :remove_const, :OpAssignGlobalUndefinedExplicitScope
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "with &&=" do
|
|
||||||
it "re-assigns a scoped constant if already true" do
|
|
||||||
module ConstantSpecs
|
|
||||||
OpAssignTrue = true
|
|
||||||
end
|
|
||||||
suppress_warning do
|
|
||||||
ConstantSpecs::OpAssignTrue &&= 1
|
|
||||||
end
|
|
||||||
ConstantSpecs::OpAssignTrue.should == 1
|
|
||||||
ConstantSpecs.send :remove_const, :OpAssignTrue
|
|
||||||
end
|
|
||||||
|
|
||||||
it "leaves scoped constant if not true" do
|
|
||||||
module ConstantSpecs
|
|
||||||
OpAssignFalse = false
|
|
||||||
end
|
|
||||||
ConstantSpecs::OpAssignFalse &&= 1
|
|
||||||
ConstantSpecs::OpAssignFalse.should == false
|
|
||||||
ConstantSpecs.send :remove_const, :OpAssignFalse
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "Constant resolution within a singleton class (class << obj)" do
|
describe "Constant resolution within a singleton class (class << obj)" do
|
||||||
|
@ -74,9 +74,9 @@ describe "An ensure block inside a begin block" do
|
|||||||
ensure
|
ensure
|
||||||
raise "from ensure"
|
raise "from ensure"
|
||||||
end
|
end
|
||||||
}.should raise_error(RuntimeError, "from ensure") do |e|
|
}.should raise_error(RuntimeError, "from ensure") { |e|
|
||||||
e.cause.message.should == "from block"
|
e.cause.message.should == "from block"
|
||||||
end
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -167,3 +167,42 @@ describe "Hash literal" do
|
|||||||
usascii_hash.keys.first.encoding.should == Encoding::US_ASCII
|
usascii_hash.keys.first.encoding.should == Encoding::US_ASCII
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "The ** operator" do
|
||||||
|
it "makes a copy when calling a method taking a keyword rest argument" do
|
||||||
|
def m(**h)
|
||||||
|
h.delete(:one); h
|
||||||
|
end
|
||||||
|
|
||||||
|
h = { one: 1, two: 2 }
|
||||||
|
m(**h).should == { two: 2 }
|
||||||
|
m(**h).should_not.equal?(h)
|
||||||
|
h.should == { one: 1, two: 2 }
|
||||||
|
end
|
||||||
|
|
||||||
|
ruby_version_is ""..."3.0" do
|
||||||
|
it "makes a caller-side copy when calling a method taking a positional Hash" do
|
||||||
|
def m(h)
|
||||||
|
h.delete(:one); h
|
||||||
|
end
|
||||||
|
|
||||||
|
h = { one: 1, two: 2 }
|
||||||
|
m(**h).should == { two: 2 }
|
||||||
|
m(**h).should_not.equal?(h)
|
||||||
|
h.should == { one: 1, two: 2 }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
ruby_version_is "3.0" do
|
||||||
|
it "does not copy when calling a method taking a positional Hash" do
|
||||||
|
def m(h)
|
||||||
|
h.delete(:one); h
|
||||||
|
end
|
||||||
|
|
||||||
|
h = { one: 1, two: 2 }
|
||||||
|
m(**h).should == { two: 2 }
|
||||||
|
m(**h).should.equal?(h)
|
||||||
|
h.should == { two: 2 }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
@ -1758,6 +1758,17 @@ describe "A method" do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "assigns the last Hash to the last optional argument if the Hash contains non-Symbol keys and is not passed as keywords" do
|
||||||
|
def m(a = nil, b = {}, v: false)
|
||||||
|
[a, b, v]
|
||||||
|
end
|
||||||
|
|
||||||
|
h = { "key" => "value" }
|
||||||
|
m(:a, h).should == [:a, h, false]
|
||||||
|
m(:a, h, v: true).should == [:a, h, true]
|
||||||
|
m(v: true).should == [nil, {}, true]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "A method call with a space between method name and parentheses" do
|
describe "A method call with a space between method name and parentheses" do
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
require_relative '../spec_helper'
|
require_relative '../spec_helper'
|
||||||
|
require_relative '../fixtures/constants'
|
||||||
|
|
||||||
describe 'Optional variable assignments' do
|
describe 'Optional variable assignments' do
|
||||||
describe 'using ||=' do
|
describe 'using ||=' do
|
||||||
@ -351,3 +352,107 @@ describe 'Optional variable assignments' do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'Optional constant assignment' do
|
||||||
|
describe 'with ||=' do
|
||||||
|
it "assigns a scoped constant if previously undefined" do
|
||||||
|
ConstantSpecs.should_not have_constant(:OpAssignUndefined)
|
||||||
|
module ConstantSpecs
|
||||||
|
OpAssignUndefined ||= 42
|
||||||
|
end
|
||||||
|
ConstantSpecs::OpAssignUndefined.should == 42
|
||||||
|
ConstantSpecs::OpAssignUndefinedOutside ||= 42
|
||||||
|
ConstantSpecs::OpAssignUndefinedOutside.should == 42
|
||||||
|
ConstantSpecs.send(:remove_const, :OpAssignUndefined)
|
||||||
|
ConstantSpecs.send(:remove_const, :OpAssignUndefinedOutside)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "assigns a global constant if previously undefined" do
|
||||||
|
OpAssignGlobalUndefined ||= 42
|
||||||
|
::OpAssignGlobalUndefinedExplicitScope ||= 42
|
||||||
|
OpAssignGlobalUndefined.should == 42
|
||||||
|
::OpAssignGlobalUndefinedExplicitScope.should == 42
|
||||||
|
Object.send :remove_const, :OpAssignGlobalUndefined
|
||||||
|
Object.send :remove_const, :OpAssignGlobalUndefinedExplicitScope
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'correctly defines non-existing constants' do
|
||||||
|
ConstantSpecs::ClassA::OR_ASSIGNED_CONSTANT1 ||= :assigned
|
||||||
|
ConstantSpecs::ClassA::OR_ASSIGNED_CONSTANT1.should == :assigned
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'correctly overwrites nil constants' do
|
||||||
|
suppress_warning do # already initialized constant
|
||||||
|
ConstantSpecs::ClassA::NIL_OR_ASSIGNED_CONSTANT1 = nil
|
||||||
|
ConstantSpecs::ClassA::NIL_OR_ASSIGNED_CONSTANT1 ||= :assigned
|
||||||
|
ConstantSpecs::ClassA::NIL_OR_ASSIGNED_CONSTANT1.should == :assigned
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'causes side-effects of the module part to be applied only once (for undefined constant)' do
|
||||||
|
x = 0
|
||||||
|
(x += 1; ConstantSpecs::ClassA)::OR_ASSIGNED_CONSTANT2 ||= :assigned
|
||||||
|
x.should == 1
|
||||||
|
ConstantSpecs::ClassA::OR_ASSIGNED_CONSTANT2.should == :assigned
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'causes side-effects of the module part to be applied (for nil constant)' do
|
||||||
|
suppress_warning do # already initialized constant
|
||||||
|
ConstantSpecs::ClassA::NIL_OR_ASSIGNED_CONSTANT2 = nil
|
||||||
|
x = 0
|
||||||
|
(x += 1; ConstantSpecs::ClassA)::NIL_OR_ASSIGNED_CONSTANT2 ||= :assigned
|
||||||
|
x.should == 1
|
||||||
|
ConstantSpecs::ClassA::NIL_OR_ASSIGNED_CONSTANT2.should == :assigned
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not evaluate the right-hand side if the module part raises an exception (for undefined constant)' do
|
||||||
|
x = 0
|
||||||
|
y = 0
|
||||||
|
|
||||||
|
-> {
|
||||||
|
(x += 1; raise Exception; ConstantSpecs::ClassA)::OR_ASSIGNED_CONSTANT3 ||= (y += 1; :assigned)
|
||||||
|
}.should raise_error(Exception)
|
||||||
|
|
||||||
|
x.should == 1
|
||||||
|
y.should == 0
|
||||||
|
defined?(ConstantSpecs::ClassA::OR_ASSIGNED_CONSTANT3).should == nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not evaluate the right-hand side if the module part raises an exception (for nil constant)' do
|
||||||
|
ConstantSpecs::ClassA::NIL_OR_ASSIGNED_CONSTANT3 = nil
|
||||||
|
x = 0
|
||||||
|
y = 0
|
||||||
|
|
||||||
|
-> {
|
||||||
|
(x += 1; raise Exception; ConstantSpecs::ClassA)::NIL_OR_ASSIGNED_CONSTANT3 ||= (y += 1; :assigned)
|
||||||
|
}.should raise_error(Exception)
|
||||||
|
|
||||||
|
x.should == 1
|
||||||
|
y.should == 0
|
||||||
|
ConstantSpecs::ClassA::NIL_OR_ASSIGNED_CONSTANT3.should == nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "with &&=" do
|
||||||
|
it "re-assigns a scoped constant if already true" do
|
||||||
|
module ConstantSpecs
|
||||||
|
OpAssignTrue = true
|
||||||
|
end
|
||||||
|
suppress_warning do
|
||||||
|
ConstantSpecs::OpAssignTrue &&= 1
|
||||||
|
end
|
||||||
|
ConstantSpecs::OpAssignTrue.should == 1
|
||||||
|
ConstantSpecs.send :remove_const, :OpAssignTrue
|
||||||
|
end
|
||||||
|
|
||||||
|
it "leaves scoped constant if not true" do
|
||||||
|
module ConstantSpecs
|
||||||
|
OpAssignFalse = false
|
||||||
|
end
|
||||||
|
ConstantSpecs::OpAssignFalse &&= 1
|
||||||
|
ConstantSpecs::OpAssignFalse.should == false
|
||||||
|
ConstantSpecs.send :remove_const, :OpAssignFalse
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
@ -25,4 +25,11 @@ describe "Regexps with grouping" do
|
|||||||
-> { Regexp.new("(?<1a>a)") }.should raise_error(RegexpError)
|
-> { Regexp.new("(?<1a>a)") }.should raise_error(RegexpError)
|
||||||
-> { Regexp.new("(?<-a>a)") }.should raise_error(RegexpError)
|
-> { Regexp.new("(?<-a>a)") }.should raise_error(RegexpError)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "ignore capture groups in line comments" do
|
||||||
|
/^
|
||||||
|
(a) # there is a capture group on this line
|
||||||
|
b # there is no capture group on this line (not even here)
|
||||||
|
$/x.match("ab").to_a.should == [ "ab", "a" ]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -428,9 +428,9 @@ describe "The rescue keyword" do
|
|||||||
raise "from block"
|
raise "from block"
|
||||||
rescue (raise "from rescue expression")
|
rescue (raise "from rescue expression")
|
||||||
end
|
end
|
||||||
}.should raise_error(RuntimeError, "from rescue expression") do |e|
|
}.should raise_error(RuntimeError, "from rescue expression") { |e|
|
||||||
e.cause.message.should == "from block"
|
e.cause.message.should == "from block"
|
||||||
end
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should splat the handling Error classes" do
|
it "should splat the handling Error classes" do
|
||||||
|
@ -308,4 +308,14 @@ describe "Ruby String interpolation" do
|
|||||||
eval(code).should_not.frozen?
|
eval(code).should_not.frozen?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is ""..."3.0" do
|
||||||
|
it "creates a frozen String when # frozen-string-literal: true is used" do
|
||||||
|
code = <<~'RUBY'
|
||||||
|
# frozen-string-literal: true
|
||||||
|
"a#{6*7}c"
|
||||||
|
RUBY
|
||||||
|
eval(code).should.frozen?
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
30
spec/ruby/library/monitor/synchronize_spec.rb
Normal file
30
spec/ruby/library/monitor/synchronize_spec.rb
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
require_relative '../../spec_helper'
|
||||||
|
require 'monitor'
|
||||||
|
|
||||||
|
describe "Monitor#synchronize" do
|
||||||
|
it "unlocks after return, even if it was interrupted by Thread#raise" do
|
||||||
|
exc_class = Class.new(RuntimeError)
|
||||||
|
|
||||||
|
monitor = Monitor.new
|
||||||
|
10.times do
|
||||||
|
locked = false
|
||||||
|
|
||||||
|
thread = Thread.new do
|
||||||
|
begin
|
||||||
|
monitor.synchronize do
|
||||||
|
locked = true
|
||||||
|
# Do not wait here, we are trying to interrupt the ensure part of #synchronize
|
||||||
|
end
|
||||||
|
sleep # wait for exception if it did not happen yet
|
||||||
|
rescue exc_class
|
||||||
|
monitor.should_not.mon_locked?
|
||||||
|
:ok
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Thread.pass until locked
|
||||||
|
thread.raise exc_class, "interrupt"
|
||||||
|
thread.value.should == :ok
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -21,7 +21,7 @@ describe 'Socket.udp_server_loop' do
|
|||||||
it 'yields the message and a Socket::UDPSource' do
|
it 'yields the message and a Socket::UDPSource' do
|
||||||
msg, src = nil
|
msg, src = nil
|
||||||
|
|
||||||
Thread.new do
|
thread = Thread.new do
|
||||||
SocketSpecs::ServerLoopPortFinder.udp_server_loop('127.0.0.1', 0) do |message, source|
|
SocketSpecs::ServerLoopPortFinder.udp_server_loop('127.0.0.1', 0) do |message, source|
|
||||||
msg = message
|
msg = message
|
||||||
src = source
|
src = source
|
||||||
@ -52,6 +52,8 @@ describe 'Socket.udp_server_loop' do
|
|||||||
|
|
||||||
msg.should == 'hello'
|
msg.should == 'hello'
|
||||||
src.should be_an_instance_of(Socket::UDPSource)
|
src.should be_an_instance_of(Socket::UDPSource)
|
||||||
|
|
||||||
|
thread.join
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -13,9 +13,11 @@ class WeakRefSpec
|
|||||||
def self.make_dead_weakref
|
def self.make_dead_weakref
|
||||||
weaks = []
|
weaks = []
|
||||||
weak = nil
|
weak = nil
|
||||||
10_000.times do
|
1000.times do
|
||||||
weaks << make_weakref
|
weaks << make_weakref
|
||||||
GC.start
|
end
|
||||||
|
|
||||||
|
1000.times do
|
||||||
GC.start
|
GC.start
|
||||||
break if weak = weaks.find { |w| !w.weakref_alive? }
|
break if weak = weaks.find { |w| !w.weakref_alive? }
|
||||||
end
|
end
|
||||||
|
@ -191,6 +191,14 @@ static VALUE kernel_spec_rb_protect_yield(VALUE self, VALUE obj, VALUE ary) {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static VALUE kernel_spec_rb_protect_errinfo(VALUE self, VALUE obj, VALUE ary) {
|
||||||
|
int status = 0;
|
||||||
|
VALUE res = rb_protect(rb_yield, obj, &status);
|
||||||
|
rb_ary_store(ary, 0, INT2NUM(23));
|
||||||
|
rb_ary_store(ary, 1, res);
|
||||||
|
return rb_errinfo();
|
||||||
|
}
|
||||||
|
|
||||||
static VALUE kernel_spec_rb_protect_null_status(VALUE self, VALUE obj) {
|
static VALUE kernel_spec_rb_protect_null_status(VALUE self, VALUE obj) {
|
||||||
return rb_protect(rb_yield, obj, NULL);
|
return rb_protect(rb_yield, obj, NULL);
|
||||||
}
|
}
|
||||||
@ -345,6 +353,7 @@ void Init_kernel_spec(void) {
|
|||||||
rb_define_method(cls, "rb_rescue", kernel_spec_rb_rescue, 4);
|
rb_define_method(cls, "rb_rescue", kernel_spec_rb_rescue, 4);
|
||||||
rb_define_method(cls, "rb_rescue2", kernel_spec_rb_rescue2, -1);
|
rb_define_method(cls, "rb_rescue2", kernel_spec_rb_rescue2, -1);
|
||||||
rb_define_method(cls, "rb_protect_yield", kernel_spec_rb_protect_yield, 2);
|
rb_define_method(cls, "rb_protect_yield", kernel_spec_rb_protect_yield, 2);
|
||||||
|
rb_define_method(cls, "rb_protect_errinfo", kernel_spec_rb_protect_errinfo, 2);
|
||||||
rb_define_method(cls, "rb_protect_null_status", kernel_spec_rb_protect_null_status, 1);
|
rb_define_method(cls, "rb_protect_null_status", kernel_spec_rb_protect_null_status, 1);
|
||||||
rb_define_method(cls, "rb_eval_string_protect", kernel_spec_rb_eval_string_protect, 2);
|
rb_define_method(cls, "rb_eval_string_protect", kernel_spec_rb_eval_string_protect, 2);
|
||||||
rb_define_method(cls, "rb_catch", kernel_spec_rb_catch, 2);
|
rb_define_method(cls, "rb_catch", kernel_spec_rb_catch, 2);
|
||||||
|
@ -9,6 +9,18 @@ static VALUE module_specs_test_method(VALUE self) {
|
|||||||
return ID2SYM(rb_intern("test_method"));
|
return ID2SYM(rb_intern("test_method"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static VALUE module_specs_test_method_2required(VALUE self, VALUE arg1, VALUE arg2) {
|
||||||
|
return ID2SYM(rb_intern("test_method_2required"));
|
||||||
|
}
|
||||||
|
|
||||||
|
static VALUE module_specs_test_method_c_array(int argc, VALUE *argv, VALUE self) {
|
||||||
|
return ID2SYM(rb_intern("test_method_c_array"));
|
||||||
|
}
|
||||||
|
|
||||||
|
static VALUE module_specs_test_method_ruby_array(VALUE self, VALUE args) {
|
||||||
|
return ID2SYM(rb_intern("test_method_ruby_array"));
|
||||||
|
}
|
||||||
|
|
||||||
static VALUE module_specs_const_defined(VALUE self, VALUE klass, VALUE id) {
|
static VALUE module_specs_const_defined(VALUE self, VALUE klass, VALUE id) {
|
||||||
return rb_const_defined(klass, SYM2ID(id)) ? Qtrue : Qfalse;
|
return rb_const_defined(klass, SYM2ID(id)) ? Qtrue : Qfalse;
|
||||||
}
|
}
|
||||||
@ -76,6 +88,21 @@ static VALUE module_specs_rb_define_method(VALUE self, VALUE cls, VALUE str_name
|
|||||||
return Qnil;
|
return Qnil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static VALUE module_specs_rb_define_method_2required(VALUE self, VALUE cls, VALUE str_name) {
|
||||||
|
rb_define_method(cls, RSTRING_PTR(str_name), module_specs_test_method_2required, 2);
|
||||||
|
return Qnil;
|
||||||
|
}
|
||||||
|
|
||||||
|
static VALUE module_specs_rb_define_method_c_array(VALUE self, VALUE cls, VALUE str_name) {
|
||||||
|
rb_define_method(cls, RSTRING_PTR(str_name), module_specs_test_method_c_array, -1);
|
||||||
|
return Qnil;
|
||||||
|
}
|
||||||
|
|
||||||
|
static VALUE module_specs_rb_define_method_ruby_array(VALUE self, VALUE cls, VALUE str_name) {
|
||||||
|
rb_define_method(cls, RSTRING_PTR(str_name), module_specs_test_method_ruby_array, -2);
|
||||||
|
return Qnil;
|
||||||
|
}
|
||||||
|
|
||||||
static VALUE module_specs_rb_define_module_function(VALUE self, VALUE cls, VALUE str_name) {
|
static VALUE module_specs_rb_define_module_function(VALUE self, VALUE cls, VALUE str_name) {
|
||||||
rb_define_module_function(cls, RSTRING_PTR(str_name), module_specs_test_method, 0);
|
rb_define_module_function(cls, RSTRING_PTR(str_name), module_specs_test_method, 0);
|
||||||
return Qnil;
|
return Qnil;
|
||||||
@ -132,6 +159,10 @@ void Init_module_spec(void) {
|
|||||||
module_specs_rb_define_global_function, 1);
|
module_specs_rb_define_global_function, 1);
|
||||||
|
|
||||||
rb_define_method(cls, "rb_define_method", module_specs_rb_define_method, 2);
|
rb_define_method(cls, "rb_define_method", module_specs_rb_define_method, 2);
|
||||||
|
rb_define_method(cls, "rb_define_method_2required", module_specs_rb_define_method_2required, 2);
|
||||||
|
rb_define_method(cls, "rb_define_method_c_array", module_specs_rb_define_method_c_array, 2);
|
||||||
|
rb_define_method(cls, "rb_define_method_ruby_array", module_specs_rb_define_method_ruby_array, 2);
|
||||||
|
|
||||||
rb_define_method(cls, "rb_define_module_function",
|
rb_define_method(cls, "rb_define_module_function",
|
||||||
module_specs_rb_define_module_function, 2);
|
module_specs_rb_define_module_function, 2);
|
||||||
|
|
||||||
|
@ -312,6 +312,14 @@ describe "C-API Kernel function" do
|
|||||||
@s.rb_protect_null_status(42) { |x| x + 1 }.should == 43
|
@s.rb_protect_null_status(42) { |x| x + 1 }.should == 43
|
||||||
@s.rb_protect_null_status(42) { |x| raise }.should == nil
|
@s.rb_protect_null_status(42) { |x| raise }.should == nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "populates errinfo with the captured exception" do
|
||||||
|
proof = []
|
||||||
|
@s.rb_protect_errinfo(77, proof) { |x| raise NameError }.class.should == NameError
|
||||||
|
proof[0].should == 23
|
||||||
|
proof[1].should == nil
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "rb_eval_string_protect" do
|
describe "rb_eval_string_protect" do
|
||||||
|
@ -246,12 +246,30 @@ describe "CApiModule" do
|
|||||||
cls.new.test_method.should == :test_method
|
cls.new.test_method.should == :test_method
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns the correct arity of the method in class" do
|
it "returns the correct arity when argc of the method in class is 0" do
|
||||||
cls = Class.new
|
cls = Class.new
|
||||||
@m.rb_define_method(cls, "test_method")
|
@m.rb_define_method(cls, "test_method")
|
||||||
cls.new.method(:test_method).arity.should == 0
|
cls.new.method(:test_method).arity.should == 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "returns the correct arity when argc of the method in class is -1" do
|
||||||
|
cls = Class.new
|
||||||
|
@m.rb_define_method_c_array(cls, "test_method_c_array")
|
||||||
|
cls.new.method(:test_method_c_array).arity.should == -1
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns the correct arity when argc of the method in class is -2" do
|
||||||
|
cls = Class.new
|
||||||
|
@m.rb_define_method_ruby_array(cls, "test_method_ruby_array")
|
||||||
|
cls.new.method(:test_method_ruby_array).arity.should == -1
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns the correct arity when argc of the method in class is 2" do
|
||||||
|
cls = Class.new
|
||||||
|
@m.rb_define_method_2required(cls, "test_method_2required")
|
||||||
|
cls.new.method(:test_method_2required).arity.should == 2
|
||||||
|
end
|
||||||
|
|
||||||
it "defines a method on a module" do
|
it "defines a method on a module" do
|
||||||
mod = Module.new
|
mod = Module.new
|
||||||
@m.rb_define_method(mod, "test_method")
|
@m.rb_define_method(mod, "test_method")
|
||||||
|
@ -12,6 +12,28 @@ describe :kernel_raise, shared: true do
|
|||||||
ScratchPad.recorded.should be_nil
|
ScratchPad.recorded.should be_nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "accepts an exception that implements to_hash" do
|
||||||
|
custom_error = Class.new(StandardError) do
|
||||||
|
def to_hash
|
||||||
|
{}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
error = custom_error.new
|
||||||
|
-> { @object.raise(error) }.should raise_error(custom_error)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "allows the message parameter to be a hash" do
|
||||||
|
data_error = Class.new(StandardError) do
|
||||||
|
attr_reader :data
|
||||||
|
def initialize(data)
|
||||||
|
@data = data
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-> { @object.raise(data_error, {:data => 42}) }.should raise_error(data_error) do |ex|
|
||||||
|
ex.data.should == {:data => 42}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it "raises RuntimeError if no exception class is given" do
|
it "raises RuntimeError if no exception class is given" do
|
||||||
-> { @object.raise }.should raise_error(RuntimeError, "")
|
-> { @object.raise }.should raise_error(RuntimeError, "")
|
||||||
end
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user