aboutsummaryrefslogtreecommitdiffstats
path: root/spec/ruby/core
diff options
context:
space:
mode:
authorBenoit Daloze <eregontp@gmail.com>2021-10-20 21:41:46 +0200
committerBenoit Daloze <eregontp@gmail.com>2021-10-20 21:41:46 +0200
commita6c6eef04aaa075f4bbd0eef740d011737afec91 (patch)
treee8779ca2ddc044899caabca88c16abc9a9054fff /spec/ruby/core
parent207a5a5bc13018344dc2ab7913fdcaeaeca01292 (diff)
downloadruby-a6c6eef04aaa075f4bbd0eef740d011737afec91.tar.gz
Update to ruby/spec@d6921ef
Diffstat (limited to 'spec/ruby/core')
-rw-r--r--spec/ruby/core/array/shared/slice.rb217
-rw-r--r--spec/ruby/core/binding/eval_spec.rb16
-rw-r--r--spec/ruby/core/conditionvariable/broadcast_spec.rb40
-rw-r--r--spec/ruby/core/conditionvariable/marshal_dump_spec.rb9
-rw-r--r--spec/ruby/core/conditionvariable/signal_spec.rb77
-rw-r--r--spec/ruby/core/conditionvariable/wait_spec.rb175
-rw-r--r--spec/ruby/core/dir/shared/glob.rb17
-rw-r--r--spec/ruby/core/env/shift_spec.rb39
-rw-r--r--spec/ruby/core/file/utime_spec.rb12
-rw-r--r--spec/ruby/core/float/comparison_spec.rb15
-rw-r--r--spec/ruby/core/hash/transform_keys_spec.rb27
-rw-r--r--spec/ruby/core/integer/zero_spec.rb21
-rw-r--r--spec/ruby/core/kernel/clone_spec.rb92
-rw-r--r--spec/ruby/core/kernel/eval_spec.rb10
-rw-r--r--spec/ruby/core/kernel/fixtures/classes.rb8
-rw-r--r--spec/ruby/core/module/autoload_spec.rb100
-rw-r--r--spec/ruby/core/module/const_set_spec.rb3
-rw-r--r--spec/ruby/core/module/constants_spec.rb6
-rw-r--r--spec/ruby/core/range/each_spec.rb24
19 files changed, 778 insertions, 130 deletions
diff --git a/spec/ruby/core/array/shared/slice.rb b/spec/ruby/core/array/shared/slice.rb
index 19e1a3ee2b..cf195ad7a4 100644
--- a/spec/ruby/core/array/shared/slice.rb
+++ b/spec/ruby/core/array/shared/slice.rb
@@ -517,8 +517,9 @@ describe :array_slice, shared: true do
end
it "raises a RangeError if passed a range with a bound that is too large" do
- -> { "hello".send(@method, bignum_value..(bignum_value + 1)) }.should raise_error(RangeError)
- -> { "hello".send(@method, 0..bignum_value) }.should raise_error(RangeError)
+ array = [1, 2, 3, 4, 5, 6]
+ -> { array.send(@method, bignum_value..(bignum_value + 1)) }.should raise_error(RangeError)
+ -> { array.send(@method, 0..bignum_value) }.should raise_error(RangeError)
end
it "can accept endless ranges" do
@@ -533,6 +534,218 @@ describe :array_slice, shared: true do
a.send(@method, eval("(-9...)")).should == nil
end
+ ruby_version_is "3.0" do
+ describe "can be sliced with Enumerator::ArithmeticSequence" do
+ before :each do
+ @array = [0, 1, 2, 3, 4, 5]
+ end
+
+ it "has endless range and positive steps" do
+ @array.send(@method, eval("(0..).step(1)")).should == [0, 1, 2, 3, 4, 5]
+ @array.send(@method, eval("(0..).step(2)")).should == [0, 2, 4]
+ @array.send(@method, eval("(0..).step(10)")).should == [0]
+
+ @array.send(@method, eval("(2..).step(1)")).should == [2, 3, 4, 5]
+ @array.send(@method, eval("(2..).step(2)")).should == [2, 4]
+ @array.send(@method, eval("(2..).step(10)")).should == [2]
+
+ @array.send(@method, eval("(-3..).step(1)")).should == [3, 4, 5]
+ @array.send(@method, eval("(-3..).step(2)")).should == [3, 5]
+ @array.send(@method, eval("(-3..).step(10)")).should == [3]
+ end
+
+ it "has beginless range and positive steps" do
+ # end with zero index
+ @array.send(@method, eval("(..0).step(1)")).should == [0]
+ @array.send(@method, eval("(...0).step(1)")).should == []
+
+ @array.send(@method, eval("(..0).step(2)")).should == [0]
+ @array.send(@method, eval("(...0).step(2)")).should == []
+
+ @array.send(@method, eval("(..0).step(10)")).should == [0]
+ @array.send(@method, eval("(...0).step(10)")).should == []
+
+ # end with positive index
+ @array.send(@method, eval("(..3).step(1)")).should == [0, 1, 2, 3]
+ @array.send(@method, eval("(...3).step(1)")).should == [0, 1, 2]
+
+ @array.send(@method, eval("(..3).step(2)")).should == [0, 2]
+ @array.send(@method, eval("(...3).step(2)")).should == [0, 2]
+
+ @array.send(@method, eval("(..3).step(10)")).should == [0]
+ @array.send(@method, eval("(...3).step(10)")).should == [0]
+
+ # end with negative index
+ @array.send(@method, eval("(..-2).step(1)")).should == [0, 1, 2, 3, 4,]
+ @array.send(@method, eval("(...-2).step(1)")).should == [0, 1, 2, 3]
+
+ @array.send(@method, eval("(..-2).step(2)")).should == [0, 2, 4]
+ @array.send(@method, eval("(...-2).step(2)")).should == [0, 2]
+
+ @array.send(@method, eval("(..-2).step(10)")).should == [0]
+ @array.send(@method, eval("(...-2).step(10)")).should == [0]
+ end
+
+ it "has endless range and negative steps" do
+ @array.send(@method, eval("(0..).step(-1)")).should == [0]
+ @array.send(@method, eval("(0..).step(-2)")).should == [0]
+ @array.send(@method, eval("(0..).step(-10)")).should == [0]
+
+ @array.send(@method, eval("(2..).step(-1)")).should == [2, 1, 0]
+ @array.send(@method, eval("(2..).step(-2)")).should == [2, 0]
+
+ @array.send(@method, eval("(-3..).step(-1)")).should == [3, 2, 1, 0]
+ @array.send(@method, eval("(-3..).step(-2)")).should == [3, 1]
+ end
+
+ it "has closed range and positive steps" do
+ # start and end with 0
+ @array.send(@method, eval("(0..0).step(1)")).should == [0]
+ @array.send(@method, eval("(0...0).step(1)")).should == []
+
+ @array.send(@method, eval("(0..0).step(2)")).should == [0]
+ @array.send(@method, eval("(0...0).step(2)")).should == []
+
+ @array.send(@method, eval("(0..0).step(10)")).should == [0]
+ @array.send(@method, eval("(0...0).step(10)")).should == []
+
+ # start and end with positive index
+ @array.send(@method, eval("(1..3).step(1)")).should == [1, 2, 3]
+ @array.send(@method, eval("(1...3).step(1)")).should == [1, 2]
+
+ @array.send(@method, eval("(1..3).step(2)")).should == [1, 3]
+ @array.send(@method, eval("(1...3).step(2)")).should == [1]
+
+ @array.send(@method, eval("(1..3).step(10)")).should == [1]
+ @array.send(@method, eval("(1...3).step(10)")).should == [1]
+
+ # start with positive index, end with negative index
+ @array.send(@method, eval("(1..-2).step(1)")).should == [1, 2, 3, 4]
+ @array.send(@method, eval("(1...-2).step(1)")).should == [1, 2, 3]
+
+ @array.send(@method, eval("(1..-2).step(2)")).should == [1, 3]
+ @array.send(@method, eval("(1...-2).step(2)")).should == [1, 3]
+
+ @array.send(@method, eval("(1..-2).step(10)")).should == [1]
+ @array.send(@method, eval("(1...-2).step(10)")).should == [1]
+
+ # start with negative index, end with positive index
+ @array.send(@method, eval("(-4..4).step(1)")).should == [2, 3, 4]
+ @array.send(@method, eval("(-4...4).step(1)")).should == [2, 3]
+
+ @array.send(@method, eval("(-4..4).step(2)")).should == [2, 4]
+ @array.send(@method, eval("(-4...4).step(2)")).should == [2]
+
+ @array.send(@method, eval("(-4..4).step(10)")).should == [2]
+ @array.send(@method, eval("(-4...4).step(10)")).should == [2]
+
+ # start with negative index, end with negative index
+ @array.send(@method, eval("(-4..-2).step(1)")).should == [2, 3, 4]
+ @array.send(@method, eval("(-4...-2).step(1)")).should == [2, 3]
+
+ @array.send(@method, eval("(-4..-2).step(2)")).should == [2, 4]
+ @array.send(@method, eval("(-4...-2).step(2)")).should == [2]
+
+ @array.send(@method, eval("(-4..-2).step(10)")).should == [2]
+ @array.send(@method, eval("(-4...-2).step(10)")).should == [2]
+ end
+
+ it "has closed range and negative steps" do
+ # start and end with 0
+ @array.send(@method, eval("(0..0).step(-1)")).should == [0]
+ @array.send(@method, eval("(0...0).step(-1)")).should == []
+
+ @array.send(@method, eval("(0..0).step(-2)")).should == [0]
+ @array.send(@method, eval("(0...0).step(-2)")).should == []
+
+ @array.send(@method, eval("(0..0).step(-10)")).should == [0]
+ @array.send(@method, eval("(0...0).step(-10)")).should == []
+
+ # start and end with positive index
+ @array.send(@method, eval("(1..3).step(-1)")).should == []
+ @array.send(@method, eval("(1...3).step(-1)")).should == []
+
+ @array.send(@method, eval("(1..3).step(-2)")).should == []
+ @array.send(@method, eval("(1...3).step(-2)")).should == []
+
+ @array.send(@method, eval("(1..3).step(-10)")).should == []
+ @array.send(@method, eval("(1...3).step(-10)")).should == []
+
+ # start with positive index, end with negative index
+ @array.send(@method, eval("(1..-2).step(-1)")).should == []
+ @array.send(@method, eval("(1...-2).step(-1)")).should == []
+
+ @array.send(@method, eval("(1..-2).step(-2)")).should == []
+ @array.send(@method, eval("(1...-2).step(-2)")).should == []
+
+ @array.send(@method, eval("(1..-2).step(-10)")).should == []
+ @array.send(@method, eval("(1...-2).step(-10)")).should == []
+
+ # start with negative index, end with positive index
+ @array.send(@method, eval("(-4..4).step(-1)")).should == []
+ @array.send(@method, eval("(-4...4).step(-1)")).should == []
+
+ @array.send(@method, eval("(-4..4).step(-2)")).should == []
+ @array.send(@method, eval("(-4...4).step(-2)")).should == []
+
+ @array.send(@method, eval("(-4..4).step(-10)")).should == []
+ @array.send(@method, eval("(-4...4).step(-10)")).should == []
+
+ # start with negative index, end with negative index
+ @array.send(@method, eval("(-4..-2).step(-1)")).should == []
+ @array.send(@method, eval("(-4...-2).step(-1)")).should == []
+
+ @array.send(@method, eval("(-4..-2).step(-2)")).should == []
+ @array.send(@method, eval("(-4...-2).step(-2)")).should == []
+
+ @array.send(@method, eval("(-4..-2).step(-10)")).should == []
+ @array.send(@method, eval("(-4...-2).step(-10)")).should == []
+ end
+
+ it "has inverted closed range and positive steps" do
+ # start and end with positive index
+ @array.send(@method, eval("(3..1).step(1)")).should == []
+ @array.send(@method, eval("(3...1).step(1)")).should == []
+
+ @array.send(@method, eval("(3..1).step(2)")).should == []
+ @array.send(@method, eval("(3...1).step(2)")).should == []
+
+ @array.send(@method, eval("(3..1).step(10)")).should == []
+ @array.send(@method, eval("(3...1).step(10)")).should == []
+
+ # start with negative index, end with positive index
+ @array.send(@method, eval("(-2..1).step(1)")).should == []
+ @array.send(@method, eval("(-2...1).step(1)")).should == []
+
+ @array.send(@method, eval("(-2..1).step(2)")).should == []
+ @array.send(@method, eval("(-2...1).step(2)")).should == []
+
+ @array.send(@method, eval("(-2..1).step(10)")).should == []
+ @array.send(@method, eval("(-2...1).step(10)")).should == []
+
+ # start with positive index, end with negative index
+ @array.send(@method, eval("(4..-4).step(1)")).should == []
+ @array.send(@method, eval("(4...-4).step(1)")).should == []
+
+ @array.send(@method, eval("(4..-4).step(2)")).should == []
+ @array.send(@method, eval("(4...-4).step(2)")).should == []
+
+ @array.send(@method, eval("(4..-4).step(10)")).should == []
+ @array.send(@method, eval("(4...-4).step(10)")).should == []
+
+ # start with negative index, end with negative index
+ @array.send(@method, eval("(-2..-4).step(1)")).should == []
+ @array.send(@method, eval("(-2...-4).step(1)")).should == []
+
+ @array.send(@method, eval("(-2..-4).step(2)")).should == []
+ @array.send(@method, eval("(-2...-4).step(2)")).should == []
+
+ @array.send(@method, eval("(-2..-4).step(10)")).should == []
+ @array.send(@method, eval("(-2...-4).step(10)")).should == []
+ end
+ end
+ end
+
ruby_version_is "2.7" do
it "can accept beginless ranges" do
a = [0, 1, 2, 3, 4, 5]
diff --git a/spec/ruby/core/binding/eval_spec.rb b/spec/ruby/core/binding/eval_spec.rb
index b36bec799e..4bb3da7a6c 100644
--- a/spec/ruby/core/binding/eval_spec.rb
+++ b/spec/ruby/core/binding/eval_spec.rb
@@ -93,16 +93,28 @@ describe "Binding#eval" do
it "inherits __FILE__ from the enclosing scope" do
obj = BindingSpecs::Demo.new(1)
bind = obj.get_binding
- suppress_warning {bind.eval("__FILE__")}.should == obj.get_file_of_binding
+ suppress_warning { bind.eval("__FILE__") }.should == obj.get_file_of_binding
+ end
+
+ it "inherits __LINE__ from the enclosing scope" do
+ obj = BindingSpecs::Demo.new(1)
+ bind, line = obj.get_binding_and_line
+ suppress_warning { bind.eval("__LINE__") }.should == line
end
end
ruby_version_is "3.0" do
- it "Uses (eval) as __FILE__ if single argument given" do
+ it "uses (eval) as __FILE__ if single argument given" do
obj = BindingSpecs::Demo.new(1)
bind = obj.get_binding
bind.eval("__FILE__").should == '(eval)'
end
+
+ it "uses 1 as __LINE__" do
+ obj = BindingSpecs::Demo.new(1)
+ bind = obj.get_binding
+ suppress_warning { bind.eval("__LINE__") }.should == 1
+ end
end
it "uses the __FILE__ that is passed in" do
diff --git a/spec/ruby/core/conditionvariable/broadcast_spec.rb b/spec/ruby/core/conditionvariable/broadcast_spec.rb
new file mode 100644
index 0000000000..d88159df23
--- /dev/null
+++ b/spec/ruby/core/conditionvariable/broadcast_spec.rb
@@ -0,0 +1,40 @@
+require_relative '../../spec_helper'
+require 'thread'
+
+describe "ConditionVariable#broadcast" do
+ it "releases all threads waiting in line for this resource" do
+ m = Mutex.new
+ cv = ConditionVariable.new
+ threads = []
+ r1 = []
+ r2 = []
+
+ # large number to attempt to cause race conditions
+ 100.times do |i|
+ threads << Thread.new(i) do |tid|
+ m.synchronize do
+ r1 << tid
+ cv.wait(m)
+ r2 << tid
+ end
+ end
+ end
+
+ # wait for all threads to acquire the mutex the first time
+ Thread.pass until m.synchronize { r1.size == threads.size }
+ # wait until all threads are sleeping (ie waiting)
+ Thread.pass until threads.all?(&:stop?)
+
+ r2.should be_empty
+ m.synchronize do
+ cv.broadcast
+ end
+
+ threads.each {|t| t.join }
+
+ # ensure that all threads that enter cv.wait are released
+ r2.sort.should == r1.sort
+ # note that order is not specified as broadcast results in a race
+ # condition on regaining the lock m
+ end
+end
diff --git a/spec/ruby/core/conditionvariable/marshal_dump_spec.rb b/spec/ruby/core/conditionvariable/marshal_dump_spec.rb
new file mode 100644
index 0000000000..f951a13e28
--- /dev/null
+++ b/spec/ruby/core/conditionvariable/marshal_dump_spec.rb
@@ -0,0 +1,9 @@
+require_relative '../../spec_helper'
+require 'thread'
+
+describe "ConditionVariable#marshal_dump" do
+ it "raises a TypeError" do
+ cv = ConditionVariable.new
+ -> { cv.marshal_dump }.should raise_error(TypeError, /can't dump/)
+ end
+end
diff --git a/spec/ruby/core/conditionvariable/signal_spec.rb b/spec/ruby/core/conditionvariable/signal_spec.rb
new file mode 100644
index 0000000000..86383073f1
--- /dev/null
+++ b/spec/ruby/core/conditionvariable/signal_spec.rb
@@ -0,0 +1,77 @@
+require_relative '../../spec_helper'
+require 'thread'
+
+describe "ConditionVariable#signal" do
+ it "releases the first thread waiting in line for this resource" do
+ m = Mutex.new
+ cv = ConditionVariable.new
+ threads = []
+ r1 = []
+ r2 = []
+
+ # large number to attempt to cause race conditions
+ 100.times do |i|
+ threads << Thread.new(i) do |tid|
+ m.synchronize do
+ r1 << tid
+ cv.wait(m)
+ r2 << tid
+ end
+ end
+ end
+
+ # wait for all threads to acquire the mutex the first time
+ Thread.pass until m.synchronize { r1.size == threads.size }
+ # wait until all threads are sleeping (ie waiting)
+ Thread.pass until threads.all?(&:stop?)
+
+ r2.should be_empty
+ 100.times do |i|
+ m.synchronize do
+ cv.signal
+ end
+ Thread.pass until r2.size == i+1
+ end
+
+ threads.each {|t| t.join }
+
+ # ensure that all the threads that went into the cv.wait are
+ # released in the same order
+ r2.should == r1
+ end
+
+ it "allows control to be passed between a pair of threads" do
+ m = Mutex.new
+ cv = ConditionVariable.new
+ repeats = 100
+ in_synchronize = false
+
+ t1 = Thread.new do
+ m.synchronize do
+ in_synchronize = true
+ repeats.times do
+ cv.wait(m)
+ cv.signal
+ end
+ end
+ end
+
+ # Make sure t1 is waiting for a signal before launching t2.
+ Thread.pass until in_synchronize
+ Thread.pass until t1.stop?
+
+ t2 = Thread.new do
+ m.synchronize do
+ repeats.times do
+ cv.signal
+ cv.wait(m)
+ end
+ end
+ end
+
+ # Check that both threads terminated without exception
+ t1.join
+ t2.join
+ m.should_not.locked?
+ end
+end
diff --git a/spec/ruby/core/conditionvariable/wait_spec.rb b/spec/ruby/core/conditionvariable/wait_spec.rb
new file mode 100644
index 0000000000..9a68c2b5a1
--- /dev/null
+++ b/spec/ruby/core/conditionvariable/wait_spec.rb
@@ -0,0 +1,175 @@
+require_relative '../../spec_helper'
+require 'thread'
+
+describe "ConditionVariable#wait" do
+ it "calls #sleep on the given object" do
+ o = Object.new
+ o.should_receive(:sleep).with(1234)
+
+ cv = ConditionVariable.new
+
+ cv.wait(o, 1234)
+ end
+
+ it "can be woken up by ConditionVariable#signal" do
+ m = Mutex.new
+ cv = ConditionVariable.new
+ in_synchronize = false
+
+ th = Thread.new do
+ m.synchronize do
+ in_synchronize = true
+ cv.wait(m)
+ end
+ :success
+ end
+
+ # wait for m to acquire the mutex
+ Thread.pass until in_synchronize
+ # wait until th is sleeping (ie waiting)
+ Thread.pass until th.stop?
+
+ m.synchronize { cv.signal }
+ th.value.should == :success
+ end
+
+ it "can be interrupted by Thread#run" do
+ m = Mutex.new
+ cv = ConditionVariable.new
+ in_synchronize = false
+
+ th = Thread.new do
+ m.synchronize do
+ in_synchronize = true
+ cv.wait(m)
+ end
+ :success
+ end
+
+ # wait for m to acquire the mutex
+ Thread.pass until in_synchronize
+ # wait until th is sleeping (ie waiting)
+ Thread.pass until th.stop?
+
+ th.run
+ th.value.should == :success
+ end
+
+ it "can be interrupted by Thread#wakeup" do
+ m = Mutex.new
+ cv = ConditionVariable.new
+ in_synchronize = false
+
+ th = Thread.new do
+ m.synchronize do
+ in_synchronize = true
+ cv.wait(m)
+ end
+ :success
+ end
+
+ # wait for m to acquire the mutex
+ Thread.pass until in_synchronize
+ # wait until th is sleeping (ie waiting)
+ Thread.pass until th.stop?
+
+ th.wakeup
+ th.value.should == :success
+ end
+
+ it "reacquires the lock even if the thread is killed" do
+ m = Mutex.new
+ cv = ConditionVariable.new
+ in_synchronize = false
+ owned = nil
+
+ th = Thread.new do
+ m.synchronize do
+ in_synchronize = true
+ begin
+ cv.wait(m)
+ ensure
+ owned = m.owned?
+ $stderr.puts "\nThe Thread doesn't own the Mutex!" unless owned
+ end
+ end
+ end
+
+ # wait for m to acquire the mutex
+ Thread.pass until in_synchronize
+ # wait until th is sleeping (ie waiting)
+ Thread.pass until th.stop?
+
+ th.kill
+ th.join
+
+ owned.should == true
+ end
+
+ it "reacquires the lock even if the thread is killed after being signaled" do
+ m = Mutex.new
+ cv = ConditionVariable.new
+ in_synchronize = false
+ owned = nil
+
+ th = Thread.new do
+ m.synchronize do
+ in_synchronize = true
+ begin
+ cv.wait(m)
+ ensure
+ owned = m.owned?
+ $stderr.puts "\nThe Thread doesn't own the Mutex!" unless owned
+ end
+ end
+ end
+
+ # wait for m to acquire the mutex
+ Thread.pass until in_synchronize
+ # wait until th is sleeping (ie waiting)
+ Thread.pass until th.stop?
+
+ m.synchronize {
+ cv.signal
+ # Wait that the thread is blocked on acquiring the Mutex
+ sleep 0.001
+ # Kill the thread, yet the thread should first acquire the Mutex before going on
+ th.kill
+ }
+
+ th.join
+ owned.should == true
+ end
+
+ it "supports multiple Threads waiting on the same ConditionVariable and Mutex" do
+ m = Mutex.new
+ cv = ConditionVariable.new
+ n_threads = 4
+ events = []
+
+ threads = n_threads.times.map {
+ Thread.new {
+ m.synchronize {
+ events << :t_in_synchronize
+ cv.wait(m)
+ }
+ }
+ }
+
+ Thread.pass until m.synchronize { events.size } == n_threads
+ Thread.pass until threads.any?(&:stop?)
+ m.synchronize do
+ threads.each { |t|
+ # Cause interactions with the waiting threads.
+ # On TruffleRuby, this causes a safepoint which has interesting
+ # interactions with the ConditionVariable.
+ bt = t.backtrace
+ bt.should be_kind_of(Array)
+ bt.size.should >= 2
+ }
+ end
+
+ cv.broadcast
+ threads.each(&:join)
+ end
+end
diff --git a/spec/ruby/core/dir/shared/glob.rb b/spec/ruby/core/dir/shared/glob.rb
index d2824df446..173038ee24 100644
--- a/spec/ruby/core/dir/shared/glob.rb
+++ b/spec/ruby/core/dir/shared/glob.rb
@@ -38,6 +38,23 @@ describe :dir_glob, shared: true do
end
end
+ ruby_version_is "3.0" do
+ it "result is sorted by default" do
+ result = Dir.send(@method, '*')
+ result.should == result.sort
+ end
+
+ it "result is sorted with sort: true" do
+ result = Dir.send(@method, '*', sort: true)
+ result.should == result.sort
+ end
+
+ it "sort: false returns same files" do
+ result = Dir.send(@method,'*', sort: false)
+ result.sort.should == Dir.send(@method, '*').sort
+ end
+ end
+
it "matches non-dotfiles with '*'" do
expected = %w[
brace
diff --git a/spec/ruby/core/env/shift_spec.rb b/spec/ruby/core/env/shift_spec.rb
index 8717b7220e..1b92e5d1e4 100644
--- a/spec/ruby/core/env/shift_spec.rb
+++ b/spec/ruby/core/env/shift_spec.rb
@@ -2,36 +2,13 @@ require_relative '../../spec_helper'
require_relative 'fixtures/common'
describe "ENV.shift" do
- it "returns a pair and deletes it" do
- ENV.should_not.empty?
- orig = ENV.to_hash
- begin
- pair = ENV.shift
- ENV.has_key?(pair.first).should == false
- ensure
- ENV.replace orig
- end
- ENV.has_key?(pair.first).should == true
- end
-
- it "returns nil if ENV.empty?" do
- orig = ENV.to_hash
- begin
- ENV.clear
- ENV.shift.should == nil
- ensure
- ENV.replace orig
- end
- end
-end
-
-describe "ENV.shift" do
before :each do
@orig = ENV.to_hash
@external = Encoding.default_external
@internal = Encoding.default_internal
Encoding.default_external = Encoding::BINARY
+ ENV.replace({"FOO"=>"BAR"})
end
after :each do
@@ -40,6 +17,18 @@ describe "ENV.shift" do
ENV.replace @orig
end
+ it "returns a pair and deletes it" do
+ ENV.should.has_key?("FOO")
+ pair = ENV.shift
+ pair.should == ["FOO", "BAR"]
+ ENV.should_not.has_key?("FOO")
+ end
+
+ it "returns nil if ENV.empty?" do
+ ENV.clear
+ ENV.shift.should == nil
+ end
+
it "uses the locale encoding if Encoding.default_internal is nil" do
Encoding.default_internal = nil
@@ -52,9 +41,7 @@ describe "ENV.shift" do
Encoding.default_internal = Encoding::IBM437
pair = ENV.shift
- pair.first.encode(Encoding::IBM437) rescue next
pair.first.encoding.should equal(Encoding::IBM437)
- pair.last.encode(Encoding::IBM437) rescue next
pair.last.encoding.should equal(Encoding::IBM437)
end
end
diff --git a/spec/ruby/core/file/utime_spec.rb b/spec/ruby/core/file/utime_spec.rb
index 59eef20c66..45a51490e4 100644
--- a/spec/ruby/core/file/utime_spec.rb
+++ b/spec/ruby/core/file/utime_spec.rb
@@ -70,11 +70,13 @@ describe "File.utime" do
end
end
- it "may set nanosecond precision" do
- t = Time.utc(2007, 11, 1, 15, 25, 0, 123456.789r)
- File.utime(t, t, @file1)
- File.atime(@file1).nsec.should.between?(0, 123500000)
- File.mtime(@file1).nsec.should.between?(0, 123500000)
+ platform_is_not :windows do
+ it "sets nanosecond precision" do
+ t = Time.utc(2007, 11, 1, 15, 25, 0, 123456.789r)
+ File.utime(t, t, @file1)
+ File.atime(@file1).nsec.should == 123456789
+ File.mtime(@file1).nsec.should == 123456789
+ end
end
platform_is :linux do
diff --git a/spec/ruby/core/float/comparison_spec.rb b/spec/ruby/core/float/comparison_spec.rb
index a46841ffbf..53e7ec332a 100644
--- a/spec/ruby/core/float/comparison_spec.rb
+++ b/spec/ruby/core/float/comparison_spec.rb
@@ -90,4 +90,19 @@ describe "Float#<=>" do
end
(infinity_value <=> obj).should == 1
end
+
+ it "returns 0 for -0.0 and 0.0" do
+ (-0.0 <=> 0.0).should == 0
+ (0.0 <=> -0.0).should == 0
+ end
+
+ it "returns 0 for -0.0 and 0" do
+ (-0.0 <=> 0).should == 0
+ (0 <=> -0.0).should == 0
+ end
+
+ it "returns 0 for 0.0 and 0" do
+ (0.0 <=> 0).should == 0
+ (0 <=> 0.0).should == 0
+ end
end
diff --git a/spec/ruby/core/hash/transform_keys_spec.rb b/spec/ruby/core/hash/transform_keys_spec.rb
index 70a4cdde36..8ee1a2cd6d 100644
--- a/spec/ruby/core/hash/transform_keys_spec.rb
+++ b/spec/ruby/core/hash/transform_keys_spec.rb
@@ -42,6 +42,20 @@ describe "Hash#transform_keys" do
r.keys.should == [:xfoo]
r.class.should == Hash
end
+
+ ruby_version_is "3.0" do
+ it "allows a hash argument" do
+ @hash.transform_keys({ a: :A, b: :B, c: :C }).should == { A: 1, B: 2, C: 3 }
+ end
+
+ it "allows a partial transformation of keys when using a hash argument" do
+ @hash.transform_keys({ a: :A, c: :C }).should == { A: 1, b: 2, C: 3 }
+ end
+
+ it "allows a combination of hash and block argument" do
+ @hash.transform_keys({ a: :A }, &:to_s).should == { A: 1, 'b' => 2, 'c' => 3 }
+ end
+ end
end
describe "Hash#transform_keys!" do
@@ -98,6 +112,13 @@ describe "Hash#transform_keys!" do
end
end
+ ruby_version_is "3.0" do
+ it "allows a hash argument" do
+ @hash.transform_keys!({ a: :A, b: :B, c: :C, d: :D })
+ @hash.should == { A: 1, B: 2, C: 3, D: 4 }
+ end
+ end
+
describe "on frozen instance" do
before :each do
@hash.freeze
@@ -112,6 +133,12 @@ describe "Hash#transform_keys!" do
@hash.should == @initial_pairs
end
+ ruby_version_is "3.0" do
+ it "raises a FrozenError on hash argument" do
+ ->{ @hash.transform_keys!({ a: :A, b: :B, c: :C }) }.should raise_error(FrozenError)
+ end
+ end
+
context "when no block is given" do
it "does not raise an exception" do
@hash.transform_keys!.should be_an_instance_of(Enumerator)
diff --git a/spec/ruby/core/integer/zero_spec.rb b/spec/ruby/core/integer/zero_spec.rb
new file mode 100644
index 0000000000..2dac50c406
--- /dev/null
+++ b/spec/ruby/core/integer/zero_spec.rb
@@ -0,0 +1,21 @@
+require_relative '../../spec_helper'
+
+describe "Integer#zero?" do
+ it "returns true if self is 0" do
+ 0.should.zero?
+ 1.should_not.zero?
+ -1.should_not.zero?
+ end
+
+ ruby_version_is "3.0" do
+ it "Integer#zero? overrides Numeric#zero?" do
+ 42.method(:zero?).owner.should == Integer
+ end
+ end
+
+ ruby_version_is ""..."3.0" do
+ it "Integer#zero? uses Numeric#zero?" do
+ 42.method(:zero?).owner.should == Numeric
+ end
+ end
+end
diff --git a/spec/ruby/core/kernel/clone_spec.rb b/spec/ruby/core/kernel/clone_spec.rb
index c18af4a490..f9daa2badc 100644
--- a/spec/ruby/core/kernel/clone_spec.rb
+++ b/spec/ruby/core/kernel/clone_spec.rb
@@ -28,27 +28,88 @@ describe "Kernel#clone" do
clone.class.should equal klass
end
- it "copies frozen state from the original" do
- o2 = @obj.clone
- @obj.freeze
- o3 = @obj.clone
+ describe "with no arguments" do
+ it "copies frozen state from the original" do
+ o2 = @obj.clone
+ @obj.freeze
+ o3 = @obj.clone
+
+ o2.should_not.frozen?
+ o3.should.frozen?
+ end
- o2.should_not.frozen?
- o3.should.frozen?
+ it 'copies frozen?' do
+ o = ''.freeze.clone
+ o.frozen?.should be_true
+ end
end
- ruby_version_is '3.0' do
- it 'takes an freeze: true option to frozen copy' do
- @obj.clone(freeze: true).should.frozen?
+ describe "with freeze: true" do
+ it 'makes a frozen copy if the original is frozen' do
@obj.freeze
@obj.clone(freeze: true).should.frozen?
end
+
+ ruby_version_is ''...'3.0' do
+ it 'does not freeze the copy even if the original is not frozen' do
+ @obj.clone(freeze: true).should_not.frozen?
+ end
+
+ it "calls #initialize_clone with no kwargs" do
+ obj = KernelSpecs::CloneFreeze.new
+ obj.clone(freeze: true)
+ ScratchPad.recorded.should == [obj, {}]
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it 'freezes the copy even if the original was not frozen' do
+ @obj.clone(freeze: true).should.frozen?
+ end
+
+ it "calls #initialize_clone with kwargs freeze: true" do
+ obj = KernelSpecs::CloneFreeze.new
+ obj.clone(freeze: true)
+ ScratchPad.recorded.should == [obj, { freeze: true }]
+ end
+
+ it "calls #initialize_clone with kwargs freeze: true even if #initialize_clone only takes a single argument" do
+ obj = KernelSpecs::Clone.new
+ -> { obj.clone(freeze: true) }.should raise_error(ArgumentError, 'wrong number of arguments (given 2, expected 1)')
+ end
+ end
end
- it 'takes an freeze: false option to not return frozen copy' do
- @obj.clone(freeze: false).should_not.frozen?
- @obj.freeze
- @obj.clone(freeze: false).should_not.frozen?
+ describe "with freeze: false" do
+ it 'does not freeze the copy if the original is frozen' do
+ @obj.freeze
+ @obj.clone(freeze: false).should_not.frozen?
+ end
+
+ it 'does not freeze the copy if the original is not frozen' do
+ @obj.clone(freeze: false).should_not.frozen?
+ end
+
+ ruby_version_is ''...'3.0' do
+ it "calls #initialize_clone with no kwargs" do
+ obj = KernelSpecs::CloneFreeze.new
+ obj.clone(freeze: false)
+ ScratchPad.recorded.should == [obj, {}]
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it "calls #initialize_clone with kwargs freeze: false" do
+ obj = KernelSpecs::CloneFreeze.new
+ obj.clone(freeze: false)
+ ScratchPad.recorded.should == [obj, { freeze: false }]
+ end
+
+ it "calls #initialize_clone with kwargs freeze: false even if #initialize_clone only takes a single argument" do
+ obj = KernelSpecs::Clone.new
+ -> { obj.clone(freeze: false) }.should raise_error(ArgumentError, 'wrong number of arguments (given 2, expected 1)')
+ end
+ end
end
it "copies instance variables" do
@@ -114,11 +175,6 @@ describe "Kernel#clone" do
cloned.bar.should == ['a']
end
- it 'copies frozen?' do
- o = ''.freeze.clone
- o.frozen?.should be_true
- end
-
ruby_version_is ''...'2.7' do
it 'copies tainted?' do
o = ''.taint.clone
diff --git a/spec/ruby/core/kernel/eval_spec.rb b/spec/ruby/core/kernel/eval_spec.rb
index 1e2764a4de..9be0f2dfd3 100644
--- a/spec/ruby/core/kernel/eval_spec.rb
+++ b/spec/ruby/core/kernel/eval_spec.rb
@@ -168,6 +168,12 @@ describe "Kernel#eval" do
suppress_warning {eval("eval '__FILE__', binding", binding)}.should == __FILE__
suppress_warning {eval("eval '__FILE__', binding", binding, 'success')}.should == 'success'
end
+
+ it 'uses the given binding file and line for __FILE__ and __LINE__' do
+ suppress_warning {
+ eval("[__FILE__, __LINE__]", binding).should == [__FILE__, __LINE__]
+ }
+ end
end
ruby_version_is "3.0" do
@@ -180,6 +186,10 @@ describe "Kernel#eval" do
eval("eval '__FILE__', binding", binding, 'success').should == '(eval)'
eval("eval '__FILE__', binding, 'success'", binding).should == 'success'
end
+
+ it 'uses (eval) for __FILE__ and 1 for __LINE__ with a binding argument' do
+ eval("[__FILE__, __LINE__]", binding).should == ["(eval)", 1]
+ end
end
# Found via Rubinius bug github:#149
diff --git a/spec/ruby/core/kernel/fixtures/classes.rb b/spec/ruby/core/kernel/fixtures/classes.rb
index 1bf5715c50..8de1407b92 100644
--- a/spec/ruby/core/kernel/fixtures/classes.rb
+++ b/spec/ruby/core/kernel/fixtures/classes.rb
@@ -288,7 +288,13 @@ module KernelSpecs
class Clone
def initialize_clone(other)
- ScratchPad.record other.object_id
+ ScratchPad.record other
+ end
+ end
+
+ class CloneFreeze
+ def initialize_clone(other, **kwargs)
+ ScratchPad.record([other, kwargs])
end
end
diff --git a/spec/ruby/core/module/autoload_spec.rb b/spec/ruby/core/module/autoload_spec.rb
index 1d61646db5..f17675846b 100644
--- a/spec/ruby/core/module/autoload_spec.rb
+++ b/spec/ruby/core/module/autoload_spec.rb
@@ -441,42 +441,21 @@ describe "Module#autoload" do
ScratchPad.recorded.should == [:raise, :raise]
end
- ruby_version_is "3.1" do
- it "removes the constant from Module#constants if the loaded file does not define it" do
- path = fixture(__FILE__, "autoload_o.rb")
- ScratchPad.record []
- ModuleSpecs::Autoload.autoload :O, path
-
- ModuleSpecs::Autoload.const_defined?(:O).should == true
- ModuleSpecs::Autoload.should have_constant(:O)
- ModuleSpecs::Autoload.autoload?(:O).should == path
-
- -> { ModuleSpecs::Autoload::O }.should raise_error(NameError)
-
- ModuleSpecs::Autoload.const_defined?(:O).should == false
- ModuleSpecs::Autoload.should_not have_constant(:O)
- ModuleSpecs::Autoload.autoload?(:O).should == nil
- -> { ModuleSpecs::Autoload.const_get(:O) }.should raise_error(NameError)
- end
- end
-
- ruby_version_is ""..."3.1" do
- it "does not remove the constant from Module#constants if the loaded file does not define it, but leaves it as 'undefined'" do
- path = fixture(__FILE__, "autoload_o.rb")
- ScratchPad.record []
- ModuleSpecs::Autoload.autoload :O, path
+ it "does not remove the constant from Module#constants if the loaded file does not define it, but leaves it as 'undefined'" do
+ path = fixture(__FILE__, "autoload_o.rb")
+ ScratchPad.record []
+ ModuleSpecs::Autoload.autoload :O, path
- ModuleSpecs::Autoload.const_defined?(:O).should == true
- ModuleSpecs::Autoload.should have_constant(:O)
- ModuleSpecs::Autoload.autoload?(:O).should == path
+ ModuleSpecs::Autoload.const_defined?(:O).should == true
+ ModuleSpecs::Autoload.should have_constant(:O)
+ ModuleSpecs::Autoload.autoload?(:O).should == path
- -> { ModuleSpecs::Autoload::O }.should raise_error(NameError)
+ -> { ModuleSpecs::Autoload::O }.should raise_error(NameError)
- ModuleSpecs::Autoload.const_defined?(:O).should == false
- ModuleSpecs::Autoload.should have_constant(:O)
- ModuleSpecs::Autoload.autoload?(:O).should == nil
- -> { ModuleSpecs::Autoload.const_get(:O) }.should raise_error(NameError)
- end
+ ModuleSpecs::Autoload.should have_constant(:O)
+ ModuleSpecs::Autoload.const_defined?(:O).should == false
+ ModuleSpecs::Autoload.autoload?(:O).should == nil
+ -> { ModuleSpecs::Autoload.const_get(:O) }.should raise_error(NameError)
end
it "does not try to load the file again if the loaded file did not define the constant" do
@@ -575,54 +554,31 @@ describe "Module#autoload" do
# Basically, the parent autoload constant remains in a "undefined" state
self.autoload?(:DeclaredInParentDefinedInCurrent).should == nil
const_defined?(:DeclaredInParentDefinedInCurrent).should == false
+ self.should have_constant(:DeclaredInParentDefinedInCurrent)
-> { DeclaredInParentDefinedInCurrent }.should raise_error(NameError)
ModuleSpecs::Autoload::LexicalScope.send(:remove_const, :DeclaredInParentDefinedInCurrent)
end
end
- ruby_version_is "3.1" do
- it "looks up in parent scope after failed autoload" do
- @remove << :DeclaredInCurrentDefinedInParent
- module ModuleSpecs::Autoload
- ScratchPad.record -> {
- DeclaredInCurrentDefinedInParent = :declared_in_current_defined_in_parent
- }
-
- class LexicalScope
- autoload :DeclaredInCurrentDefinedInParent, fixture(__FILE__, "autoload_callback.rb")
- -> { DeclaredInCurrentDefinedInParent }.should_not raise_error(NameError)
- # Basically, the autoload constant remains in a "undefined" state
- self.autoload?(:DeclaredInCurrentDefinedInParent).should == nil
- const_defined?(:DeclaredInCurrentDefinedInParent).should == false
- -> { const_get(:DeclaredInCurrentDefinedInParent) }.should raise_error(NameError)
- end
+ it "and fails when finding the undefined autoload constant in the current scope when declared in current and defined in parent" do
+ @remove << :DeclaredInCurrentDefinedInParent
+ module ModuleSpecs::Autoload
+ ScratchPad.record -> {
+ DeclaredInCurrentDefinedInParent = :declared_in_current_defined_in_parent
+ }
- DeclaredInCurrentDefinedInParent.should == :declared_in_current_defined_in_parent
+ class LexicalScope
+ autoload :DeclaredInCurrentDefinedInParent, fixture(__FILE__, "autoload_callback.rb")
+ -> { DeclaredInCurrentDefinedInParent }.should raise_error(NameError)
+ # Basically, the autoload constant remains in a "undefined" state
+ self.autoload?(:DeclaredInCurrentDefinedInParent).should == nil
+ const_defined?(:DeclaredInCurrentDefinedInParent).should == false
+ self.should have_constant(:DeclaredInCurrentDefinedInParent)
+ -> { const_get(:DeclaredInCurrentDefinedInParent) }.should raise_error(NameError)
end
- end
- end
-
- ruby_version_is ""..."3.1" do
- it "and fails when finding the undefined autoload constant in the current scope when declared in current and defined in parent" do
- @remove << :DeclaredInCurrentDefinedInParent
- module ModuleSpecs::Autoload
- ScratchPad.record -> {
- DeclaredInCurrentDefinedInParent = :declared_in_current_defined_in_parent
- }
-
- class LexicalScope
- autoload :DeclaredInCurrentDefinedInParent, fixture(__FILE__, "autoload_callback.rb")
- -> { DeclaredInCurrentDefinedInParent }.should raise_error(NameError)
- # Basically, the autoload constant remains in a "undefined" state
- self.autoload?(:DeclaredInCurrentDefinedInParent).should == nil
- const_defined?(:DeclaredInCurrentDefinedInParent).should == false
- self.should have_constant(:DeclaredInCurrentDefinedInParent)
- -> { const_get(:DeclaredInCurrentDefinedInParent) }.should raise_error(NameError)
- end
- DeclaredInCurrentDefinedInParent.should == :declared_in_current_defined_in_parent
- end
+ DeclaredInCurrentDefinedInParent.should == :declared_in_current_defined_in_parent
end
end
diff --git a/spec/ruby/core/module/const_set_spec.rb b/spec/ruby/core/module/const_set_spec.rb
index ba7810d17b..b537d3f133 100644
--- a/spec/ruby/core/module/const_set_spec.rb
+++ b/spec/ruby/core/module/const_set_spec.rb
@@ -101,7 +101,7 @@ describe "Module#const_set" do
mod.const_get(:Foo).should == 1
end
- it "does not warn after a failed autoload" do
+ it "does not warn if the previous value was undefined" do
path = fixture(__FILE__, "autoload_o.rb")
ScratchPad.record []
mod = Module.new
@@ -109,6 +109,7 @@ describe "Module#const_set" do
mod.autoload :Foo, path
-> { mod::Foo }.should raise_error(NameError)
+ mod.should have_constant(:Foo)
mod.const_defined?(:Foo).should == false
mod.autoload?(:Foo).should == nil
diff --git a/spec/ruby/core/module/constants_spec.rb b/spec/ruby/core/module/constants_spec.rb
index fe95143872..330da1cc88 100644
--- a/spec/ruby/core/module/constants_spec.rb
+++ b/spec/ruby/core/module/constants_spec.rb
@@ -74,6 +74,12 @@ describe "Module#constants" do
it "returns only public constants" do
ModuleSpecs::PrivConstModule.constants.should == [:PUBLIC_CONSTANT]
end
+
+ it "returns only constants starting with an uppercase letter" do
+ # e.g. fatal, IO::generic_readable and IO::generic_writable should not be returned by Module#constants
+ Object.constants.each { |c| c[0].should == c[0].upcase }
+ IO.constants.each { |c| c[0].should == c[0].upcase }
+ end
end
describe "Module#constants" do
diff --git a/spec/ruby/core/range/each_spec.rb b/spec/ruby/core/range/each_spec.rb
index bd4bbb82e5..6b33f57737 100644
--- a/spec/ruby/core/range/each_spec.rb
+++ b/spec/ruby/core/range/each_spec.rb
@@ -84,9 +84,27 @@ describe "Range#each" do
enum.to_a.should == [1, 2, 3]
end
- it "raises a TypeError if the first element is a Time object" do
- t = Time.now
- -> { (t..t+1).each { |i| i } }.should raise_error(TypeError)
+ ruby_version_is "3.1" do
+ it "supports Time objects that respond to #succ" do
+ t = Time.utc(1970)
+ def t.succ; self + 1 end
+ t_succ = t.succ
+ def t_succ.succ; self + 1; end
+
+ (t..t_succ).to_a.should == [Time.utc(1970), Time.utc(1970, nil, nil, nil, nil, 1)]
+ (t...t_succ).to_a.should == [Time.utc(1970)]
+ end
+ end
+
+ ruby_version_is ""..."3.1" do
+ it "raises a TypeError if the first element is a Time object even if it responds to #succ" do
+ t = Time.utc(1970)
+ def t.succ; self + 1 end
+ t_succ = t.succ
+ def t_succ.succ; self + 1; end
+
+ -> { (t..t_succ).each { |i| i } }.should raise_error(TypeError)
+ end
end
it "passes each Symbol element by using #succ" do