Skip to content

[GR-14806] Update ruby/spec #3824

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Apr 1, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions ci.jsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -312,9 +312,8 @@ local part_definitions = {
"CHECK_LEAKS": "true",
"RUBY_SPEC_TEST_ZLIB_CRC_TABLE": "false", # CRuby was built on OL6 and is used on OL7
},
run+: jt(["-u", "ruby", "mspec", "spec/ruby"]) +
jt(["-u", "/cm/shared/apps-ol7/ruby/3.1.2/bin/ruby", "mspec", "spec/ruby"]) +
jt(["-u", "/cm/shared/apps/ruby/3.0.2/bin/ruby", "mspec", "spec/ruby"]),
run+: jt(["-u", "ruby", "mspec", "spec/ruby"]) + # 3.2.2
jt(["-u", "/cm/shared/apps-ol7/ruby/3.1.2/bin/ruby", "mspec", "spec/ruby"]),
},

test_fast: {
Expand Down
19 changes: 19 additions & 0 deletions spec/mspec/tool/remove_old_guards.rb
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,6 +1,23 @@
#!/usr/bin/env ruby

# Removes old version guards in ruby/spec.
# Run it from the ruby/spec repository root.
# The argument is the new minimum supported version.
#
# cd spec
# ../mspec/tool/remove_old_guards.rb <ruby-version>
#
# where <ruby-version> is a version guard with which should be removed
#
# Example:
# tool/remove_old_guards.rb 3.1
#
# As a result guards like
# ruby_version_is "3.1" do
# # ...
# end
#
# will be removed.

def dedent(line)
if line.start_with?(" ")
Expand Down Expand Up @@ -105,6 +122,8 @@ def search(regexp)
end
end

abort "usage: #{$0} <ruby-version>" if ARGV.empty?

version = Regexp.escape(ARGV.fetch(0))
version += "(?:\\.0)?" if version.count(".") < 2
remove_guards(/ruby_version_is (["'])#{version}\1 do/, true)
Expand Down
5 changes: 3 additions & 2 deletions spec/ruby/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ ruby/spec is known to be tested in these implementations for every commit:
* [Opal](https://github.com/opal/opal/tree/master/spec)
* [Artichoke](https://github.com/artichoke/spec/tree/artichoke-vendor)

ruby/spec describes the behavior of Ruby 3.0 and more recent Ruby versions.
More precisely, every latest stable MRI release should [pass](https://github.com/ruby/spec/actions/workflows/ci.yml) all specs of ruby/spec (3.0.x, 3.1.x, 3.2.x, etc), and those are tested in CI.
ruby/spec describes the behavior of Ruby 3.1 and more recent Ruby versions.
More precisely, every latest stable MRI release should [pass](https://github.com/ruby/spec/actions/workflows/ci.yml) all specs of ruby/spec (3.1.x, 3.2.x, etc), and those are tested in CI.

### Synchronization with Ruby Implementations

Expand Down Expand Up @@ -62,6 +62,7 @@ For older specs try these commits:
* Ruby 2.5.9 - [Suite](https://github.com/ruby/spec/commit/c503335d3d9f6ec6ef24de60a0716c34af69b64f) using [MSpec](https://github.com/ruby/mspec/commit/0091e8a62e954717cd54641f935eaf1403692041)
* Ruby 2.6.10 - [Suite](https://github.com/ruby/spec/commit/aaf998fb8c92c4e63ad423a2e7ca6e6921818c6e) using [MSpec](https://github.com/ruby/mspec/commit/5e36c684e9e2b92b1187589bba1df22c640a8661)
* Ruby 2.7.8 - [Suite](https://github.com/ruby/spec/commit/93787e6035c925b593a9c0c6fb0e7e07a6f1df1f) using [MSpec](https://github.com/ruby/mspec/commit/1d8cf64722d8a7529f7cd205be5f16a89b7a67fd)
* Ruby 3.0.7 - [Suite](https://github.com/ruby/spec/commit/affef93d9940f615e4836f64b011da211f570913) using [MSpec](https://github.com/ruby/mspec/commit/0aabb3e548eb5ea6cad0125f8f46cee34542b6b7)

### Running the specs

Expand Down
24 changes: 12 additions & 12 deletions spec/ruby/command_line/dash_upper_u_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

describe "ruby -U" do
it "sets Encoding.default_internal to UTF-8" do
ruby_exe('print Encoding.default_internal.name',
options: '-U').should == 'UTF-8'
ruby_exe('print Encoding.default_internal.name',
options: '-U').should == 'UTF-8'
end

it "sets Encoding.default_internal to UTF-8 when RUBYOPT is empty or only spaces" do
Expand All @@ -14,25 +14,25 @@
end

it "does nothing different if specified multiple times" do
ruby_exe('print Encoding.default_internal.name',
options: '-U -U').should == 'UTF-8'
ruby_exe('print Encoding.default_internal.name',
options: '-U -U').should == 'UTF-8'
end

it "is overruled by Encoding.default_internal=" do
ruby_exe('Encoding.default_internal="ascii"; print Encoding.default_internal.name',
options: '-U').should == 'US-ASCII'
ruby_exe('Encoding.default_internal="ascii"; print Encoding.default_internal.name',
options: '-U').should == 'US-ASCII'
end

it "does not affect the default external encoding" do
ruby_exe('Encoding.default_external="ascii"; print Encoding.default_external.name',
options: '-U').should == 'US-ASCII'
ruby_exe('Encoding.default_external="ascii"; print Encoding.default_external.name',
options: '-U').should == 'US-ASCII'
end

it "does not affect the source encoding" do
ruby_exe("print __ENCODING__.name",
options: '-U -KE').should == 'EUC-JP'
ruby_exe("print __ENCODING__.name",
options: '-KE -U').should == 'EUC-JP'
ruby_exe("print __ENCODING__.name",
options: '-U -KE').should == 'EUC-JP'
ruby_exe("print __ENCODING__.name",
options: '-KE -U').should == 'EUC-JP'
end

# I assume IO redirection will break on Windows...
Expand Down
2 changes: 1 addition & 1 deletion spec/ruby/core/array/drop_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
end

it "raises an ArgumentError if the number of elements specified is negative" do
-> { [1, 2].drop(-3) }.should raise_error(ArgumentError)
-> { [1, 2].drop(-3) }.should raise_error(ArgumentError)
end

it "returns an empty Array if all elements are dropped" do
Expand Down
1 change: 1 addition & 0 deletions spec/ruby/core/array/fetch_values_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
it "returns the values for indexes" do
@array.fetch_values(0).should == [:a]
@array.fetch_values(0, 2).should == [:a, :c]
@array.fetch_values(-1).should == [:c]
end

it "returns the values for indexes ordered in the order of the requested indexes" do
Expand Down
92 changes: 45 additions & 47 deletions spec/ruby/core/array/intersect_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,65 +2,63 @@
require_relative 'fixtures/classes'

describe 'Array#intersect?' do
ruby_version_is '3.1' do # https://bugs.ruby-lang.org/issues/15198
describe 'when at least one element in two Arrays is the same' do
it 'returns true' do
[1, 2].intersect?([2, 3, 4]).should == true
[2, 3, 4].intersect?([1, 2]).should == true
end
describe 'when at least one element in two Arrays is the same' do
it 'returns true' do
[1, 2].intersect?([2, 3, 4]).should == true
[2, 3, 4].intersect?([1, 2]).should == true
end
end

describe 'when there are no elements in common between two Arrays' do
it 'returns false' do
[0, 1, 2].intersect?([3, 4]).should == false
[3, 4].intersect?([0, 1, 2]).should == false
[3, 4].intersect?([]).should == false
[].intersect?([0, 1, 2]).should == false
end
describe 'when there are no elements in common between two Arrays' do
it 'returns false' do
[0, 1, 2].intersect?([3, 4]).should == false
[3, 4].intersect?([0, 1, 2]).should == false
[3, 4].intersect?([]).should == false
[].intersect?([0, 1, 2]).should == false
end
end

it "tries to convert the passed argument to an Array using #to_ary" do
obj = mock('[1,2,3]')
obj.should_receive(:to_ary).and_return([1, 2, 3])
it "tries to convert the passed argument to an Array using #to_ary" do
obj = mock('[1,2,3]')
obj.should_receive(:to_ary).and_return([1, 2, 3])

[1, 2].intersect?(obj).should == true
end
[1, 2].intersect?(obj).should == true
end

it "determines equivalence between elements in the sense of eql?" do
obj1 = mock('1')
obj2 = mock('2')
obj1.stub!(:hash).and_return(0)
obj2.stub!(:hash).and_return(0)
obj1.stub!(:eql?).and_return(true)
obj2.stub!(:eql?).and_return(true)
it "determines equivalence between elements in the sense of eql?" do
obj1 = mock('1')
obj2 = mock('2')
obj1.stub!(:hash).and_return(0)
obj2.stub!(:hash).and_return(0)
obj1.stub!(:eql?).and_return(true)
obj2.stub!(:eql?).and_return(true)

[obj1].intersect?([obj2]).should == true
[obj1].intersect?([obj2]).should == true

obj1 = mock('3')
obj2 = mock('4')
obj1.stub!(:hash).and_return(0)
obj2.stub!(:hash).and_return(0)
obj1.stub!(:eql?).and_return(false)
obj2.stub!(:eql?).and_return(false)
obj1 = mock('3')
obj2 = mock('4')
obj1.stub!(:hash).and_return(0)
obj2.stub!(:hash).and_return(0)
obj1.stub!(:eql?).and_return(false)
obj2.stub!(:eql?).and_return(false)

[obj1].intersect?([obj2]).should == false
end
[obj1].intersect?([obj2]).should == false
end

it "does not call to_ary on array subclasses" do
[5, 6].intersect?(ArraySpecs::ToAryArray[1, 2, 5, 6]).should == true
end
it "does not call to_ary on array subclasses" do
[5, 6].intersect?(ArraySpecs::ToAryArray[1, 2, 5, 6]).should == true
end

it "properly handles an identical item even when its #eql? isn't reflexive" do
x = mock('x')
x.stub!(:hash).and_return(42)
x.stub!(:eql?).and_return(false) # Stubbed for clarity and latitude in implementation; not actually sent by MRI.
it "properly handles an identical item even when its #eql? isn't reflexive" do
x = mock('x')
x.stub!(:hash).and_return(42)
x.stub!(:eql?).and_return(false) # Stubbed for clarity and latitude in implementation; not actually sent by MRI.

[x].intersect?([x]).should == true
end
[x].intersect?([x]).should == true
end

it "has semantic of !(a & b).empty?" do
[].intersect?([]).should == false
[nil].intersect?([nil]).should == true
end
it "has semantic of !(a & b).empty?" do
[].intersect?([]).should == false
[nil].intersect?([nil]).should == true
end
end
7 changes: 7 additions & 0 deletions spec/ruby/core/array/sample_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,13 @@

-> { [1, 2].sample(random: random) }.should raise_error(RangeError)
end

it "raises a RangeError if the value is greater than the Array size" do
random = mock("array_sample_random")
random.should_receive(:rand).and_return(3)

-> { [1, 2].sample(random: random) }.should raise_error(RangeError)
end
end
end

Expand Down
13 changes: 11 additions & 2 deletions spec/ruby/core/array/shuffle_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,18 @@
-> { [1, 2].shuffle(random: random) }.should raise_error(RangeError)
end

it "raises a RangeError if the value is equal to one" do
it "raises a RangeError if the value is equal to the Array size" do
value = mock("array_shuffle_random_value")
value.should_receive(:to_int).at_least(1).times.and_return(1)
value.should_receive(:to_int).at_least(1).times.and_return(2)
random = mock("array_shuffle_random")
random.should_receive(:rand).at_least(1).times.and_return(value)

-> { [1, 2].shuffle(random: random) }.should raise_error(RangeError)
end

it "raises a RangeError if the value is greater than the Array size" do
value = mock("array_shuffle_random_value")
value.should_receive(:to_int).at_least(1).times.and_return(3)
random = mock("array_shuffle_random")
random.should_receive(:rand).at_least(1).times.and_return(value)

Expand Down
19 changes: 4 additions & 15 deletions spec/ruby/core/basicobject/instance_eval_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -141,22 +141,11 @@ class B; end
caller.get_constant_with_string(receiver).should == :singleton_class
end

ruby_version_is ""..."3.1" do
it "looks in the caller scope next" do
receiver = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverClass::ReceiverScope::Receiver.new
caller = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverClass::CallerScope::Caller.new
it "looks in the receiver class next" do
receiver = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverClass::ReceiverScope::Receiver.new
caller = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverClass::CallerScope::Caller.new

caller.get_constant_with_string(receiver).should == :Caller
end
end

ruby_version_is "3.1" do
it "looks in the receiver class next" do
receiver = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverClass::ReceiverScope::Receiver.new
caller = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverClass::CallerScope::Caller.new

caller.get_constant_with_string(receiver).should == :Receiver
end
caller.get_constant_with_string(receiver).should == :Receiver
end

it "looks in the caller class next" do
Expand Down
2 changes: 2 additions & 0 deletions spec/ruby/core/basicobject/singleton_method_added_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ def self.foo
end
}.should raise_error(NoMethodError, /undefined method [`']singleton_method_added' for/)
end
ensure
BasicObjectSpecs.send(:remove_const, :NoSingletonMethodAdded)
end

it "raises NoMethodError for a singleton instance" do
Expand Down
2 changes: 2 additions & 0 deletions spec/ruby/core/class/dup_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ def self.message
it "stores the new name if assigned to a constant" do
CoreClassSpecs::RecordCopy = CoreClassSpecs::Record.dup
CoreClassSpecs::RecordCopy.name.should == "CoreClassSpecs::RecordCopy"
ensure
CoreClassSpecs.send(:remove_const, :RecordCopy)
end

it "raises TypeError if called on BasicObject" do
Expand Down
31 changes: 31 additions & 0 deletions spec/ruby/core/class/fixtures/callback_order.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
module CoreClassSpecs
module Callbacks
class Base
def self.inherited(subclass)
subclass.const_set(:INHERITED_NAME, subclass.name)
ORDER << [
:inherited,
subclass,
eval("defined?(#{subclass.name})"),
Object.const_source_location(subclass.name) ? :location : :unknown_location,
]
super
end
end

ORDER = []

def self.const_added(const_name)
ORDER << [
:const_added,
const_name,
eval("defined?(#{const_name})"),
const_source_location(const_name) ? :location : :unknown_location,
]
super
end

class Child < Base
end
end
end
13 changes: 13 additions & 0 deletions spec/ruby/core/class/inherited_spec.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
require_relative 'fixtures/callback_order'

describe "Class.inherited" do

Expand Down Expand Up @@ -98,4 +99,16 @@ class << top; protected :inherited; end
-> { Class.new(top) }.should_not raise_error
end

it "is invoked after the class is named when using class definition syntax" do
CoreClassSpecs::Callbacks::Child::INHERITED_NAME.should == "CoreClassSpecs::Callbacks::Child"
end

ruby_version_is "3.5" do # https://bugs.ruby-lang.org/issues/21143
it "is invoked before `const_added`" do
CoreClassSpecs::Callbacks::ORDER.should == [
[:inherited, CoreClassSpecs::Callbacks::Child, "constant", :location],
[:const_added, :Child, "constant", :location],
]
end
end
end
2 changes: 2 additions & 0 deletions spec/ruby/core/class/new_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ def message2; "hello"; end
a = Class.new
MyClass::NestedClass = a
MyClass::NestedClass.name.should == "MyClass::NestedClass"
ensure
Object.send(:remove_const, :MyClass)
end

it "sets the new class' superclass to the given class" do
Expand Down
Loading
Loading