This commit is contained in:
Andrew Konchin 2025-03-26 19:56:40 +02:00 committed by Benoit Daloze
parent 53a930f157
commit bac22c985e
Notes: git 2025-03-27 10:09:42 +00:00
242 changed files with 4763 additions and 3269 deletions

View File

@ -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
@ -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

View File

@ -2,8 +2,8 @@ require_relative '../spec_helper'
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
@ -14,25 +14,25 @@ describe "ruby -U" do
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...

View File

@ -7,7 +7,7 @@ describe "Array#drop" do
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

View File

@ -2,65 +2,63 @@ require_relative '../../spec_helper'
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
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])
[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)
[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].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 "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
it "has semantic of !(a & b).empty?" do
[].intersect?([]).should == false
[nil].intersect?([nil]).should == true
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
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])
[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)
[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].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 "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
it "has semantic of !(a & b).empty?" do
[].intersect?([]).should == false
[nil].intersect?([nil]).should == true
end
end

View File

@ -141,22 +141,11 @@ describe "BasicObject#instance_eval" do
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

View File

@ -96,6 +96,8 @@ describe "BasicObject#singleton_method_added" do
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

View File

@ -59,6 +59,8 @@ describe "Class#dup" do
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

View File

@ -83,6 +83,8 @@ describe "Class.new" do
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

View File

@ -1,87 +1,85 @@
require_relative '../../spec_helper'
require_relative '../module/fixtures/classes'
ruby_version_is '3.1' do
describe "Class#subclasses" do
it "returns a list of classes directly inheriting from self" do
assert_subclasses(ModuleSpecs::Parent, [ModuleSpecs::Child, ModuleSpecs::Child2])
describe "Class#subclasses" do
it "returns a list of classes directly inheriting from self" do
assert_subclasses(ModuleSpecs::Parent, [ModuleSpecs::Child, ModuleSpecs::Child2])
end
it "does not return included modules from the parent" do
parent = Class.new
child = Class.new(parent)
mod = Module.new
parent.include(mod)
assert_subclasses(parent, [child])
end
it "does not return included modules from the child" do
parent = Class.new
child = Class.new(parent)
mod = Module.new
parent.include(mod)
assert_subclasses(parent, [child])
end
it "does not return prepended modules from the parent" do
parent = Class.new
child = Class.new(parent)
mod = Module.new
parent.prepend(mod)
assert_subclasses(parent, [child])
end
it "does not return prepended modules from the child" do
parent = Class.new
child = Class.new(parent)
mod = Module.new
child.prepend(mod)
assert_subclasses(parent, [child])
end
it "does not return singleton classes" do
a = Class.new
a_obj = a.new
def a_obj.force_singleton_class
42
end
it "does not return included modules from the parent" do
parent = Class.new
child = Class.new(parent)
mod = Module.new
parent.include(mod)
a.subclasses.should_not include(a_obj.singleton_class)
end
assert_subclasses(parent, [child])
end
it "has 1 entry per module or class" do
ModuleSpecs::Parent.subclasses.should == ModuleSpecs::Parent.subclasses.uniq
end
it "does not return included modules from the child" do
parent = Class.new
child = Class.new(parent)
mod = Module.new
parent.include(mod)
it "works when creating subclasses concurrently" do
t = 16
n = 1000
go = false
superclass = Class.new
assert_subclasses(parent, [child])
end
it "does not return prepended modules from the parent" do
parent = Class.new
child = Class.new(parent)
mod = Module.new
parent.prepend(mod)
assert_subclasses(parent, [child])
end
it "does not return prepended modules from the child" do
parent = Class.new
child = Class.new(parent)
mod = Module.new
child.prepend(mod)
assert_subclasses(parent, [child])
end
it "does not return singleton classes" do
a = Class.new
a_obj = a.new
def a_obj.force_singleton_class
42
end
a.subclasses.should_not include(a_obj.singleton_class)
end
it "has 1 entry per module or class" do
ModuleSpecs::Parent.subclasses.should == ModuleSpecs::Parent.subclasses.uniq
end
it "works when creating subclasses concurrently" do
t = 16
n = 1000
go = false
superclass = Class.new
threads = t.times.map do
Thread.new do
Thread.pass until go
n.times.map do
Class.new(superclass)
end
threads = t.times.map do
Thread.new do
Thread.pass until go
n.times.map do
Class.new(superclass)
end
end
go = true
classes = threads.map(&:value)
superclass.subclasses.size.should == t * n
superclass.subclasses.each { |c| c.should be_kind_of(Class) }
end
def assert_subclasses(mod,subclasses)
mod.subclasses.sort_by(&:inspect).should == subclasses.sort_by(&:inspect)
end
go = true
classes = threads.map(&:value)
superclass.subclasses.size.should == t * n
superclass.subclasses.each { |c| c.should be_kind_of(Class) }
end
def assert_subclasses(mod,subclasses)
mod.subclasses.sort_by(&:inspect).should == subclasses.sort_by(&:inspect)
end
end

View File

@ -24,15 +24,15 @@ describe :complex_rect, shared: true do
end
it "returns the real part of self as the first element" do
@numbers.each do |number|
number.send(@method).first.should == number.real
end
@numbers.each do |number|
number.send(@method).first.should == number.real
end
end
it "returns the imaginary part of self as the last element" do
@numbers.each do |number|
number.send(@method).last.should == number.imaginary
end
@numbers.each do |number|
number.send(@method).last.should == number.imaginary
end
end
it "raises an ArgumentError if given any arguments" do

View File

@ -0,0 +1,107 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
ruby_version_is "3.2" do
describe "Data#deconstruct" do
it "returns a hash of attributes" do
klass = Data.define(:x, :y)
d = klass.new(1, 2)
d.deconstruct_keys([:x, :y]).should == {x: 1, y: 2}
end
it "requires one argument" do
klass = Data.define(:x, :y)
d = klass.new(1, 2)
-> {
d.deconstruct_keys
}.should raise_error(ArgumentError, /wrong number of arguments \(given 0, expected 1\)/)
end
it "returns only specified keys" do
klass = Data.define(:x, :y)
d = klass.new(1, 2)
d.deconstruct_keys([:x, :y]).should == {x: 1, y: 2}
d.deconstruct_keys([:x] ).should == {x: 1}
d.deconstruct_keys([] ).should == {}
end
it "accepts string attribute names" do
klass = Data.define(:x, :y)
d = klass.new(1, 2)
d.deconstruct_keys(['x', 'y']).should == {'x' => 1, 'y' => 2}
end
it "accepts argument position number as well but returns them as keys" do
klass = Data.define(:x, :y)
d = klass.new(1, 2)
d.deconstruct_keys([0, 1]).should == {0 => 1, 1 => 2}
d.deconstruct_keys([0] ).should == {0 => 1}
d.deconstruct_keys([-1] ).should == {-1 => 2}
end
it "ignores incorrect position numbers" do
klass = Data.define(:x, :y)
d = klass.new(1, 2)
d.deconstruct_keys([0, 3]).should == {0 => 1}
end
it "support mixing attribute names and argument position numbers" do
klass = Data.define(:x, :y)
d = klass.new(1, 2)
d.deconstruct_keys([0, :x]).should == {0 => 1, :x => 1}
end
it "returns an empty hash when there are more keys than attributes" do
klass = Data.define(:x, :y)
d = klass.new(1, 2)
d.deconstruct_keys([:x, :y, :x]).should == {}
end
it "returns at first not existing attribute name" do
klass = Data.define(:x, :y)
d = klass.new(1, 2)
d.deconstruct_keys([:a, :x]).should == {}
d.deconstruct_keys([:x, :a]).should == {x: 1}
end
it "returns at first not existing argument position number" do
klass = Data.define(:x, :y)
d = klass.new(1, 2)
d.deconstruct_keys([3, 0]).should == {}
d.deconstruct_keys([0, 3]).should == {0 => 1}
end
it "accepts nil argument and return all the attributes" do
klass = Data.define(:x, :y)
d = klass.new(1, 2)
d.deconstruct_keys(nil).should == {x: 1, y: 2}
end
it "raises TypeError if index is not a String, a Symbol and not convertible to Integer " do
klass = Data.define(:x, :y)
d = klass.new(1, 2)
-> {
d.deconstruct_keys([0, []])
}.should raise_error(TypeError, "no implicit conversion of Array into Integer")
end
it "raise TypeError if passed anything except nil or array" do
klass = Data.define(:x, :y)
d = klass.new(1, 2)
-> { d.deconstruct_keys('x') }.should raise_error(TypeError, /expected Array or nil/)
-> { d.deconstruct_keys(1) }.should raise_error(TypeError, /expected Array or nil/)
-> { d.deconstruct_keys(:x) }.should raise_error(TypeError, /expected Array or nil/)
-> { d.deconstruct_keys({}) }.should raise_error(TypeError, /expected Array or nil/)
end
end
end

View File

@ -0,0 +1,10 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
ruby_version_is "3.2" do
describe "Data#deconstruct" do
it "returns an array of attribute values" do
DataSpecs::Measure.new(42, "km").deconstruct.should == [42, "km"]
end
end
end

View File

@ -0,0 +1,65 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
ruby_version_is "3.2" do
describe "Data#eql?" do
it "returns true if the other is the same object" do
a = DataSpecs::Measure.new(42, "km")
a.should.eql?(a)
end
it "returns true if the other has all the same fields" do
a = DataSpecs::Measure.new(42, "km")
b = DataSpecs::Measure.new(42, "km")
a.should.eql?(b)
end
it "returns false if the other is a different object or has different fields" do
a = DataSpecs::Measure.new(42, "km")
b = DataSpecs::Measure.new(42, "mi")
a.should_not.eql?(b)
end
it "returns false if other is of a different class" do
a = DataSpecs::Measure.new(42, "km")
klass = Data.define(*DataSpecs::Measure.members)
b = klass.new(42, "km")
a.should_not.eql?(b)
end
it "returns false if any corresponding elements are not equal with #eql?" do
a = DataSpecs::Measure.new(42, "km")
b = DataSpecs::Measure.new(42.0, "mi")
a.should_not.eql?(b)
end
context "recursive structure" do
it "returns true the other is the same object" do
a = DataSpecs::Measure.allocate
a.send(:initialize, amount: 42, unit: a)
a.should.eql?(a)
end
it "returns true if the other has all the same fields" do
a = DataSpecs::Measure.allocate
a.send(:initialize, amount: 42, unit: a)
b = DataSpecs::Measure.allocate
b.send(:initialize, amount: 42, unit: b)
a.should.eql?(b)
end
it "returns false if any corresponding elements are not equal with #eql?" do
a = DataSpecs::Measure.allocate
a.send(:initialize, amount: a, unit: "km")
b = DataSpecs::Measure.allocate
b.send(:initialize, amount: b, unit: "mi")
a.should_not.eql?(b)
end
end
end
end

View File

@ -0,0 +1,65 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
ruby_version_is "3.2" do
describe "Data#==" do
it "returns true if the other is the same object" do
a = DataSpecs::Measure.new(42, "km")
a.should == a
end
it "returns true if the other has all the same fields" do
a = DataSpecs::Measure.new(42, "km")
b = DataSpecs::Measure.new(42, "km")
a.should == b
end
it "returns false if the other is a different object or has different fields" do
a = DataSpecs::Measure.new(42, "km")
b = DataSpecs::Measure.new(42, "mi")
a.should_not == b
end
it "returns false if other is of a different class" do
a = DataSpecs::Measure.new(42, "km")
klass = Data.define(*DataSpecs::Measure.members)
b = klass.new(42, "km")
a.should_not == b
end
it "returns false if any corresponding elements are not equal with #==" do
a = DataSpecs::Measure.new(42, "km")
b = DataSpecs::Measure.new(42.0, "mi")
a.should_not == b
end
context "recursive structure" do
it "returns true the other is the same object" do
a = DataSpecs::Measure.allocate
a.send(:initialize, amount: 42, unit: a)
a.should == a
end
it "returns true if the other has all the same fields" do
a = DataSpecs::Measure.allocate
a.send(:initialize, amount: 42, unit: a)
b = DataSpecs::Measure.allocate
b.send(:initialize, amount: 42, unit: b)
a.should == b
end
it "returns false if any corresponding elements are not equal with #==" do
a = DataSpecs::Measure.allocate
a.send(:initialize, amount: a, unit: "km")
b = DataSpecs::Measure.allocate
b.send(:initialize, amount: b, unit: "mi")
a.should_not == b
end
end
end
end

View File

@ -1,5 +1,13 @@
module DataSpecs
guard -> { ruby_version_is "3.2" and Data.respond_to?(:define) } do
Measure = Data.define(:amount, :unit)
class MeasureWithOverriddenName < Measure
def self.name
"A"
end
end
class DataSubclass < Data; end
end
end

View File

@ -0,0 +1,27 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
ruby_version_is "3.2" do
describe "Data#hash" do
it "returns the same integer for objects with the same content" do
a = DataSpecs::Measure.new(42, "km")
b = DataSpecs::Measure.new(42, "km")
a.hash.should == b.hash
a.hash.should be_an_instance_of(Integer)
end
it "returns different hashes for objects with different values" do
a = DataSpecs::Measure.new(42, "km")
b = DataSpecs::Measure.new(42, "ml")
a.hash.should_not == b.hash
a = DataSpecs::Measure.new(42, "km")
b = DataSpecs::Measure.new(13, "km")
a.hash.should_not == b.hash
end
it "returns different hashes for different classes" do
Data.define(:x).new(1).hash.should != Data.define(:x).new(1).hash
end
end
end

View File

@ -0,0 +1,8 @@
require_relative '../../spec_helper'
require_relative 'shared/inspect'
ruby_version_is "3.2" do
describe "Data#inspect" do
it_behaves_like :data_inspect, :inspect
end
end

View File

@ -0,0 +1,23 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
ruby_version_is "3.2" do
describe "Data#members" do
it "returns an array of attribute names" do
measure = DataSpecs::Measure.new(amount: 42, unit: 'km')
measure.members.should == [:amount, :unit]
end
end
describe "DataClass#members" do
it "returns an array of attribute names" do
DataSpecs::Measure.members.should == [:amount, :unit]
end
context "class inheriting Data" do
it "isn't available in a subclass" do
DataSpecs::DataSubclass.should_not.respond_to?(:members)
end
end
end
end

View File

@ -0,0 +1,54 @@
require_relative '../fixtures/classes'
describe :data_inspect, shared: true do
it "returns a string representation showing members and values" do
a = DataSpecs::Measure.new(42, "km")
a.send(@method).should == '#<data DataSpecs::Measure amount=42, unit="km">'
end
it "returns a string representation without the class name for anonymous structs" do
Data.define(:a).new("").send(@method).should == '#<data a="">'
end
it "returns a string representation without the class name for structs nested in anonymous classes" do
c = Class.new
c.class_eval <<~DOC
Foo = Data.define(:a)
DOC
c::Foo.new("").send(@method).should == '#<data a="">'
end
it "returns a string representation without the class name for structs nested in anonymous modules" do
m = Module.new
m.class_eval <<~DOC
Foo = Data.define(:a)
DOC
m::Foo.new("").send(@method).should == '#<data a="">'
end
it "does not call #name method" do
struct = DataSpecs::MeasureWithOverriddenName.new(42, "km")
struct.send(@method).should == '#<data DataSpecs::MeasureWithOverriddenName amount=42, unit="km">'
end
it "does not call #name method when struct is anonymous" do
klass = Class.new(DataSpecs::Measure) do
def self.name
"A"
end
end
struct = klass.new(42, "km")
struct.send(@method).should == '#<data amount=42, unit="km">'
end
context "recursive structure" do
it "returns string representation with recursive attribute replaced with ..." do
a = DataSpecs::Measure.allocate
a.send(:initialize, amount: 42, unit: a)
a.send(@method).should == "#<data DataSpecs::Measure amount=42, unit=#<data DataSpecs::Measure:...>>"
end
end
end

View File

@ -0,0 +1,8 @@
require_relative '../../spec_helper'
require_relative 'shared/inspect'
ruby_version_is "3.2" do
describe "Data#to_s" do
it_behaves_like :data_inspect, :to_s
end
end

View File

@ -177,7 +177,7 @@ ruby_version_is '3.3' do
dir.close
end
platform_is_not :windows do
guard -> { Dir.respond_to? :fchdir } do
it "does not raise an Errno::ENOENT if the original directory no longer exists" do
dir_name1 = tmp('testdir1')
dir_name2 = tmp('testdir2')

View File

@ -89,31 +89,15 @@ describe "Dir.glob" do
Dir.glob('**/', File::FNM_DOTMATCH).sort.should == expected
end
ruby_version_is ''...'3.1' do
it "recursively matches files and directories in nested dot subdirectory with 'nested/**/*' from the current directory and option File::FNM_DOTMATCH" do
expected = %w[
nested/.
nested/.dotsubir
nested/.dotsubir/.
nested/.dotsubir/.dotfile
nested/.dotsubir/nondotfile
]
it "recursively matches files and directories in nested dot subdirectory except . with 'nested/**/*' from the current directory and option File::FNM_DOTMATCH" do
expected = %w[
nested/.
nested/.dotsubir
nested/.dotsubir/.dotfile
nested/.dotsubir/nondotfile
]
Dir.glob('nested/**/*', File::FNM_DOTMATCH).sort.should == expected.sort
end
end
ruby_version_is '3.1' do
it "recursively matches files and directories in nested dot subdirectory except . with 'nested/**/*' from the current directory and option File::FNM_DOTMATCH" do
expected = %w[
nested/.
nested/.dotsubir
nested/.dotsubir/.dotfile
nested/.dotsubir/nondotfile
]
Dir.glob('nested/**/*', File::FNM_DOTMATCH).sort.should == expected.sort
end
Dir.glob('nested/**/*', File::FNM_DOTMATCH).sort.should == expected.sort
end
# This is a separate case to check **/ coming after a constant
@ -260,34 +244,31 @@ describe "Dir.glob" do
Dir.glob('**/.*', base: "deeply/nested").sort.should == expected
end
# < 3.1 include a "." entry for every dir: ["directory/.", "directory/structure/.", ...]
ruby_version_is '3.1' do
it "handles **/.* with base keyword argument and FNM_DOTMATCH" do
expected = %w[
.
.dotfile.ext
directory/structure/.ext
].sort
it "handles **/.* with base keyword argument and FNM_DOTMATCH" do
expected = %w[
.
.dotfile.ext
directory/structure/.ext
].sort
Dir.glob('**/.*', File::FNM_DOTMATCH, base: "deeply/nested").sort.should == expected
end
Dir.glob('**/.*', File::FNM_DOTMATCH, base: "deeply/nested").sort.should == expected
end
it "handles **/** with base keyword argument and FNM_DOTMATCH" do
expected = %w[
.
.dotfile.ext
directory
directory/structure
directory/structure/.ext
directory/structure/bar
directory/structure/baz
directory/structure/file_one
directory/structure/file_one.ext
directory/structure/foo
].sort
it "handles **/** with base keyword argument and FNM_DOTMATCH" do
expected = %w[
.
.dotfile.ext
directory
directory/structure
directory/structure/.ext
directory/structure/bar
directory/structure/baz
directory/structure/file_one
directory/structure/file_one.ext
directory/structure/foo
].sort
Dir.glob('**/**', File::FNM_DOTMATCH, base: "deeply/nested").sort.should == expected
end
Dir.glob('**/**', File::FNM_DOTMATCH, base: "deeply/nested").sort.should == expected
end
it "handles **/*pattern* with base keyword argument and FNM_DOTMATCH" do

View File

@ -42,25 +42,10 @@ describe :dir_glob, shared: true do
result.sort.should == Dir.send(@method, '*').sort
end
ruby_version_is ""..."3.1" do
it "result is sorted with any non false value of sort:" do
result = Dir.send(@method, '*', sort: 0)
result.should == result.sort
result = Dir.send(@method, '*', sort: nil)
result.should == result.sort
result = Dir.send(@method, '*', sort: 'false')
result.should == result.sort
end
end
ruby_version_is "3.1" do
it "raises an ArgumentError if sort: is not true or false" do
-> { Dir.send(@method, '*', sort: 0) }.should raise_error ArgumentError, /expected true or false/
-> { Dir.send(@method, '*', sort: nil) }.should raise_error ArgumentError, /expected true or false/
-> { Dir.send(@method, '*', sort: 'false') }.should raise_error ArgumentError, /expected true or false/
end
it "raises an ArgumentError if sort: is not true or false" do
-> { Dir.send(@method, '*', sort: 0) }.should raise_error ArgumentError, /expected true or false/
-> { Dir.send(@method, '*', sort: nil) }.should raise_error ArgumentError, /expected true or false/
-> { Dir.send(@method, '*', sort: 'false') }.should raise_error ArgumentError, /expected true or false/
end
it "matches non-dotfiles with '*'" do
@ -151,16 +136,8 @@ describe :dir_glob, shared: true do
Dir.send(@method, 'special/test\{1\}/*').should == ['special/test{1}/file[1]']
end
ruby_version_is ''...'3.1' do
it "matches dotfiles with '.*'" do
Dir.send(@method, '.*').sort.should == %w|. .. .dotfile .dotsubdir|.sort
end
end
ruby_version_is '3.1' do
it "matches dotfiles except .. with '.*'" do
Dir.send(@method, '.*').sort.should == %w|. .dotfile .dotsubdir|.sort
end
it "matches dotfiles except .. with '.*'" do
Dir.send(@method, '.*').sort.should == %w|. .dotfile .dotsubdir|.sort
end
it "matches non-dotfiles with '*<non-special characters>'" do
@ -205,16 +182,8 @@ describe :dir_glob, shared: true do
Dir.send(@method, '**').sort.should == expected
end
ruby_version_is ''...'3.1' do
it "matches dotfiles in the current directory with '.**'" do
Dir.send(@method, '.**').sort.should == %w|. .. .dotsubdir .dotfile|.sort
end
end
ruby_version_is '3.1' do
it "matches dotfiles in the current directory except .. with '.**'" do
Dir.send(@method, '.**').sort.should == %w|. .dotsubdir .dotfile|.sort
end
it "matches dotfiles in the current directory except .. with '.**'" do
Dir.send(@method, '.**').sort.should == %w|. .dotsubdir .dotfile|.sort
end
it "recursively matches any nondot subdirectories with '**/'" do
@ -245,19 +214,9 @@ describe :dir_glob, shared: true do
Dir.send(@method, '**/*ory', base: 'deeply').sort.should == expected
end
ruby_version_is ''...'3.1' do
it "recursively matches any subdirectories including ./ and ../ with '.**/'" do
Dir.chdir("#{DirSpecs.mock_dir}/subdir_one") do
Dir.send(@method, '.**/').sort.should == %w|./ ../|.sort
end
end
end
ruby_version_is '3.1' do
it "recursively matches any subdirectories including ./ with '.**/'" do
Dir.chdir("#{DirSpecs.mock_dir}/subdir_one") do
Dir.send(@method, '.**/').should == ['./']
end
it "recursively matches any subdirectories including ./ with '.**/'" do
Dir.chdir("#{DirSpecs.mock_dir}/subdir_one") do
Dir.send(@method, '.**/').should == ['./']
end
end

View File

@ -16,8 +16,8 @@ describe "Encoding::Converter#finish" do
end
it "returns the last part of the converted String if it hasn't already" do
@ec.convert("\u{9999}").should == "\e$B9a".dup.force_encoding('iso-2022-jp')
@ec.finish.should == "\e(B".dup.force_encoding('iso-2022-jp')
@ec.convert("\u{9999}").should == "\e$B9a".dup.force_encoding('iso-2022-jp')
@ec.finish.should == "\e(B".dup.force_encoding('iso-2022-jp')
end
it "returns a String in the destination encoding" do

View File

@ -23,8 +23,8 @@ describe "Encoding::Converter.search_convpath" do
end
it "raises an Encoding::ConverterNotFoundError if no conversion path exists" do
-> do
Encoding::Converter.search_convpath(Encoding::BINARY, Encoding::Emacs_Mule)
end.should raise_error(Encoding::ConverterNotFoundError)
-> do
Encoding::Converter.search_convpath(Encoding::BINARY, Encoding::Emacs_Mule)
end.should raise_error(Encoding::ConverterNotFoundError)
end
end

View File

@ -1,11 +1,9 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
ruby_version_is '3.1' do
describe "Enumerable#compact" do
it 'returns array without nil elements' do
arr = EnumerableSpecs::Numerous.new(nil, 1, 2, nil, true)
arr.compact.should == [1, 2, true]
end
describe "Enumerable#compact" do
it 'returns array without nil elements' do
arr = EnumerableSpecs::Numerous.new(nil, 1, 2, nil, true)
arr.compact.should == [1, 2, true]
end
end

View File

@ -56,10 +56,8 @@ describe "Enumerable#each_cons" do
multi.each_cons(2).to_a.should == [[[1, 2], [3, 4, 5]], [[3, 4, 5], [6, 7, 8, 9]]]
end
ruby_version_is "3.1" do
it "returns self when a block is given" do
@enum.each_cons(3){}.should == @enum
end
it "returns self when a block is given" do
@enum.each_cons(3){}.should == @enum
end
describe "when no block is given" do

View File

@ -57,10 +57,8 @@ describe "Enumerable#each_slice" do
e.to_a.should == @sliced
end
ruby_version_is "3.1" do
it "returns self when a block is given" do
@enum.each_slice(3){}.should == @enum
end
it "returns self when a block is given" do
@enum.each_slice(3){}.should == @enum
end
it "gathers whole arrays as elements when each yields multiple" do

View File

@ -32,62 +32,60 @@ describe "Enumerable#tally" do
end
end
ruby_version_is "3.1" do
describe "Enumerable#tally with a hash" do
before :each do
ScratchPad.record []
end
describe "Enumerable#tally with a hash" do
before :each do
ScratchPad.record []
end
it "returns a hash with counts according to the value" do
enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
enum.tally({ 'foo' => 1 }).should == { 'foo' => 3, 'bar' => 1, 'baz' => 1}
end
it "returns a hash with counts according to the value" do
enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
enum.tally({ 'foo' => 1 }).should == { 'foo' => 3, 'bar' => 1, 'baz' => 1}
end
it "returns the given hash" do
enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
hash = { 'foo' => 1 }
enum.tally(hash).should equal(hash)
end
it "returns the given hash" do
enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
hash = { 'foo' => 1 }
enum.tally(hash).should equal(hash)
end
it "calls #to_hash to convert argument to Hash implicitly if passed not a Hash" do
enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
object = Object.new
def object.to_hash; { 'foo' => 1 }; end
enum.tally(object).should == { 'foo' => 3, 'bar' => 1, 'baz' => 1}
end
it "calls #to_hash to convert argument to Hash implicitly if passed not a Hash" do
enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
object = Object.new
def object.to_hash; { 'foo' => 1 }; end
enum.tally(object).should == { 'foo' => 3, 'bar' => 1, 'baz' => 1}
end
it "raises a FrozenError and does not update the given hash when the hash is frozen" do
enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
hash = { 'foo' => 1 }.freeze
-> { enum.tally(hash) }.should raise_error(FrozenError)
hash.should == { 'foo' => 1 }
end
it "raises a FrozenError and does not update the given hash when the hash is frozen" do
enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
hash = { 'foo' => 1 }.freeze
-> { enum.tally(hash) }.should raise_error(FrozenError)
hash.should == { 'foo' => 1 }
end
it "raises a FrozenError even if enumerable is empty" do
enum = EnumerableSpecs::Numerous.new()
hash = { 'foo' => 1 }.freeze
-> { enum.tally(hash) }.should raise_error(FrozenError)
end
it "raises a FrozenError even if enumerable is empty" do
enum = EnumerableSpecs::Numerous.new()
hash = { 'foo' => 1 }.freeze
-> { enum.tally(hash) }.should raise_error(FrozenError)
end
it "does not call given block" do
enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
enum.tally({ 'foo' => 1 }) { |v| ScratchPad << v }
ScratchPad.recorded.should == []
end
it "does not call given block" do
enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
enum.tally({ 'foo' => 1 }) { |v| ScratchPad << v }
ScratchPad.recorded.should == []
end
it "ignores the default value" do
enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
enum.tally(Hash.new(100)).should == { 'foo' => 2, 'bar' => 1, 'baz' => 1}
end
it "ignores the default value" do
enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
enum.tally(Hash.new(100)).should == { 'foo' => 2, 'bar' => 1, 'baz' => 1}
end
it "ignores the default proc" do
enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
enum.tally(Hash.new {100}).should == { 'foo' => 2, 'bar' => 1, 'baz' => 1}
end
it "ignores the default proc" do
enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
enum.tally(Hash.new {100}).should == { 'foo' => 2, 'bar' => 1, 'baz' => 1}
end
it "needs the values counting each elements to be an integer" do
enum = EnumerableSpecs::Numerous.new('foo')
-> { enum.tally({ 'foo' => 'bar' }) }.should raise_error(TypeError)
end
it "needs the values counting each elements to be an integer" do
enum = EnumerableSpecs::Numerous.new('foo')
-> { enum.tally({ 'foo' => 'bar' }) }.should raise_error(TypeError)
end
end

View File

@ -1,16 +1,14 @@
require_relative '../../../spec_helper'
require_relative 'fixtures/classes'
ruby_version_is '3.1' do
describe "Enumerator::Lazy#compact" do
it 'returns array without nil elements' do
arr = [1, nil, 3, false, 5].to_enum.lazy.compact
arr.should be_an_instance_of(Enumerator::Lazy)
arr.force.should == [1, 3, false, 5]
end
describe "Enumerator::Lazy#compact" do
it 'returns array without nil elements' do
arr = [1, nil, 3, false, 5].to_enum.lazy.compact
arr.should be_an_instance_of(Enumerator::Lazy)
arr.force.should == [1, 3, false, 5]
end
it "sets #size to nil" do
Enumerator::Lazy.new(Object.new, 100) {}.compact.size.should == nil
end
it "sets #size to nil" do
Enumerator::Lazy.new(Object.new, 100) {}.compact.size.should == nil
end
end

View File

@ -9,16 +9,11 @@ describe "Enumerator::Lazy" do
it "defines lazy versions of a whitelist of Enumerator methods" do
lazy_methods = [
:chunk, :collect, :collect_concat, :drop, :drop_while, :enum_for,
:chunk, :chunk_while, :collect, :collect_concat, :compact, :drop, :drop_while, :enum_for,
:find_all, :flat_map, :force, :grep, :grep_v, :lazy, :map, :reject,
:select, :slice_after, :slice_before, :slice_when, :take, :take_while,
:to_enum, :zip
:to_enum, :uniq, :zip
]
lazy_methods += [:chunk_while, :uniq]
ruby_version_is '3.1' do
lazy_methods += [:compact]
end
Enumerator::Lazy.instance_methods(false).should include(*lazy_methods)
end

View File

@ -1,11 +1,9 @@
require_relative '../../spec_helper'
describe "ENV#dup" do
ruby_version_is "3.1" do
it "raises TypeError" do
-> {
ENV.dup
}.should raise_error(TypeError, /Cannot dup ENV, use ENV.to_h to get a copy of ENV as a hash/)
end
it "raises TypeError" do
-> {
ENV.dup
}.should raise_error(TypeError, /Cannot dup ENV, use ENV.to_h to get a copy of ENV as a hash/)
end
end

View File

@ -47,7 +47,7 @@ describe "ENV.fetch" do
it "warns on block and default parameter given" do
-> do
ENV.fetch("foo", "default") { "bar" }.should == "bar"
ENV.fetch("foo", "default") { "bar" }.should == "bar"
end.should complain(/block supersedes default value argument/)
end

View File

@ -2,5 +2,5 @@ require_relative '../../spec_helper'
require_relative 'shared/length'
describe "ENV.length" do
it_behaves_like :env_length, :length
it_behaves_like :env_length, :length
end

View File

@ -2,5 +2,5 @@ require_relative '../../spec_helper'
require_relative 'shared/length'
describe "ENV.size" do
it_behaves_like :env_length, :size
it_behaves_like :env_length, :size
end

View File

@ -29,6 +29,8 @@ describe "Errno::EMFILE" do
ExceptionSpecs::EMFILESub = Class.new(Errno::EMFILE)
exc = ExceptionSpecs::EMFILESub.new
exc.should be_an_instance_of(ExceptionSpecs::EMFILESub)
ensure
ExceptionSpecs.send(:remove_const, :EMFILESub)
end
end

View File

@ -16,6 +16,8 @@ describe "SystemCallError" do
exc = ExceptionSpecs::SCESub.new
ScratchPad.recorded.should equal(:initialize)
exc.should be_an_instance_of(ExceptionSpecs::SCESub)
ensure
ExceptionSpecs.send(:remove_const, :SCESub)
end
end

View File

@ -1,7 +1,5 @@
require_relative '../../spec_helper'
require 'fiber'
describe "Fiber#alive?" do
it "returns true for a Fiber that hasn't had #resume called" do
fiber = Fiber.new { true }

View File

@ -1,8 +1,6 @@
require_relative '../../spec_helper'
require_relative 'shared/blocking'
require "fiber"
describe "Fiber.blocking?" do
it_behaves_like :non_blocking_fiber, -> { Fiber.blocking? }

View File

@ -1,14 +1,6 @@
require_relative '../../spec_helper'
require 'fiber'
describe "Fiber.current" do
ruby_version_is "3.1" do
it "is available without an extra require" do
ruby_exe("print Fiber.current.class", options: '--disable-gems --disable-did-you-mean').should == "Fiber"
end
end
it "returns the root Fiber when called outside of a Fiber" do
root = Fiber.current
root.should be_an_instance_of(Fiber)

View File

@ -1,5 +1,4 @@
require_relative '../../spec_helper'
require 'fiber'
describe "Fiber#inspect" do
describe "status" do

View File

@ -130,7 +130,6 @@ end
describe "Fiber#raise" do
it "transfers and raises on a transferring fiber" do
require "fiber"
root = Fiber.current
fiber = Fiber.new { root.transfer }
fiber.transfer

View File

@ -1,5 +1,5 @@
require_relative '../../spec_helper'
require_relative '../../shared/fiber/resume'
require_relative 'shared/resume'
describe "Fiber#resume" do
it_behaves_like :fiber_resume, :resume
@ -67,4 +67,17 @@ describe "Fiber#resume" do
ruby_exe(code).should == "ensure executed\n"
end
it "can work with Fiber#transfer" do
fiber1 = Fiber.new { true }
fiber2 = Fiber.new { fiber1.transfer; Fiber.yield 10 ; Fiber.yield 20; raise }
fiber2.resume.should == 10
fiber2.resume.should == 20
end
it "raises a FiberError if the Fiber attempts to resume a resuming fiber" do
root_fiber = Fiber.current
fiber1 = Fiber.new { root_fiber.resume }
-> { fiber1.resume }.should raise_error(FiberError, /attempt to resume a resuming fiber/)
end
end

View File

@ -1,7 +1,7 @@
describe :fiber_resume, shared: true do
it "can be invoked from the root Fiber" do
fiber = Fiber.new { :fiber }
fiber.send(@method).should == :fiber
fiber = Fiber.new { :fiber }
fiber.send(@method).should == :fiber
end
it "raises a FiberError if invoked from a different Thread" do

View File

@ -1,7 +1,5 @@
require_relative '../../spec_helper'
require_relative '../../shared/fiber/resume'
require 'fiber'
require_relative 'shared/resume'
describe "Fiber#transfer" do
it_behaves_like :fiber_resume, :transfer

View File

@ -11,34 +11,32 @@ describe "File.dirname" do
File.dirname('/foo/foo').should == '/foo'
end
ruby_version_is '3.1' do
context "when level is passed" do
it "returns all the components of filename except the last parts by the level" do
File.dirname('/home/jason', 2).should == '/'
File.dirname('/home/jason/poot.txt', 2).should == '/home'
end
context "when level is passed" do
it "returns all the components of filename except the last parts by the level" do
File.dirname('/home/jason', 2).should == '/'
File.dirname('/home/jason/poot.txt', 2).should == '/home'
end
it "returns the same String if the level is 0" do
File.dirname('poot.txt', 0).should == 'poot.txt'
File.dirname('/', 0).should == '/'
end
it "returns the same String if the level is 0" do
File.dirname('poot.txt', 0).should == 'poot.txt'
File.dirname('/', 0).should == '/'
end
it "raises ArgumentError if the level is negative" do
-> {
File.dirname('/home/jason', -1)
}.should raise_error(ArgumentError, "negative level: -1")
end
it "raises ArgumentError if the level is negative" do
-> {
File.dirname('/home/jason', -1)
}.should raise_error(ArgumentError, "negative level: -1")
end
it "returns '/' when level exceeds the number of segments in the path" do
File.dirname("/home/jason", 100).should == '/'
end
it "returns '/' when level exceeds the number of segments in the path" do
File.dirname("/home/jason", 100).should == '/'
end
it "calls #to_int if passed not numeric value" do
object = Object.new
def object.to_int; 2; end
it "calls #to_int if passed not numeric value" do
object = Object.new
def object.to_int; 2; end
File.dirname("/a/b/c/d", object).should == '/a/b'
end
File.dirname("/a/b/c/d", object).should == '/a/b'
end
end
@ -65,19 +63,19 @@ describe "File.dirname" do
end
it "returns all the components of filename except the last one (edge cases on all platforms)" do
File.dirname("").should == "."
File.dirname(".").should == "."
File.dirname("./").should == "."
File.dirname("./b/./").should == "./b"
File.dirname("..").should == "."
File.dirname("../").should == "."
File.dirname("/").should == "/"
File.dirname("/.").should == "/"
File.dirname("/foo/").should == "/"
File.dirname("/foo/.").should == "/foo"
File.dirname("/foo/./").should == "/foo"
File.dirname("/foo/../.").should == "/foo/.."
File.dirname("foo/../").should == "foo"
File.dirname("").should == "."
File.dirname(".").should == "."
File.dirname("./").should == "."
File.dirname("./b/./").should == "./b"
File.dirname("..").should == "."
File.dirname("../").should == "."
File.dirname("/").should == "/"
File.dirname("/.").should == "/"
File.dirname("/foo/").should == "/"
File.dirname("/foo/.").should == "/foo"
File.dirname("/foo/./").should == "/foo"
File.dirname("/foo/../.").should == "/foo/.."
File.dirname("foo/../").should == "foo"
end
platform_is_not :windows do

View File

@ -77,18 +77,6 @@ describe :file_path, shared: true do
after :each do
rm_r @dir
end
ruby_version_is ""..."3.1" do
it "raises IOError if file was opened with File::TMPFILE" do
begin
File.open(@dir, File::RDWR | File::TMPFILE) do |f|
-> { f.send(@method) }.should raise_error(IOError)
end
rescue Errno::EOPNOTSUPP, Errno::EINVAL, Errno::EISDIR
skip "no support from the filesystem"
end
end
end
end
end
end

View File

@ -91,7 +91,7 @@ describe "Float#<=>" do
it "returns 1 when self is Infinity and other is infinite?=nil (which means finite)" do
obj = Object.new
def obj.infinite?
nil
nil
end
(infinity_value <=> obj).should == 1
end

View File

@ -30,6 +30,11 @@ describe "Float#round" do
12.345678.round(3.999).should == 12.346
end
it "correctly rounds exact floats with a numerous digits in a fraction part" do
0.8241000000000004.round(10).should == 0.8241
0.8241000000000002.round(10).should == 0.8241
end
it "returns zero when passed a negative argument with magnitude greater than magnitude of the whole number portion of the Float" do
0.8346268.round(-1).should eql(0)
end
@ -68,6 +73,10 @@ describe "Float#round" do
0.42.round(2.0**30).should == 0.42
end
it "returns rounded values for not so big argument" do
0.42.round(2.0**23).should == 0.42
end
it "returns big values rounded to nearest" do
+2.5e20.round(-20).should eql( +3 * 10 ** 20 )
-2.5e20.round(-20).should eql( -3 * 10 ** 20 )

View File

@ -1,19 +1,17 @@
require_relative '../../spec_helper'
ruby_version_is "3.1" do
describe "GC.measure_total_time" do
before :each do
@default = GC.measure_total_time
end
describe "GC.measure_total_time" do
before :each do
@default = GC.measure_total_time
end
after :each do
GC.measure_total_time = @default
end
after :each do
GC.measure_total_time = @default
end
it "can set and get a boolean value" do
original = GC.measure_total_time
GC.measure_total_time = !original
GC.measure_total_time.should == !original
end
it "can set and get a boolean value" do
original = GC.measure_total_time
GC.measure_total_time = !original
GC.measure_total_time.should == !original
end
end

View File

@ -1,15 +1,13 @@
require_relative '../../spec_helper'
ruby_version_is "3.1" do
describe "GC.total_time" do
it "returns an Integer" do
GC.total_time.should be_kind_of(Integer)
end
describe "GC.total_time" do
it "returns an Integer" do
GC.total_time.should be_kind_of(Integer)
end
it "increases as collections are run" do
time_before = GC.total_time
GC.start
GC.total_time.should >= time_before
end
it "increases as collections are run" do
time_before = GC.total_time
GC.start
GC.total_time.should >= time_before
end
end

View File

@ -42,12 +42,10 @@ describe "Hash#hash" do
# Like above, because h.eql?(x: [h])
end
ruby_version_is "3.1" do
it "allows omitting values" do
a = 1
b = 2
it "allows omitting values" do
a = 1
b = 2
eval('{a:, b:}.should == { a: 1, b: 2 }')
end
{a:, b:}.should == { a: 1, b: 2 }
end
end

View File

@ -91,9 +91,9 @@ describe :hash_store, shared: true do
end
it "does not raise an exception if changing the value of an existing key during iteration" do
hash = {1 => 2, 3 => 4, 5 => 6}
hash.each { hash.send(@method, 1, :foo) }
hash.should == {1 => :foo, 3 => 4, 5 => 6}
hash = {1 => 2, 3 => 4, 5 => 6}
hash.each { hash.send(@method, 1, :foo) }
hash.should == {1 => :foo, 3 => 4, 5 => 6}
end
it "does not dispatch to hash for Boolean, Integer, Float, String, or Symbol" do

View File

@ -76,24 +76,12 @@ describe "Hash#transform_keys!" do
@hash.should == { b: 1, c: 2, d: 3, e: 4 }
end
ruby_version_is ""..."3.0.2" do # https://bugs.ruby-lang.org/issues/17735
it "returns the processed keys if we break from the block" do
@hash.transform_keys! do |v|
break if v == :c
v.succ
end
@hash.should == { b: 1, c: 2 }
end
end
ruby_version_is "3.0.2" do
it "returns the processed keys and non evaluated keys if we break from the block" do
@hash.transform_keys! do |v|
break if v == :c
v.succ
end
@hash.should == { b: 1, c: 2, d: 4 }
it "returns the processed keys and non evaluated keys if we break from the block" do
@hash.transform_keys! do |v|
break if v == :c
v.succ
end
@hash.should == { b: 1, c: 2, d: 4 }
end
it "keeps later pair if new keys conflict" do
@ -129,7 +117,7 @@ describe "Hash#transform_keys!" do
end
it "raises a FrozenError on hash argument" do
->{ @hash.transform_keys!({ a: :A, b: :B, c: :C }) }.should raise_error(FrozenError)
->{ @hash.transform_keys!({ a: :A, b: :B, c: :C }) }.should raise_error(FrozenError)
end
context "when no block is given" do

View File

@ -1,50 +1,48 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
ruby_version_is "3.1" do
describe "Integer.try_convert" do
it "returns the argument if it's an Integer" do
x = 42
Integer.try_convert(x).should equal(x)
end
describe "Integer.try_convert" do
it "returns the argument if it's an Integer" do
x = 42
Integer.try_convert(x).should equal(x)
end
it "returns nil when the argument does not respond to #to_int" do
Integer.try_convert(Object.new).should be_nil
end
it "returns nil when the argument does not respond to #to_int" do
Integer.try_convert(Object.new).should be_nil
end
it "sends #to_int to the argument and returns the result if it's nil" do
obj = mock("to_int")
obj.should_receive(:to_int).and_return(nil)
Integer.try_convert(obj).should be_nil
end
it "sends #to_int to the argument and returns the result if it's nil" do
obj = mock("to_int")
obj.should_receive(:to_int).and_return(nil)
Integer.try_convert(obj).should be_nil
end
it "sends #to_int to the argument and returns the result if it's an Integer" do
x = 234
obj = mock("to_int")
obj.should_receive(:to_int).and_return(x)
Integer.try_convert(obj).should equal(x)
end
it "sends #to_int to the argument and returns the result if it's an Integer" do
x = 234
obj = mock("to_int")
obj.should_receive(:to_int).and_return(x)
Integer.try_convert(obj).should equal(x)
end
it "sends #to_int to the argument and raises TypeError if it's not a kind of Integer" do
obj = mock("to_int")
obj.should_receive(:to_int).and_return(Object.new)
-> {
Integer.try_convert obj
}.should raise_error(TypeError, "can't convert MockObject to Integer (MockObject#to_int gives Object)")
end
it "sends #to_int to the argument and raises TypeError if it's not a kind of Integer" do
obj = mock("to_int")
obj.should_receive(:to_int).and_return(Object.new)
-> {
Integer.try_convert obj
}.should raise_error(TypeError, "can't convert MockObject to Integer (MockObject#to_int gives Object)")
end
it "responds with a different error message when it raises a TypeError, depending on the type of the non-Integer object :to_int returns" do
obj = mock("to_int")
obj.should_receive(:to_int).and_return("A String")
-> {
Integer.try_convert obj
}.should raise_error(TypeError, "can't convert MockObject to Integer (MockObject#to_int gives String)")
end
it "responds with a different error message when it raises a TypeError, depending on the type of the non-Integer object :to_int returns" do
obj = mock("to_int")
obj.should_receive(:to_int).and_return("A String")
-> {
Integer.try_convert obj
}.should raise_error(TypeError, "can't convert MockObject to Integer (MockObject#to_int gives String)")
end
it "does not rescue exceptions raised by #to_int" do
obj = mock("to_int")
obj.should_receive(:to_int).and_raise(RuntimeError)
-> { Integer.try_convert obj }.should raise_error(RuntimeError)
end
it "does not rescue exceptions raised by #to_int" do
obj = mock("to_int")
obj.should_receive(:to_int).and_raise(RuntimeError)
-> { Integer.try_convert obj }.should raise_error(RuntimeError)
end
end

View File

@ -94,12 +94,10 @@ describe "IO#external_encoding" do
rm_r @name
end
ruby_version_is '3.1' do
it "can be retrieved from a closed stream" do
io = IOSpecs.io_fixture("lines.txt", "r")
io.close
io.external_encoding.should equal(Encoding.default_external)
end
it "can be retrieved from a closed stream" do
io = IOSpecs.io_fixture("lines.txt", "r")
io.close
io.external_encoding.should equal(Encoding.default_external)
end
describe "with 'r' mode" do

View File

@ -113,12 +113,10 @@ describe "IO#internal_encoding" do
Encoding.default_internal = @internal
end
ruby_version_is '3.1' do
it "can be retrieved from a closed stream" do
io = IOSpecs.io_fixture("lines.txt", "r")
io.close
io.internal_encoding.should equal(Encoding.default_internal)
end
it "can be retrieved from a closed stream" do
io = IOSpecs.io_fixture("lines.txt", "r")
io.close
io.internal_encoding.should equal(Encoding.default_internal)
end
describe "with 'r' mode" do

View File

@ -93,12 +93,10 @@ describe "IO#readpartial" do
@rd.readpartial(0).should == ""
end
ruby_bug "#18421", ""..."3.0.4" do
it "clears and returns the given buffer if the length argument is 0" do
buffer = +"existing content"
@rd.readpartial(0, buffer).should == buffer
buffer.should == ""
end
it "clears and returns the given buffer if the length argument is 0" do
buffer = +"existing content"
@rd.readpartial(0, buffer).should == buffer
buffer.should == ""
end
it "preserves the encoding of the given buffer" do

View File

@ -43,7 +43,7 @@ platform_is_not :windows do
it "checks if the file is writable if writing zero bytes" do
-> {
@readonly_file.write_nonblock("")
@readonly_file.write_nonblock("")
}.should raise_error(IOError)
end
end

View File

@ -5,15 +5,20 @@ describe :kernel_block_given, shared: true do
it "returns true if and only if a block is supplied" do
@object.accept_block {}.should == true
@object.accept_block_as_argument {}.should == true
@object.accept_block_inside_block {}.should == true
@object.accept_block_as_argument_inside_block {}.should == true
@object.accept_block.should == false
@object.accept_block_as_argument.should == false
@object.accept_block_inside_block.should == false
@object.accept_block_as_argument_inside_block.should == false
end
# Clarify: Based on http://www.ruby-forum.com/topic/137822 it appears
# that Matz wanted this to be true in 1.9.
it "returns false when a method defined by define_method is called with a block" do
@object.defined_block {}.should == false
@object.defined_block_inside_block {}.should == false
end
end

View File

@ -313,6 +313,8 @@ CODE
eval(code)
EvalSpecs.constants(false).should include(:"")
EvalSpecs::.should == 3.14
ensure
EvalSpecs.send(:remove_const, :Vπ)
end
it "allows an emacs-style magic comment encoding" do
@ -326,6 +328,8 @@ CODE
eval(code)
EvalSpecs.constants(false).should include(:"Vπemacs")
EvalSpecs::Vπemacs.should == 3.14
ensure
EvalSpecs.send(:remove_const, :Vπemacs)
end
it "allows spaces before the magic encoding comment" do
@ -339,6 +343,8 @@ CODE
eval(code)
EvalSpecs.constants(false).should include(:"Vπspaces")
EvalSpecs::Vπspaces.should == 3.14
ensure
EvalSpecs.send(:remove_const, :Vπspaces)
end
it "allows a shebang line before the magic encoding comment" do
@ -353,6 +359,8 @@ CODE
eval(code)
EvalSpecs.constants(false).should include(:"Vπshebang")
EvalSpecs::Vπshebang.should == 3.14
ensure
EvalSpecs.send(:remove_const, :Vπshebang)
end
it "allows a shebang line and some spaces before the magic encoding comment" do
@ -367,6 +375,8 @@ CODE
eval(code)
EvalSpecs.constants(false).should include(:"Vπshebang_spaces")
EvalSpecs::Vπshebang_spaces.should == 3.14
ensure
EvalSpecs.send(:remove_const, :Vπshebang_spaces)
end
it "allows a magic encoding comment and a subsequent frozen_string_literal magic comment" do
@ -385,6 +395,8 @@ CODE
EvalSpecs::Vπstring.should == "frozen"
EvalSpecs::Vπstring.encoding.should == Encoding::UTF_8
EvalSpecs::Vπstring.frozen?.should == !frozen_string_default
ensure
EvalSpecs.send(:remove_const, :Vπstring)
end
it "allows a magic encoding comment and a frozen_string_literal magic comment on the same line in emacs style" do
@ -400,6 +412,8 @@ CODE
EvalSpecs::Vπsame_line.should == "frozen"
EvalSpecs::Vπsame_line.encoding.should == Encoding::UTF_8
EvalSpecs::Vπsame_line.frozen?.should be_true
ensure
EvalSpecs.send(:remove_const, :Vπsame_line)
end
it "ignores the magic encoding comment if it is after a frozen_string_literal magic comment" do
@ -420,6 +434,8 @@ CODE
value.should == "frozen"
value.encoding.should == Encoding::BINARY
value.frozen?.should == !frozen_string_default
ensure
EvalSpecs.send(:remove_const, binary_constant)
end
it "ignores the frozen_string_literal magic comment if it appears after a token and warns if $VERBOSE is true" do

View File

@ -219,10 +219,28 @@ module KernelSpecs
block_given?
end
def self.accept_block_inside_block()
yield_self {
block_given?
}
end
def self.accept_block_as_argument_inside_block(&block)
yield_self {
block_given?
}
end
class << self
define_method(:defined_block) do
block_given?
end
define_method(:defined_block_inside_block) do
yield_self {
block_given?
}
end
end
end
@ -235,10 +253,28 @@ module KernelSpecs
self.send(:block_given?)
end
def self.accept_block_inside_block
yield_self {
self.send(:block_given?)
}
end
def self.accept_block_as_argument_inside_block(&block)
yield_self {
self.send(:block_given?)
}
end
class << self
define_method(:defined_block) do
self.send(:block_given?)
end
define_method(:defined_block_inside_block) do
yield_self {
self.send(:block_given?)
}
end
end
end
@ -251,10 +287,28 @@ module KernelSpecs
Kernel.block_given?
end
def self.accept_block_inside_block
yield_self {
Kernel.block_given?
}
end
def self.accept_block_as_argument_inside_block(&block)
yield_self {
Kernel.block_given?
}
end
class << self
define_method(:defined_block) do
Kernel.block_given?
end
define_method(:defined_block_inside_block) do
yield_self {
Kernel.block_given?
}
end
end
end

View File

@ -16,10 +16,7 @@ describe "Kernel#require" do
Kernel.should have_private_instance_method(:require)
end
provided = %w[complex enumerator rational thread ruby2_keywords]
ruby_version_is "3.1" do
provided << "fiber"
end
provided = %w[complex enumerator fiber rational thread ruby2_keywords]
it "#{provided.join(', ')} are already required" do
out = ruby_exe("puts $LOADED_FEATURES", options: '--disable-gems --disable-did-you-mean')

View File

@ -165,37 +165,35 @@ describe :kernel_load, shared: true do
end
describe "when passed a module for 'wrap'" do
ruby_version_is "3.1" do
it "sets the enclosing scope to the supplied module" do
path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
mod = Module.new
@object.load(path, mod)
it "sets the enclosing scope to the supplied module" do
path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
mod = Module.new
@object.load(path, mod)
Object.const_defined?(:LoadSpecWrap).should be_false
mod.const_defined?(:LoadSpecWrap).should be_true
Object.const_defined?(:LoadSpecWrap).should be_false
mod.const_defined?(:LoadSpecWrap).should be_true
wrap_module = ScratchPad.recorded[1]
wrap_module.should == mod
end
wrap_module = ScratchPad.recorded[1]
wrap_module.should == mod
end
it "makes constants and instance methods in the source file reachable with the supplied module" do
path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
mod = Module.new
@object.load(path, mod)
it "makes constants and instance methods in the source file reachable with the supplied module" do
path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
mod = Module.new
@object.load(path, mod)
mod::LOAD_WRAP_SPECS_TOP_LEVEL_CONSTANT.should == 1
obj = Object.new
obj.extend(mod)
obj.send(:load_wrap_specs_top_level_method).should == :load_wrap_specs_top_level_method
end
mod::LOAD_WRAP_SPECS_TOP_LEVEL_CONSTANT.should == 1
obj = Object.new
obj.extend(mod)
obj.send(:load_wrap_specs_top_level_method).should == :load_wrap_specs_top_level_method
end
it "makes instance methods in the source file private" do
path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
mod = Module.new
@object.load(path, mod)
it "makes instance methods in the source file private" do
path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
mod = Module.new
@object.load(path, mod)
mod.private_instance_methods.include?(:load_wrap_specs_top_level_method).should == true
end
mod.private_instance_methods.include?(:load_wrap_specs_top_level_method).should == true
end
end

View File

@ -30,16 +30,8 @@ describe "main#private" do
end
end
ruby_version_is ''...'3.1' do
it "returns Object" do
eval("private :main_public_method", TOPLEVEL_BINDING).should equal(Object)
end
end
ruby_version_is '3.1' do
it "returns argument" do
eval("private :main_public_method", TOPLEVEL_BINDING).should equal(:main_public_method)
end
it "returns argument" do
eval("private :main_public_method", TOPLEVEL_BINDING).should equal(:main_public_method)
end
it "raises a NameError when at least one of given method names is undefined" do

View File

@ -30,16 +30,8 @@ describe "main#public" do
end
end
ruby_version_is ''...'3.1' do
it "returns Object" do
eval("public :main_private_method", TOPLEVEL_BINDING).should equal(Object)
end
end
ruby_version_is '3.1' do
it "returns argument" do
eval("public :main_private_method", TOPLEVEL_BINDING).should equal(:main_private_method)
end
it "returns argument" do
eval("public :main_private_method", TOPLEVEL_BINDING).should equal(:main_private_method)
end

View File

@ -599,20 +599,18 @@ describe "Marshal.dump" do
Marshal.dump(Hash.new(1)).should == "\004\b}\000i\006"
end
ruby_version_is "3.1" do
it "dumps a Hash with compare_by_identity" do
h = {}
h.compare_by_identity
it "dumps a Hash with compare_by_identity" do
h = {}
h.compare_by_identity
Marshal.dump(h).should == "\004\bC:\tHash{\x00"
end
Marshal.dump(h).should == "\004\bC:\tHash{\x00"
end
it "dumps a Hash subclass with compare_by_identity" do
h = UserHash.new
h.compare_by_identity
it "dumps a Hash subclass with compare_by_identity" do
h = UserHash.new
h.compare_by_identity
Marshal.dump(h).should == "\x04\bC:\rUserHashC:\tHash{\x00"
end
Marshal.dump(h).should == "\x04\bC:\rUserHashC:\tHash{\x00"
end
it "raises a TypeError with hash having default proc" do

View File

@ -23,224 +23,220 @@ describe :marshal_load, shared: true do
-> { Marshal.send(@method, kaboom) }.should raise_error(ArgumentError)
end
ruby_version_is "3.1" do
describe "when called with freeze: true" do
it "returns frozen strings" do
string = Marshal.send(@method, Marshal.dump("foo"), freeze: true)
string.should == "foo"
string.should.frozen?
describe "when called with freeze: true" do
it "returns frozen strings" do
string = Marshal.send(@method, Marshal.dump("foo"), freeze: true)
string.should == "foo"
string.should.frozen?
utf8_string = "foo".encode(Encoding::UTF_8)
string = Marshal.send(@method, Marshal.dump(utf8_string), freeze: true)
string.should == utf8_string
string.should.frozen?
utf8_string = "foo".encode(Encoding::UTF_8)
string = Marshal.send(@method, Marshal.dump(utf8_string), freeze: true)
string.should == utf8_string
string.should.frozen?
end
it "returns frozen arrays" do
array = Marshal.send(@method, Marshal.dump([1, 2, 3]), freeze: true)
array.should == [1, 2, 3]
array.should.frozen?
end
it "returns frozen hashes" do
hash = Marshal.send(@method, Marshal.dump({foo: 42}), freeze: true)
hash.should == {foo: 42}
hash.should.frozen?
end
it "returns frozen regexps" do
regexp = Marshal.send(@method, Marshal.dump(/foo/), freeze: true)
regexp.should == /foo/
regexp.should.frozen?
end
it "returns frozen structs" do
struct = Marshal.send(@method, Marshal.dump(MarshalSpec::StructToDump.new(1, 2)), freeze: true)
struct.should == MarshalSpec::StructToDump.new(1, 2)
struct.should.frozen?
end
it "returns frozen objects" do
source_object = Object.new
object = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
object.should.frozen?
end
describe "deep freezing" do
it "returns hashes with frozen keys and values" do
key = Object.new
value = Object.new
source_object = {key => value}
hash = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
hash.size.should == 1
hash.keys[0].should.frozen?
hash.values[0].should.frozen?
end
it "returns frozen arrays" do
array = Marshal.send(@method, Marshal.dump([1, 2, 3]), freeze: true)
array.should == [1, 2, 3]
array.should.frozen?
it "returns arrays with frozen elements" do
object = Object.new
source_object = [object]
array = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
array.size.should == 1
array[0].should.frozen?
end
it "returns frozen hashes" do
hash = Marshal.send(@method, Marshal.dump({foo: 42}), freeze: true)
hash.should == {foo: 42}
hash.should.frozen?
it "returns structs with frozen members" do
object1 = Object.new
object2 = Object.new
source_object = MarshalSpec::StructToDump.new(object1, object2)
struct = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
struct.a.should.frozen?
struct.b.should.frozen?
end
it "returns frozen regexps" do
regexp = Marshal.send(@method, Marshal.dump(/foo/), freeze: true)
regexp.should == /foo/
regexp.should.frozen?
end
it "returns frozen structs" do
struct = Marshal.send(@method, Marshal.dump(MarshalSpec::StructToDump.new(1, 2)), freeze: true)
struct.should == MarshalSpec::StructToDump.new(1, 2)
struct.should.frozen?
end
it "returns frozen objects" do
it "returns objects with frozen instance variables" do
source_object = Object.new
instance_variable = Object.new
source_object.instance_variable_set(:@a, instance_variable)
object = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
object.instance_variable_get(:@a).should != nil
object.instance_variable_get(:@a).should.frozen?
end
it "deduplicates frozen strings" do
source_object = ["foo" + "bar", "foobar"]
object = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
object[0].should equal(object[1])
end
end
it "does not freeze modules" do
object = Marshal.send(@method, Marshal.dump(Kernel), freeze: true)
object.should_not.frozen?
Kernel.should_not.frozen?
end
it "does not freeze classes" do
object = Marshal.send(@method, Marshal.dump(Object), freeze: true)
object.should_not.frozen?
Object.should_not.frozen?
end
ruby_bug "#19427", ""..."3.3" do
it "does freeze extended objects" do
object = Marshal.load("\x04\be:\x0FEnumerableo:\vObject\x00", freeze: true)
object.should.frozen?
end
describe "deep freezing" do
it "returns hashes with frozen keys and values" do
key = Object.new
value = Object.new
source_object = {key => value}
it "does freeze extended objects with instance variables" do
object = Marshal.load("\x04\be:\x0FEnumerableo:\vObject\x06:\n@ivarT", freeze: true)
object.should.frozen?
end
end
hash = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
hash.size.should == 1
hash.keys[0].should.frozen?
hash.values[0].should.frozen?
end
it "returns arrays with frozen elements" do
object = Object.new
source_object = [object]
array = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
array.size.should == 1
array[0].should.frozen?
end
it "returns structs with frozen members" do
object1 = Object.new
object2 = Object.new
source_object = MarshalSpec::StructToDump.new(object1, object2)
struct = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
struct.a.should.frozen?
struct.b.should.frozen?
end
it "returns objects with frozen instance variables" do
source_object = Object.new
instance_variable = Object.new
source_object.instance_variable_set(:@a, instance_variable)
object = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
object.instance_variable_get(:@a).should != nil
object.instance_variable_get(:@a).should.frozen?
end
it "deduplicates frozen strings" do
source_object = ["foo" + "bar", "foobar"]
object = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
object[0].should equal(object[1])
end
ruby_bug "#19427", "3.1"..."3.3" do
it "returns frozen object having #_dump method" do
object = Marshal.send(@method, Marshal.dump(UserDefined.new), freeze: true)
object.should.frozen?
end
it "does not freeze modules" do
object = Marshal.send(@method, Marshal.dump(Kernel), freeze: true)
object.should_not.frozen?
Kernel.should_not.frozen?
it "returns frozen object responding to #marshal_dump and #marshal_load" do
object = Marshal.send(@method, Marshal.dump(UserMarshal.new), freeze: true)
object.should.frozen?
end
it "does not freeze classes" do
object = Marshal.send(@method, Marshal.dump(Object), freeze: true)
object.should_not.frozen?
Object.should_not.frozen?
end
it "returns frozen object extended by a module" do
object = Object.new
object.extend(MarshalSpec::ModuleToExtendBy)
ruby_bug "#19427", ""..."3.3" do
it "does freeze extended objects" do
object = Marshal.load("\x04\be:\x0FEnumerableo:\vObject\x00", freeze: true)
object.should.frozen?
end
it "does freeze extended objects with instance variables" do
object = Marshal.load("\x04\be:\x0FEnumerableo:\vObject\x06:\n@ivarT", freeze: true)
object.should.frozen?
end
end
ruby_bug "#19427", "3.1"..."3.3" do
it "returns frozen object having #_dump method" do
object = Marshal.send(@method, Marshal.dump(UserDefined.new), freeze: true)
object.should.frozen?
end
it "returns frozen object responding to #marshal_dump and #marshal_load" do
object = Marshal.send(@method, Marshal.dump(UserMarshal.new), freeze: true)
object.should.frozen?
end
it "returns frozen object extended by a module" do
object = Object.new
object.extend(MarshalSpec::ModuleToExtendBy)
object = Marshal.send(@method, Marshal.dump(object), freeze: true)
object.should.frozen?
end
end
it "does not call freeze method" do
object = MarshalSpec::ObjectWithFreezeRaisingException.new
object = Marshal.send(@method, Marshal.dump(object), freeze: true)
object.should.frozen?
end
end
it "returns frozen object even if object does not respond to freeze method" do
object = MarshalSpec::ObjectWithoutFreeze.new
object = Marshal.send(@method, Marshal.dump(object), freeze: true)
object.should.frozen?
end
it "does not call freeze method" do
object = MarshalSpec::ObjectWithFreezeRaisingException.new
object = Marshal.send(@method, Marshal.dump(object), freeze: true)
object.should.frozen?
end
it "returns a frozen object when is an instance of String/Array/Regexp/Hash subclass and has instance variables" do
source_object = UserString.new
source_object.instance_variable_set(:@foo, "bar")
it "returns frozen object even if object does not respond to freeze method" do
object = MarshalSpec::ObjectWithoutFreeze.new
object = Marshal.send(@method, Marshal.dump(object), freeze: true)
object.should.frozen?
end
object = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
object.should.frozen?
end
it "returns a frozen object when is an instance of String/Array/Regexp/Hash subclass and has instance variables" do
source_object = UserString.new
source_object.instance_variable_set(:@foo, "bar")
describe "when called with a proc" do
it "call the proc with frozen objects" do
arr = []
s = +'hi'
s.instance_variable_set(:@foo, 5)
st = Struct.new("Brittle", :a).new
st.instance_variable_set(:@clue, 'none')
st.a = 0.0
h = Hash.new('def')
h['nine'] = 9
a = [:a, :b, :c]
a.instance_variable_set(:@two, 2)
obj = [s, 10, s, s, st, a]
obj.instance_variable_set(:@zoo, 'ant')
proc = Proc.new { |o| arr << o; o}
object = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
object.should.frozen?
end
Marshal.send(
@method,
"\x04\bI[\vI\"\ahi\a:\x06EF:\t@fooi\ni\x0F@\x06@\x06IS:\x14Struct::Brittle\x06:\x06af\x060\x06:\n@clueI\"\tnone\x06;\x00FI[\b;\b:\x06b:\x06c\x06:\t@twoi\a\x06:\t@zooI\"\bant\x06;\x00F",
proc,
freeze: true,
)
describe "when called with a proc" do
it "call the proc with frozen objects" do
arr = []
s = +'hi'
s.instance_variable_set(:@foo, 5)
st = Struct.new("Brittle", :a).new
st.instance_variable_set(:@clue, 'none')
st.a = 0.0
h = Hash.new('def')
h['nine'] = 9
a = [:a, :b, :c]
a.instance_variable_set(:@two, 2)
obj = [s, 10, s, s, st, a]
obj.instance_variable_set(:@zoo, 'ant')
proc = Proc.new { |o| arr << o; o}
arr.should == [
false, 5, "hi", 10, "hi", "hi", 0.0, false, "none", st,
:b, :c, 2, a, false, "ant", ["hi", 10, "hi", "hi", st, [:a, :b, :c]],
]
Marshal.send(
@method,
"\x04\bI[\vI\"\ahi\a:\x06EF:\t@fooi\ni\x0F@\x06@\x06IS:\x14Struct::Brittle\x06:\x06af\x060\x06:\n@clueI\"\tnone\x06;\x00FI[\b;\b:\x06b:\x06c\x06:\t@twoi\a\x06:\t@zooI\"\bant\x06;\x00F",
proc,
freeze: true,
)
arr.each do |v|
v.should.frozen?
end
arr.should == [
false, 5, "hi", 10, "hi", "hi", 0.0, false, "none", st,
:b, :c, 2, a, false, "ant", ["hi", 10, "hi", "hi", st, [:a, :b, :c]],
]
Struct.send(:remove_const, :Brittle)
arr.each do |v|
v.should.frozen?
end
it "does not freeze the object returned by the proc" do
string = Marshal.send(@method, Marshal.dump("foo"), proc { |o| o.upcase }, freeze: true)
string.should == "FOO"
string.should_not.frozen?
end
Struct.send(:remove_const, :Brittle)
end
it "does not freeze the object returned by the proc" do
string = Marshal.send(@method, Marshal.dump("foo"), proc { |o| o.upcase }, freeze: true)
string.should == "FOO"
string.should_not.frozen?
end
end
end
describe "when called with a proc" do
ruby_bug "#18141", ""..."3.1" do
it "call the proc with fully initialized strings" do
utf8_string = "foo".encode(Encoding::UTF_8)
Marshal.send(@method, Marshal.dump(utf8_string), proc { |arg|
if arg.is_a?(String)
arg.should == utf8_string
arg.encoding.should == Encoding::UTF_8
end
arg
})
end
it "call the proc with fully initialized strings" do
utf8_string = "foo".encode(Encoding::UTF_8)
Marshal.send(@method, Marshal.dump(utf8_string), proc { |arg|
if arg.is_a?(String)
arg.should == utf8_string
arg.encoding.should == Encoding::UTF_8
end
arg
})
end
it "no longer mutate the object after it was passed to the proc" do
string = Marshal.load(Marshal.dump("foo"), :freeze.to_proc)
string.should.frozen?
end
it "no longer mutate the object after it was passed to the proc" do
string = Marshal.load(Marshal.dump("foo"), :freeze.to_proc)
string.should.frozen?
end
ruby_bug "#19427", ""..."3.3" do
@ -255,40 +251,38 @@ describe :marshal_load, shared: true do
Marshal.send(@method, Marshal.dump([1,2]), proc { [3,4] }).should == [3,4]
end
ruby_bug "#18141", ""..."3.1" do
it "calls the proc for recursively visited data" do
a = [1]
a << a
ret = []
Marshal.send(@method, Marshal.dump(a), proc { |arg| ret << arg.inspect; arg })
ret[0].should == 1.inspect
ret[1].should == a.inspect
ret.size.should == 2
end
it "calls the proc for recursively visited data" do
a = [1]
a << a
ret = []
Marshal.send(@method, Marshal.dump(a), proc { |arg| ret << arg.inspect; arg })
ret[0].should == 1.inspect
ret[1].should == a.inspect
ret.size.should == 2
end
it "loads an Array with proc" do
arr = []
s = +'hi'
s.instance_variable_set(:@foo, 5)
st = Struct.new("Brittle", :a).new
st.instance_variable_set(:@clue, 'none')
st.a = 0.0
h = Hash.new('def')
h['nine'] = 9
a = [:a, :b, :c]
a.instance_variable_set(:@two, 2)
obj = [s, 10, s, s, st, a]
obj.instance_variable_set(:@zoo, 'ant')
proc = Proc.new { |o| arr << o.dup; o}
it "loads an Array with proc" do
arr = []
s = +'hi'
s.instance_variable_set(:@foo, 5)
st = Struct.new("Brittle", :a).new
st.instance_variable_set(:@clue, 'none')
st.a = 0.0
h = Hash.new('def')
h['nine'] = 9
a = [:a, :b, :c]
a.instance_variable_set(:@two, 2)
obj = [s, 10, s, s, st, a]
obj.instance_variable_set(:@zoo, 'ant')
proc = Proc.new { |o| arr << o.dup; o}
Marshal.send(@method, "\x04\bI[\vI\"\ahi\a:\x06EF:\t@fooi\ni\x0F@\x06@\x06IS:\x14Struct::Brittle\x06:\x06af\x060\x06:\n@clueI\"\tnone\x06;\x00FI[\b;\b:\x06b:\x06c\x06:\t@twoi\a\x06:\t@zooI\"\bant\x06;\x00F", proc)
Marshal.send(@method, "\x04\bI[\vI\"\ahi\a:\x06EF:\t@fooi\ni\x0F@\x06@\x06IS:\x14Struct::Brittle\x06:\x06af\x060\x06:\n@clueI\"\tnone\x06;\x00FI[\b;\b:\x06b:\x06c\x06:\t@twoi\a\x06:\t@zooI\"\bant\x06;\x00F", proc)
arr.should == [
false, 5, "hi", 10, "hi", "hi", 0.0, false, "none", st,
:b, :c, 2, a, false, "ant", ["hi", 10, "hi", "hi", st, [:a, :b, :c]],
]
Struct.send(:remove_const, :Brittle)
end
arr.should == [
false, 5, "hi", 10, "hi", "hi", 0.0, false, "none", st,
:b, :c, 2, a, false, "ant", ["hi", 10, "hi", "hi", st, [:a, :b, :c]],
]
Struct.send(:remove_const, :Brittle)
end
end
@ -364,39 +358,37 @@ describe :marshal_load, shared: true do
end
end
ruby_bug "#18141", ""..."3.1" do
it "loads an array containing objects having _dump method, and with proc" do
arr = []
myproc = Proc.new { |o| arr << o.dup; o }
o1 = UserDefined.new;
o2 = UserDefinedWithIvar.new
obj = [o1, o2, o1, o2]
it "loads an array containing objects having _dump method, and with proc" do
arr = []
myproc = Proc.new { |o| arr << o.dup; o }
o1 = UserDefined.new;
o2 = UserDefinedWithIvar.new
obj = [o1, o2, o1, o2]
Marshal.send(@method, "\x04\b[\tu:\x10UserDefined\x18\x04\b[\aI\"\nstuff\x06:\x06EF@\x06u:\x18UserDefinedWithIvar>\x04\b[\bI\"\nstuff\a:\x06EF:\t@foo:\x18UserDefinedWithIvarI\"\tmore\x06;\x00F@\a@\x06@\a", myproc)
Marshal.send(@method, "\x04\b[\tu:\x10UserDefined\x18\x04\b[\aI\"\nstuff\x06:\x06EF@\x06u:\x18UserDefinedWithIvar>\x04\b[\bI\"\nstuff\a:\x06EF:\t@foo:\x18UserDefinedWithIvarI\"\tmore\x06;\x00F@\a@\x06@\a", myproc)
arr[0].should == o1
arr[1].should == o2
arr[2].should == obj
arr.size.should == 3
end
arr[0].should == o1
arr[1].should == o2
arr[2].should == obj
arr.size.should == 3
end
it "loads an array containing objects having marshal_dump method, and with proc" do
arr = []
proc = Proc.new { |o| arr << o.dup; o }
o1 = UserMarshal.new
o2 = UserMarshalWithIvar.new
it "loads an array containing objects having marshal_dump method, and with proc" do
arr = []
proc = Proc.new { |o| arr << o.dup; o }
o1 = UserMarshal.new
o2 = UserMarshalWithIvar.new
Marshal.send(@method, "\004\b[\tU:\020UserMarshal\"\nstuffU:\030UserMarshalWithIvar[\006\"\fmy data@\006@\b", proc)
Marshal.send(@method, "\004\b[\tU:\020UserMarshal\"\nstuffU:\030UserMarshalWithIvar[\006\"\fmy data@\006@\b", proc)
arr[0].should == 'stuff'
arr[1].should == o1
arr[2].should == 'my data'
arr[3].should == ['my data']
arr[4].should == o2
arr[5].should == [o1, o2, o1, o2]
arr[0].should == 'stuff'
arr[1].should == o1
arr[2].should == 'my data'
arr[3].should == ['my data']
arr[4].should == o2
arr[5].should == [o1, o2, o1, o2]
arr.size.should == 6
end
arr.size.should == 6
end
it "assigns classes to nested subclasses of Array correctly" do
@ -526,28 +518,26 @@ describe :marshal_load, shared: true do
unmarshalled[:key].instance_variable_get(:@string_ivar).should == 'string ivar'
end
ruby_version_is "3.1" do
it "preserves compare_by_identity behaviour" do
h = { a: 1 }
h.compare_by_identity
unmarshalled = Marshal.send(@method, Marshal.dump(h))
unmarshalled.should.compare_by_identity?
it "preserves compare_by_identity behaviour" do
h = { a: 1 }
h.compare_by_identity
unmarshalled = Marshal.send(@method, Marshal.dump(h))
unmarshalled.should.compare_by_identity?
h = { a: 1 }
unmarshalled = Marshal.send(@method, Marshal.dump(h))
unmarshalled.should_not.compare_by_identity?
end
h = { a: 1 }
unmarshalled = Marshal.send(@method, Marshal.dump(h))
unmarshalled.should_not.compare_by_identity?
end
it "preserves compare_by_identity behaviour for a Hash subclass" do
h = UserHash.new({ a: 1 })
h.compare_by_identity
unmarshalled = Marshal.send(@method, Marshal.dump(h))
unmarshalled.should.compare_by_identity?
it "preserves compare_by_identity behaviour for a Hash subclass" do
h = UserHash.new({ a: 1 })
h.compare_by_identity
unmarshalled = Marshal.send(@method, Marshal.dump(h))
unmarshalled.should.compare_by_identity?
h = UserHash.new({ a: 1 })
unmarshalled = Marshal.send(@method, Marshal.dump(h))
unmarshalled.should_not.compare_by_identity?
end
h = UserHash.new({ a: 1 })
unmarshalled = Marshal.send(@method, Marshal.dump(h))
unmarshalled.should_not.compare_by_identity?
end
it "allocates an instance of the proper class when Hash subclass with compare_by_identity behaviour" do

View File

@ -2,33 +2,31 @@
require_relative '../../spec_helper'
ruby_version_is "3.1" do
describe "MatchData#match_length" do
it "returns the length of the corresponding match when given an Integer" do
md = /(.)(.)(\d+)(\d)/.match("THX1138.")
describe "MatchData#match_length" do
it "returns the length of the corresponding match when given an Integer" do
md = /(.)(.)(\d+)(\d)/.match("THX1138.")
md.match_length(0).should == 6
md.match_length(1).should == 1
md.match_length(2).should == 1
md.match_length(3).should == 3
md.match_length(4).should == 1
end
md.match_length(0).should == 6
md.match_length(1).should == 1
md.match_length(2).should == 1
md.match_length(3).should == 3
md.match_length(4).should == 1
end
it "returns nil on non-matching index matches" do
md = /\d+(\w)?/.match("THX1138.")
md.match_length(1).should == nil
end
it "returns nil on non-matching index matches" do
md = /\d+(\w)?/.match("THX1138.")
md.match_length(1).should == nil
end
it "returns the length of the corresponding named match when given a Symbol" do
md = 'haystack'.match(/(?<t>t(?<a>ack))/)
md.match_length(:a).should == 3
md.match_length(:t).should == 4
end
it "returns the length of the corresponding named match when given a Symbol" do
md = 'haystack'.match(/(?<t>t(?<a>ack))/)
md.match_length(:a).should == 3
md.match_length(:t).should == 4
end
it "returns nil on non-matching index matches" do
md = 'haystack'.match(/(?<t>t)(?<a>all)?/)
md.match_length(:t).should == 1
md.match_length(:a).should == nil
end
it "returns nil on non-matching index matches" do
md = 'haystack'.match(/(?<t>t)(?<a>all)?/)
md.match_length(:t).should == 1
md.match_length(:a).should == nil
end
end

View File

@ -2,33 +2,31 @@
require_relative '../../spec_helper'
ruby_version_is "3.1" do
describe "MatchData#match" do
it "returns the corresponding match when given an Integer" do
md = /(.)(.)(\d+)(\d)/.match("THX1138.")
describe "MatchData#match" do
it "returns the corresponding match when given an Integer" do
md = /(.)(.)(\d+)(\d)/.match("THX1138.")
md.match(0).should == 'HX1138'
md.match(1).should == 'H'
md.match(2).should == 'X'
md.match(3).should == '113'
md.match(4).should == '8'
end
md.match(0).should == 'HX1138'
md.match(1).should == 'H'
md.match(2).should == 'X'
md.match(3).should == '113'
md.match(4).should == '8'
end
it "returns nil on non-matching index matches" do
md = /\d+(\w)?/.match("THX1138.")
md.match(1).should == nil
end
it "returns nil on non-matching index matches" do
md = /\d+(\w)?/.match("THX1138.")
md.match(1).should == nil
end
it "returns the corresponding named match when given a Symbol" do
md = 'haystack'.match(/(?<t>t(?<a>ack))/)
md.match(:a).should == 'ack'
md.match(:t).should == 'tack'
end
it "returns the corresponding named match when given a Symbol" do
md = 'haystack'.match(/(?<t>t(?<a>ack))/)
md.match(:a).should == 'ack'
md.match(:t).should == 'tack'
end
it "returns nil on non-matching index matches" do
md = 'haystack'.match(/(?<t>t)(?<a>all)?/)
md.match(:t).should == 't'
md.match(:a).should == nil
end
it "returns nil on non-matching index matches" do
md = 'haystack'.match(/(?<t>t)(?<a>all)?/)
md.match(:t).should == 't'
md.match(:a).should == nil
end
end

View File

@ -257,30 +257,17 @@ describe "Method#parameters" do
end
end
ruby_version_is '3.1' do
it "adds block arg with name & for anonymous block argument" do
object = Object.new
eval(<<~RUBY).should == [[:block, :&]]
def object.foo(&)
end
object.method(:foo).parameters
RUBY
it "adds block arg with name & for anonymous block argument" do
object = Object.new
def object.foo(&)
end
object.method(:foo).parameters.should == [[:block, :&]]
end
ruby_version_is ""..."3.1" do
it "returns [:rest, :*], [:block, :&] for forward parameters operator" do
m = MethodSpecs::Methods.new
m.method(:forward_parameters).parameters.should == [[:rest, :*], [:block, :&]]
end
end
ruby_version_is "3.1" do
it "returns [:rest, :*], [:keyrest, :**], [:block, :&] for forward parameters operator" do
m = MethodSpecs::Methods.new
m.method(:forward_parameters).parameters.should == [[:rest, :*], [:keyrest, :**], [:block, :&]]
end
it "returns [:rest, :*], [:keyrest, :**], [:block, :&] for forward parameters operator" do
m = MethodSpecs::Methods.new
m.method(:forward_parameters).parameters.should == [[:rest, :*], [:keyrest, :**], [:block, :&]]
end
it "returns the args and block for a splat and block argument" do

View File

@ -2,7 +2,7 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Method#private?" do
ruby_version_is "3.1"..."3.2" do
ruby_version_is ""..."3.2" do
it "returns false when the method is public" do
obj = MethodSpecs::Methods.new
obj.method(:my_public_method).private?.should == false

View File

@ -2,7 +2,7 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Method#protected?" do
ruby_version_is "3.1"..."3.2" do
ruby_version_is ""..."3.2" do
it "returns false when the method is public" do
obj = MethodSpecs::Methods.new
obj.method(:my_public_method).protected?.should == false

View File

@ -2,7 +2,7 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Method#public?" do
ruby_version_is "3.1"..."3.2" do
ruby_version_is ""..."3.2" do
it "returns true when the method is public" do
obj = MethodSpecs::Methods.new
obj.method(:my_public_method).public?.should == true

View File

@ -486,42 +486,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
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.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_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
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 have_constant(:O)
ModuleSpecs::Autoload.autoload?(:O).should == nil
-> { ModuleSpecs::Autoload.const_get(:O) }.should raise_error(NameError)
end
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
it "does not try to load the file again if the loaded file did not define the constant" do
@ -654,48 +633,23 @@ describe "Module#autoload" do
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
}
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
DeclaredInCurrentDefinedInParent.should == :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
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

View File

@ -65,6 +65,8 @@ describe "Module#const_defined?" do
str = "CS_CONSTλ".encode("euc-jp")
ConstantSpecs.const_set str, 1
ConstantSpecs.const_defined?(str).should be_true
ensure
ConstantSpecs.send(:remove_const, str)
end
it "returns false if the constant is not defined in the receiver, its superclass, or any included modules" do

View File

@ -131,7 +131,7 @@ describe "Module#const_get" do
end
it "does read private constants" do
ConstantSpecs.const_get(:CS_PRIVATE).should == :cs_private
ConstantSpecs.const_get(:CS_PRIVATE).should == :cs_private
end
it 'does autoload a constant' do
@ -202,40 +202,60 @@ describe "Module#const_get" do
ConstantSpecs::ContainerA::ChildA::CS_CONST301 = :const301_5
ConstantSpecs::ContainerA::ChildA.const_get(:CS_CONST301).should == :const301_5
ensure
ConstantSpecs::ClassA.send(:remove_const, :CS_CONST301)
ConstantSpecs::ModuleA.send(:remove_const, :CS_CONST301)
ConstantSpecs::ParentA.send(:remove_const, :CS_CONST301)
ConstantSpecs::ContainerA::ChildA.send(:remove_const, :CS_CONST301)
end
it "searches a module included in the immediate class before the superclass" do
ConstantSpecs::ParentB::CS_CONST302 = :const302_1
ConstantSpecs::ModuleF::CS_CONST302 = :const302_2
ConstantSpecs::ContainerB::ChildB.const_get(:CS_CONST302).should == :const302_2
ensure
ConstantSpecs::ParentB.send(:remove_const, :CS_CONST302)
ConstantSpecs::ModuleF.send(:remove_const, :CS_CONST302)
end
it "searches the superclass before a module included in the superclass" do
ConstantSpecs::ModuleE::CS_CONST303 = :const303_1
ConstantSpecs::ParentB::CS_CONST303 = :const303_2
ConstantSpecs::ContainerB::ChildB.const_get(:CS_CONST303).should == :const303_2
ensure
ConstantSpecs::ModuleE.send(:remove_const, :CS_CONST303)
ConstantSpecs::ParentB.send(:remove_const, :CS_CONST303)
end
it "searches a module included in the superclass" do
ConstantSpecs::ModuleA::CS_CONST304 = :const304_1
ConstantSpecs::ModuleE::CS_CONST304 = :const304_2
ConstantSpecs::ContainerB::ChildB.const_get(:CS_CONST304).should == :const304_2
ensure
ConstantSpecs::ModuleA.send(:remove_const, :CS_CONST304)
ConstantSpecs::ModuleE.send(:remove_const, :CS_CONST304)
end
it "searches the superclass chain" do
ConstantSpecs::ModuleA::CS_CONST305 = :const305
ConstantSpecs::ContainerB::ChildB.const_get(:CS_CONST305).should == :const305
ensure
ConstantSpecs::ModuleA.send(:remove_const, :CS_CONST305)
end
it "returns a toplevel constant when the receiver is a Class" do
Object::CS_CONST306 = :const306
ConstantSpecs::ContainerB::ChildB.const_get(:CS_CONST306).should == :const306
ensure
Object.send(:remove_const, :CS_CONST306)
end
it "returns a toplevel constant when the receiver is a Module" do
Object::CS_CONST308 = :const308
ConstantSpecs.const_get(:CS_CONST308).should == :const308
ConstantSpecs::ModuleA.const_get(:CS_CONST308).should == :const308
ensure
Object.send(:remove_const, :CS_CONST308)
end
it "returns the updated value of a constant" do
@ -246,6 +266,8 @@ describe "Module#const_get" do
ConstantSpecs::ClassB::CS_CONST309 = :const309_2
}.should complain(/already initialized constant/)
ConstantSpecs::ClassB.const_get(:CS_CONST309).should == :const309_2
ensure
ConstantSpecs::ClassB.send(:remove_const, :CS_CONST309)
end
end
end

View File

@ -8,16 +8,23 @@ describe "Module#const_set" do
ConstantSpecs.const_set "CS_CONST402", :const402
ConstantSpecs.const_get(:CS_CONST402).should == :const402
ensure
ConstantSpecs.send(:remove_const, :CS_CONST401)
ConstantSpecs.send(:remove_const, :CS_CONST402)
end
it "returns the value set" do
ConstantSpecs.const_set(:CS_CONST403, :const403).should == :const403
ensure
ConstantSpecs.send(:remove_const, :CS_CONST403)
end
it "sets the name of an anonymous module" do
m = Module.new
ConstantSpecs.const_set(:CS_CONST1000, m)
m.name.should == "ConstantSpecs::CS_CONST1000"
ensure
ConstantSpecs.send(:remove_const, :CS_CONST1000)
end
it "sets the name of a module scoped by an anonymous module" do
@ -38,6 +45,8 @@ describe "Module#const_set" do
b.name.should == "ModuleSpecs_CS3::B"
c.name.should == "ModuleSpecs_CS3::B::C"
d.name.should == "ModuleSpecs_CS3::D"
ensure
Object.send(:remove_const, :ModuleSpecs_CS3)
end
it "raises a NameError if the name does not start with a capital letter" do
@ -55,6 +64,8 @@ describe "Module#const_set" do
ConstantSpecs.const_set("CS_CONST404", :const404).should == :const404
-> { ConstantSpecs.const_set "Name=", 1 }.should raise_error(NameError)
-> { ConstantSpecs.const_set "Name?", 1 }.should raise_error(NameError)
ensure
ConstantSpecs.send(:remove_const, :CS_CONST404)
end
it "calls #to_str to convert the given name to a String" do
@ -62,6 +73,8 @@ describe "Module#const_set" do
name.should_receive(:to_str).and_return("CS_CONST405")
ConstantSpecs.const_set(name, :const405).should == :const405
ConstantSpecs::CS_CONST405.should == :const405
ensure
ConstantSpecs.send(:remove_const, :CS_CONST405)
end
it "raises a TypeError if conversion to a String by calling #to_str fails" do

View File

@ -19,40 +19,60 @@ describe "Module#const_source_location" do
ConstantSpecs::ContainerA::ChildA::CSL_CONST301 = :const301_5
ConstantSpecs::ContainerA::ChildA.const_source_location(:CSL_CONST301).should == [__FILE__, __LINE__ - 1]
ensure
ConstantSpecs::ClassA.send(:remove_const, :CSL_CONST301)
ConstantSpecs::ModuleA.send(:remove_const, :CSL_CONST301)
ConstantSpecs::ParentA.send(:remove_const, :CSL_CONST301)
ConstantSpecs::ContainerA::ChildA.send(:remove_const, :CSL_CONST301)
end
it "searches a path in a module included in the immediate class before the superclass" do
ConstantSpecs::ParentB::CSL_CONST302 = :const302_1
ConstantSpecs::ModuleF::CSL_CONST302 = :const302_2
ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST302).should == [__FILE__, __LINE__ - 1]
ensure
ConstantSpecs::ParentB.send(:remove_const, :CSL_CONST302)
ConstantSpecs::ModuleF.send(:remove_const, :CSL_CONST302)
end
it "searches a path in the superclass before a module included in the superclass" do
ConstantSpecs::ModuleE::CSL_CONST303 = :const303_1
ConstantSpecs::ParentB::CSL_CONST303 = :const303_2
ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST303).should == [__FILE__, __LINE__ - 1]
ensure
ConstantSpecs::ModuleE.send(:remove_const, :CSL_CONST303)
ConstantSpecs::ParentB.send(:remove_const, :CSL_CONST303)
end
it "searches a path in a module included in the superclass" do
ConstantSpecs::ModuleA::CSL_CONST304 = :const304_1
ConstantSpecs::ModuleE::CSL_CONST304 = :const304_2
ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST304).should == [__FILE__, __LINE__ - 1]
ensure
ConstantSpecs::ModuleA.send(:remove_const, :CSL_CONST304)
ConstantSpecs::ModuleE.send(:remove_const, :CSL_CONST304)
end
it "searches a path in the superclass chain" do
ConstantSpecs::ModuleA::CSL_CONST305 = :const305
ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST305).should == [__FILE__, __LINE__ - 1]
ensure
ConstantSpecs::ModuleA.send(:remove_const, :CSL_CONST305)
end
it "returns path to a toplevel constant when the receiver is a Class" do
Object::CSL_CONST306 = :const306
ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST306).should == [__FILE__, __LINE__ - 1]
ensure
Object.send(:remove_const, :CSL_CONST306)
end
it "returns path to a toplevel constant when the receiver is a Module" do
Object::CSL_CONST308 = :const308
ConstantSpecs.const_source_location(:CSL_CONST308).should == [__FILE__, __LINE__ - 1]
ConstantSpecs::ModuleA.const_source_location(:CSL_CONST308).should == [__FILE__, __LINE__ - 2]
ensure
Object.send(:remove_const, :CSL_CONST308)
end
it "returns path to the updated value of a constant" do
@ -63,6 +83,8 @@ describe "Module#const_source_location" do
ConstantSpecs::ClassB::CSL_CONST309 = :const309_2
}.should complain(/already initialized constant/)
ConstantSpecs::ClassB.const_source_location(:CSL_CONST309).should == [__FILE__, __LINE__ - 2]
ensure
ConstantSpecs::ClassB.send(:remove_const, :CSL_CONST309)
end
end
@ -207,7 +229,7 @@ describe "Module#const_source_location" do
end
it "does search private constants path" do
ConstantSpecs.const_source_location(:CS_PRIVATE).should == [@constants_fixture_path, ConstantSpecs::CS_PRIVATE_LINE]
ConstantSpecs.const_source_location(:CS_PRIVATE).should == [@constants_fixture_path, ConstantSpecs::CS_PRIVATE_LINE]
end
it "works for eval with a given line" do

View File

@ -476,6 +476,9 @@ describe "Module#define_method" do
ChildClass = Class.new(ParentClass) { define_method(:foo) { :baz } }
ParentClass.send :define_method, :foo, ChildClass.instance_method(:foo)
}.should raise_error(TypeError, /bind argument must be a subclass of ChildClass/)
ensure
Object.send(:remove_const, :ParentClass)
Object.send(:remove_const, :ChildClass)
end
it "raises a TypeError when an UnboundMethod from one class is defined on an unrelated class" do

View File

@ -44,7 +44,11 @@ describe "Module#include" do
end
it "does not raise a TypeError when the argument is an instance of a subclass of Module" do
-> { ModuleSpecs::SubclassSpec.include(ModuleSpecs::Subclass.new) }.should_not raise_error(TypeError)
class ModuleSpecs::SubclassSpec::AClass
end
-> { ModuleSpecs::SubclassSpec::AClass.include(ModuleSpecs::Subclass.new) }.should_not raise_error(TypeError)
ensure
ModuleSpecs::SubclassSpec.send(:remove_const, :AClass)
end
ruby_version_is ""..."3.2" do
@ -427,6 +431,8 @@ describe "Module#include" do
M.const_set(:FOO, 'm')
B.foo.should == 'm'
end
ensure
ModuleSpecs.send(:remove_const, :ConstUpdated)
end
it "updates the constant when a module included after a call is later updated" do
@ -453,6 +459,8 @@ describe "Module#include" do
M.const_set(:FOO, 'm')
B.foo.should == 'm'
end
ensure
ModuleSpecs.send(:remove_const, :ConstLaterUpdated)
end
it "updates the constant when a module included in another module after a call is later updated" do
@ -479,6 +487,8 @@ describe "Module#include" do
M.const_set(:FOO, 'm')
B.foo.should == 'm'
end
ensure
ModuleSpecs.send(:remove_const, :ConstModuleLaterUpdated)
end
it "updates the constant when a nested included module is updated" do
@ -507,6 +517,8 @@ describe "Module#include" do
N.const_set(:FOO, 'n')
B.foo.should == 'n'
end
ensure
ModuleSpecs.send(:remove_const, :ConstUpdatedNestedIncludeUpdated)
end
it "updates the constant when a new module is included" do
@ -531,6 +543,8 @@ describe "Module#include" do
B.include(M)
B.foo.should == 'm'
end
ensure
ModuleSpecs.send(:remove_const, :ConstUpdatedNewInclude)
end
it "updates the constant when a new module with nested module is included" do
@ -559,6 +573,8 @@ describe "Module#include" do
B.include M
B.foo.should == 'n'
end
ensure
ModuleSpecs.send(:remove_const, :ConstUpdatedNestedIncluded)
end
it "overrides a previous super method call" do

View File

@ -38,22 +38,11 @@ describe "Module#module_function with specific method names" do
m.respond_to?(:test3).should == false
end
ruby_version_is ""..."3.1" do
it "returns self" do
Module.new do
def foo; end
module_function(:foo).should equal(self)
end
end
end
ruby_version_is "3.1" do
it "returns argument or arguments if given" do
Module.new do
def foo; end
module_function(:foo).should equal(:foo)
module_function(:foo, :foo).should == [:foo, :foo]
end
it "returns argument or arguments if given" do
Module.new do
def foo; end
module_function(:foo).should equal(:foo)
module_function(:foo, :foo).should == [:foo, :foo]
end
end
@ -216,19 +205,9 @@ describe "Module#module_function as a toggle (no arguments) in a Module body" do
m.respond_to?(:test2).should == true
end
ruby_version_is ""..."3.1" do
it "returns self" do
Module.new do
module_function.should equal(self)
end
end
end
ruby_version_is "3.1" do
it "returns nil" do
Module.new do
module_function.should equal(nil)
end
it "returns nil" do
Module.new do
module_function.should equal(nil)
end
end

View File

@ -30,6 +30,8 @@ describe "Module#name" do
m::N.name.should =~ /\A#<Module:0x\h+>::N\z/
ModuleSpecs::Anonymous::WasAnnon = m::N
m::N.name.should == "ModuleSpecs::Anonymous::WasAnnon"
ensure
ModuleSpecs::Anonymous.send(:remove_const, :WasAnnon)
end
it "may be the repeated in different module objects" do
@ -76,12 +78,16 @@ describe "Module#name" do
m = Module.new
ModuleSpecs::Anonymous::A = m
m.name.should == "ModuleSpecs::Anonymous::A"
ensure
ModuleSpecs::Anonymous.send(:remove_const, :A)
end
it "is set when assigning to a constant (constant path does not match outer module name)" do
m = Module.new
ModuleSpecs::Anonymous::SameChild::A = m
m.name.should == "ModuleSpecs::Anonymous::Child::A"
ensure
ModuleSpecs::Anonymous::SameChild.send(:remove_const, :A)
end
it "is not modified when assigning to a new constant after it has been accessed" do
@ -90,6 +96,9 @@ describe "Module#name" do
m.name.should == "ModuleSpecs::Anonymous::B"
ModuleSpecs::Anonymous::C = m
m.name.should == "ModuleSpecs::Anonymous::B"
ensure
ModuleSpecs::Anonymous.send(:remove_const, :B)
ModuleSpecs::Anonymous.send(:remove_const, :C)
end
it "is not modified when assigned to a different anonymous module" do
@ -125,6 +134,8 @@ describe "Module#name" do
m::N = Module.new
ModuleSpecs::Anonymous::E = m
m::N.name.should == "ModuleSpecs::Anonymous::E::N"
ensure
ModuleSpecs::Anonymous.send(:remove_const, :E)
end
# https://bugs.ruby-lang.org/issues/19681
@ -138,6 +149,8 @@ describe "Module#name" do
"ModuleSpecs::Anonymous::StoredInMultiplePlaces::O"
]
valid_names.should include(m::N.name) # You get one of the two, but you don't know which one.
ensure
ModuleSpecs::Anonymous.send(:remove_const, :StoredInMultiplePlaces)
end
ruby_version_is "3.2" do

View File

@ -261,6 +261,8 @@ describe "Module#prepend" do
B.prepend M
B.foo.should == 'm'
end
ensure
ModuleSpecs.send(:remove_const, :ConstUpdatePrepended)
end
it "updates the constant when a prepended module is updated" do
@ -281,6 +283,8 @@ describe "Module#prepend" do
M.const_set(:FOO, 'm')
B.foo.should == 'm'
end
ensure
ModuleSpecs.send(:remove_const, :ConstPrependedUpdated)
end
it "updates the constant when there is a base included constant and the prepended module overrides it" do
@ -302,6 +306,8 @@ describe "Module#prepend" do
A.prepend M
A.foo.should == 'm'
end
ensure
ModuleSpecs.send(:remove_const, :ConstIncludedPrependedOverride)
end
it "updates the constant when there is a base included constant and the prepended module is later updated" do
@ -325,6 +331,8 @@ describe "Module#prepend" do
M.const_set(:FOO, 'm')
A.foo.should == 'm'
end
ensure
ModuleSpecs.send(:remove_const, :ConstIncludedPrependedLaterUpdated)
end
it "updates the constant when a module prepended after a constant is later updated" do
@ -348,6 +356,8 @@ describe "Module#prepend" do
M.const_set(:FOO, 'm')
B.foo.should == 'm'
end
ensure
ModuleSpecs.send(:remove_const, :ConstUpdatedPrependedAfterLaterUpdated)
end
it "updates the constant when a module is prepended after another and the constant is defined later on that module" do
@ -372,6 +382,8 @@ describe "Module#prepend" do
N.const_set(:FOO, 'n')
A.foo.should == 'n'
end
ensure
ModuleSpecs.send(:remove_const, :ConstUpdatedPrependedAfterConstDefined)
end
it "updates the constant when a module is included in a prepended module and the constant is defined later" do
@ -399,6 +411,8 @@ describe "Module#prepend" do
N.const_set(:FOO, 'n')
A.foo.should == 'n'
end
ensure
ModuleSpecs.send(:remove_const, :ConstUpdatedIncludedInPrependedConstDefinedLater)
end
it "updates the constant when a new module with an included module is prepended" do
@ -425,6 +439,8 @@ describe "Module#prepend" do
B.prepend M
B.foo.should == 'n'
end
ensure
ModuleSpecs.send(:remove_const, :ConstUpdatedNewModuleIncludedPrepended)
end
it "raises a TypeError when the argument is not a Module" do
@ -432,7 +448,11 @@ describe "Module#prepend" do
end
it "does not raise a TypeError when the argument is an instance of a subclass of Module" do
-> { ModuleSpecs::SubclassSpec.prepend(ModuleSpecs::Subclass.new) }.should_not raise_error(TypeError)
class ModuleSpecs::SubclassSpec::AClass
end
-> { ModuleSpecs::SubclassSpec::AClass.prepend(ModuleSpecs::Subclass.new) }.should_not raise_error(TypeError)
ensure
ModuleSpecs::SubclassSpec.send(:remove_const, :AClass)
end
ruby_version_is ""..."3.2" do
@ -787,34 +807,17 @@ describe "Module#prepend" do
# https://bugs.ruby-lang.org/issues/17423
describe "when module already exists in ancestor chain" do
ruby_version_is ""..."3.1" do
it "does not modify the ancestor chain" do
m = Module.new do; end
a = Module.new do; end
b = Class.new do; end
it "modifies the ancestor chain" do
m = Module.new do; end
a = Module.new do; end
b = Class.new do; end
b.include(a)
a.prepend(m)
b.ancestors.take(4).should == [b, m, a, Object]
b.include(a)
a.prepend(m)
b.ancestors.take(4).should == [b, m, a, Object]
b.prepend(m)
b.ancestors.take(4).should == [b, m, a, Object]
end
end
ruby_version_is "3.1" do
it "modifies the ancestor chain" do
m = Module.new do; end
a = Module.new do; end
b = Class.new do; end
b.include(a)
a.prepend(m)
b.ancestors.take(4).should == [b, m, a, Object]
b.prepend(m)
b.ancestors.take(5).should == [m, b, m, a, Object]
end
b.prepend(m)
b.ancestors.take(5).should == [m, b, m, a, Object]
end
end

View File

@ -38,25 +38,13 @@ describe "Module#private" do
:module_specs_public_method_on_object_for_kernel_private)
end
ruby_version_is ""..."3.1" do
it "returns self" do
(class << Object.new; self; end).class_eval do
def foo; end
private(:foo).should equal(self)
private.should equal(self)
end
end
end
ruby_version_is "3.1" do
it "returns argument or arguments if given" do
(class << Object.new; self; end).class_eval do
def foo; end
private(:foo).should equal(:foo)
private([:foo, :foo]).should == [:foo, :foo]
private(:foo, :foo).should == [:foo, :foo]
private.should equal(nil)
end
it "returns argument or arguments if given" do
(class << Object.new; self; end).class_eval do
def foo; end
private(:foo).should equal(:foo)
private([:foo, :foo]).should == [:foo, :foo]
private(:foo, :foo).should == [:foo, :foo]
private.should equal(nil)
end
end

View File

@ -39,25 +39,13 @@ describe "Module#protected" do
:module_specs_public_method_on_object_for_kernel_protected)
end
ruby_version_is ""..."3.1" do
it "returns self" do
(class << Object.new; self; end).class_eval do
def foo; end
protected(:foo).should equal(self)
protected.should equal(self)
end
end
end
ruby_version_is "3.1" do
it "returns argument or arguments if given" do
(class << Object.new; self; end).class_eval do
def foo; end
protected(:foo).should equal(:foo)
protected([:foo, :foo]).should == [:foo, :foo]
protected(:foo, :foo).should == [:foo, :foo]
protected.should equal(nil)
end
it "returns argument or arguments if given" do
(class << Object.new; self; end).class_eval do
def foo; end
protected(:foo).should equal(:foo)
protected([:foo, :foo]).should == [:foo, :foo]
protected(:foo, :foo).should == [:foo, :foo]
protected.should equal(nil)
end
end

View File

@ -27,25 +27,13 @@ describe "Module#public" do
:module_specs_private_method_on_object_for_kernel_public)
end
ruby_version_is ""..."3.1" do
it "returns self" do
(class << Object.new; self; end).class_eval do
def foo; end
public(:foo).should equal(self)
public.should equal(self)
end
end
end
ruby_version_is "3.1" do
it "returns argument or arguments if given" do
(class << Object.new; self; end).class_eval do
def foo; end
public(:foo).should equal(:foo)
public([:foo, :foo]).should == [:foo, :foo]
public(:foo, :foo).should == [:foo, :foo]
public.should equal(nil)
end
it "returns argument or arguments if given" do
(class << Object.new; self; end).class_eval do
def foo; end
public(:foo).should equal(:foo)
public([:foo, :foo]).should == [:foo, :foo]
public(:foo, :foo).should == [:foo, :foo]
public.should equal(nil)
end
end

View File

@ -272,7 +272,7 @@ describe "Module#refine" do
it "looks in later included modules of the refined module first" do
a = Module.new do
def foo
"foo from A"
"foo from A"
end
end
@ -300,67 +300,6 @@ describe "Module#refine" do
result.should == "foo from IncludeMeLater"
end
ruby_version_is ""..."3.1" do
it "looks in prepended modules from the refinement first" do
refined_class = ModuleSpecs.build_refined_class
refinement = Module.new do
refine refined_class do
include ModuleSpecs::IncludedModule
prepend ModuleSpecs::PrependedModule
def foo; "foo from refinement"; end
end
end
result = nil
Module.new do
using refinement
result = refined_class.new.foo
end
result.should == "foo from prepended module"
end
it "looks in refinement then" do
refined_class = ModuleSpecs.build_refined_class
refinement = Module.new do
refine(refined_class) do
include ModuleSpecs::IncludedModule
def foo; "foo from refinement"; end
end
end
result = nil
Module.new do
using refinement
result = refined_class.new.foo
end
result.should == "foo from refinement"
end
it "looks in included modules from the refinement then" do
refined_class = ModuleSpecs.build_refined_class
refinement = Module.new do
refine refined_class do
include ModuleSpecs::IncludedModule
end
end
result = nil
Module.new do
using refinement
result = refined_class.new.foo
end
result.should == "foo from included module"
end
end
it "looks in the class then" do
refined_class = ModuleSpecs.build_refined_class
@ -606,30 +545,6 @@ describe "Module#refine" do
end
context "when super is called in a refinement" do
ruby_version_is ""..."3.1" do
it "looks in the included to refinery module" do
refined_class = ModuleSpecs.build_refined_class
refinement = Module.new do
refine refined_class do
include ModuleSpecs::IncludedModule
def foo
super
end
end
end
result = nil
Module.new do
using refinement
result = refined_class.new.foo
end
result.should == "foo from included module"
end
end
it "looks in the refined class" do
refined_class = ModuleSpecs.build_refined_class
@ -650,59 +565,6 @@ describe "Module#refine" do
result.should == "foo"
end
ruby_version_is ""..."3.1" do
it "looks in the refined class from included module" do
refined_class = ModuleSpecs.build_refined_class(for_super: true)
a = Module.new do
def foo
[:A] + super
end
end
refinement = Module.new do
refine refined_class do
include a
end
end
result = nil
Module.new do
using refinement
result = refined_class.new.foo
end
result.should == [:A, :C]
end
it "looks in the refined ancestors from included module" do
refined_class = ModuleSpecs.build_refined_class(for_super: true)
subclass = Class.new(refined_class)
a = Module.new do
def foo
[:A] + super
end
end
refinement = Module.new do
refine refined_class do
include a
end
end
result = nil
Module.new do
using refinement
result = subclass.new.foo
end
result.should == [:A, :C]
end
end
# super in a method of a refinement invokes the method in the refined
# class even if there is another refinement which has been activated
# in the same context.
@ -763,179 +625,6 @@ describe "Module#refine" do
}.should raise_error(NoMethodError)
end
end
ruby_version_is ""..."3.1" do
it "does't have access to active refinements for C from included module" do
refined_class = ModuleSpecs.build_refined_class
a = Module.new do
def foo
super + bar
end
end
refinement = Module.new do
refine refined_class do
include a
def bar
"bar is not seen from A methods"
end
end
end
Module.new do
using refinement
-> {
refined_class.new.foo
}.should raise_error(NameError) { |e| e.name.should == :bar }
end
end
it "does't have access to other active refinements from included module" do
refined_class = ModuleSpecs.build_refined_class
refinement_integer = Module.new do
refine Integer do
def bar
"bar is not seen from A methods"
end
end
end
a = Module.new do
def foo
super + 1.bar
end
end
refinement = Module.new do
refine refined_class do
include a
end
end
Module.new do
using refinement
using refinement_integer
-> {
refined_class.new.foo
}.should raise_error(NameError) { |e| e.name.should == :bar }
end
end
# https://bugs.ruby-lang.org/issues/16977
it "looks in the another active refinement if super called from included modules" do
refined_class = ModuleSpecs.build_refined_class(for_super: true)
a = Module.new do
def foo
[:A] + super
end
end
b = Module.new do
def foo
[:B] + super
end
end
refinement_a = Module.new do
refine refined_class do
include a
end
end
refinement_b = Module.new do
refine refined_class do
include b
end
end
result = nil
Module.new do
using refinement_a
using refinement_b
result = refined_class.new.foo
end
result.should == [:B, :A, :C]
end
it "looks in the current active refinement from included modules" do
refined_class = ModuleSpecs.build_refined_class(for_super: true)
a = Module.new do
def foo
[:A] + super
end
end
b = Module.new do
def foo
[:B] + super
end
end
refinement = Module.new do
refine refined_class do
def foo
[:LAST] + super
end
end
end
refinement_a_b = Module.new do
refine refined_class do
include a
include b
end
end
result = nil
Module.new do
using refinement
using refinement_a_b
result = refined_class.new.foo
end
result.should == [:B, :A, :LAST, :C]
end
it "looks in the lexical scope refinements before other active refinements" do
refined_class = ModuleSpecs.build_refined_class(for_super: true)
refinement_local = Module.new do
refine refined_class do
def foo
[:LOCAL] + super
end
end
end
a = Module.new do
using refinement_local
def foo
[:A] + super
end
end
refinement = Module.new do
refine refined_class do
include a
end
end
result = nil
Module.new do
using refinement
result = refined_class.new.foo
end
result.should == [:A, :LOCAL, :C]
end
end
end
it 'and alias aliases a method within a refinement module, but not outside it' do

View File

@ -101,5 +101,7 @@ describe "Module#remove_const" do
A.send(:remove_const,:FOO)
A.foo.should == 'm'
end
ensure
ConstantSpecs.send(:remove_const, :RemovedConstantUpdate)
end
end

View File

@ -51,6 +51,8 @@ describe "Module#to_s" do
ModuleSpecs::RefinementInspect::R.name.should == 'ModuleSpecs::RefinementInspect::R'
ModuleSpecs::RefinementInspect::R.to_s.should == '#<refinement:String@ModuleSpecs::RefinementInspect>'
ensure
ModuleSpecs.send(:remove_const, :RefinementInspect)
end
it 'does not call #inspect or #to_s for singleton classes' do

View File

@ -19,8 +19,8 @@ describe :numeric_imag, shared: true do
end
it "raises an ArgumentError if given any arguments" do
@numbers.each do |number|
-> { number.send(@method, number) }.should raise_error(ArgumentError)
end
@numbers.each do |number|
-> { number.send(@method, number) }.should raise_error(ArgumentError)
end
end
end

View File

@ -25,24 +25,24 @@ describe :numeric_rect, shared: true do
end
it "returns self as the first element" do
@numbers.each do |number|
if Float === number and number.nan?
number.send(@method).first.nan?.should be_true
else
number.send(@method).first.should == number
end
end
@numbers.each do |number|
if Float === number and number.nan?
number.send(@method).first.nan?.should be_true
else
number.send(@method).first.should == number
end
end
end
it "returns 0 as the last element" do
@numbers.each do |number|
number.send(@method).last.should == 0
end
@numbers.each do |number|
number.send(@method).last.should == 0
end
end
it "raises an ArgumentError if given any arguments" do
@numbers.each do |number|
-> { number.send(@method, number) }.should raise_error(ArgumentError)
end
@numbers.each do |number|
-> { number.send(@method, number) }.should raise_error(ArgumentError)
end
end
end

View File

@ -193,25 +193,23 @@ describe "ObjectSpace.define_finalizer" do
ret[1].should.equal?(p)
end
ruby_version_is "3.1" do
describe "when $VERBOSE is not nil" do
it "warns if an exception is raised in finalizer" do
code = <<-RUBY
ObjectSpace.define_finalizer(Object.new) { raise "finalizing" }
RUBY
describe "when $VERBOSE is not nil" do
it "warns if an exception is raised in finalizer" do
code = <<-RUBY
ObjectSpace.define_finalizer(Object.new) { raise "finalizing" }
RUBY
ruby_exe(code, args: "2>&1").should include("warning: Exception in finalizer", "finalizing")
end
ruby_exe(code, args: "2>&1").should include("warning: Exception in finalizer", "finalizing")
end
end
describe "when $VERBOSE is nil" do
it "does not warn even if an exception is raised in finalizer" do
code = <<-RUBY
ObjectSpace.define_finalizer(Object.new) { raise "finalizing" }
RUBY
describe "when $VERBOSE is nil" do
it "does not warn even if an exception is raised in finalizer" do
code = <<-RUBY
ObjectSpace.define_finalizer(Object.new) { raise "finalizing" }
RUBY
ruby_exe(code, args: "2>&1", options: "-W0").should == ""
end
ruby_exe(code, args: "2>&1", options: "-W0").should == ""
end
end
end

View File

@ -0,0 +1,27 @@
require_relative '../../../spec_helper'
ruby_version_is '3.3' do
describe "ObjectSpace::WeakKeyMap#clear" do
it "removes all the entries" do
m = ObjectSpace::WeakKeyMap.new
key = Object.new
value = Object.new
m[key] = value
key2 = Object.new
value2 = Object.new
m[key2] = value2
m.clear
m.key?(key).should == false
m.key?(key2).should == false
end
it "returns self" do
m = ObjectSpace::WeakKeyMap.new
m.clear.should.equal?(m)
end
end
end

View File

@ -33,8 +33,19 @@ ruby_version_is '3.3' do
end
it "returns nil if the key is not found when no block is given" do
m = ObjectSpace::WeakMap.new
m = ObjectSpace::WeakKeyMap.new
m.delete(Object.new).should == nil
end
it "returns nil when a key cannot be garbage collected" do
map = ObjectSpace::WeakKeyMap.new
map.delete(1).should == nil
map.delete(1.0).should == nil
map.delete(:a).should == nil
map.delete(true).should == nil
map.delete(false).should == nil
map.delete(nil).should == nil
end
end
end

View File

@ -1,4 +1,5 @@
require_relative '../../../spec_helper'
require_relative 'fixtures/classes'
ruby_version_is "3.3" do
describe "ObjectSpace::WeakKeyMap#[]" do
@ -15,12 +16,92 @@ ruby_version_is "3.3" do
map[key2].should == ref2
end
it "matches using equality semantics" do
it "compares keys with #eql? semantics" do
map = ObjectSpace::WeakKeyMap.new
key = [1.0]
map[key] = "x"
map[[1]].should == nil
map[[1.0]].should == "x"
key.should == [1.0] # keep the key alive until here to keep the map entry
map = ObjectSpace::WeakKeyMap.new
key = [1]
map[key] = "x"
map[[1.0]].should == nil
map[[1]].should == "x"
key.should == [1] # keep the key alive until here to keep the map entry
map = ObjectSpace::WeakKeyMap.new
key1, key2 = %w[a a].map(&:upcase)
ref = "x"
map[key1] = ref
map[key2].should == ref
end
it "compares key via #hash first" do
x = mock('0')
x.should_receive(:hash).and_return(0)
map = ObjectSpace::WeakKeyMap.new
key = 'foo'
map[key] = :bar
map[x].should == nil
end
it "does not compare keys with different #hash values via #eql?" do
x = mock('x')
x.should_not_receive(:eql?)
x.stub!(:hash).and_return(0)
y = mock('y')
y.should_not_receive(:eql?)
y.stub!(:hash).and_return(1)
map = ObjectSpace::WeakKeyMap.new
map[y] = 1
map[x].should == nil
end
it "compares keys with the same #hash value via #eql?" do
x = mock('x')
x.should_receive(:eql?).and_return(true)
x.stub!(:hash).and_return(42)
y = mock('y')
y.should_not_receive(:eql?)
y.stub!(:hash).and_return(42)
map = ObjectSpace::WeakKeyMap.new
map[y] = 1
map[x].should == 1
end
it "finds a value via an identical key even when its #eql? isn't reflexive" do
x = mock('x')
x.should_receive(:hash).at_least(1).and_return(42)
x.stub!(:eql?).and_return(false) # Stubbed for clarity and latitude in implementation; not actually sent by MRI.
map = ObjectSpace::WeakKeyMap.new
map[x] = :x
map[x].should == :x
end
it "supports keys with private #hash method" do
key = WeakKeyMapSpecs::KeyWithPrivateHash.new
map = ObjectSpace::WeakKeyMap.new
map[key] = 42
map[key].should == 42
end
it "returns nil and does not raise error when a key cannot be garbage collected" do
map = ObjectSpace::WeakKeyMap.new
map[1].should == nil
map[1.0].should == nil
map[:a].should == nil
map[true].should == nil
map[false].should == nil
map[nil].should == nil
end
end
end

View File

@ -8,10 +8,6 @@ ruby_version_is "3.3" do
map[key].should == value
end
def should_not_accept(map, key, value)
-> { map[key] = value }.should raise_error(ArgumentError)
end
it "is correct" do
map = ObjectSpace::WeakKeyMap.new
key1, key2 = %w[a b].map(&:upcase)
@ -40,32 +36,47 @@ ruby_version_is "3.3" do
should_accept(map, y, x)
end
it "rejects symbols as keys" do
it "does not duplicate and freeze String keys (like Hash#[]= does)" do
map = ObjectSpace::WeakKeyMap.new
should_not_accept(map, :foo, true)
should_not_accept(map, rand.to_s.to_sym, true)
key = +"a"
map[key] = 1
map.getkey("a").should.equal? key
map.getkey("a").should_not.frozen?
key.should == "a" # keep the key alive until here to keep the map entry
end
it "rejects integers as keys" do
map = ObjectSpace::WeakKeyMap.new
should_not_accept(map, 42, true)
should_not_accept(map, 2 ** 68, true)
end
context "a key cannot be garbage collected" do
it "raises ArgumentError when Integer is used as a key" do
map = ObjectSpace::WeakKeyMap.new
-> { map[1] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
end
it "rejects floats as keys" do
map = ObjectSpace::WeakKeyMap.new
should_not_accept(map, 4.2, true)
end
it "raises ArgumentError when Float is used as a key" do
map = ObjectSpace::WeakKeyMap.new
-> { map[1.0] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
end
it "rejects booleans as keys" do
map = ObjectSpace::WeakKeyMap.new
should_not_accept(map, true, true)
should_not_accept(map, false, true)
end
it "raises ArgumentError when Symbol is used as a key" do
map = ObjectSpace::WeakKeyMap.new
-> { map[:a] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
end
it "rejects nil as keys" do
map = ObjectSpace::WeakKeyMap.new
should_not_accept(map, nil, true)
it "raises ArgumentError when true is used as a key" do
map = ObjectSpace::WeakKeyMap.new
-> { map[true] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
end
it "raises ArgumentError when false is used as a key" do
map = ObjectSpace::WeakKeyMap.new
-> { map[false] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
end
it "raises ArgumentError when nil is used as a key" do
map = ObjectSpace::WeakKeyMap.new
-> { map[nil] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
end
end
end
end

View File

@ -0,0 +1,5 @@
module WeakKeyMapSpecs
class KeyWithPrivateHash
private :hash
end
end

View File

@ -9,6 +9,20 @@ ruby_version_is "3.3" do
map[key1] = true
map.getkey(key2).should equal(key1)
map.getkey("X").should == nil
key1.should == "A" # keep the key alive until here to keep the map entry
key2.should == "A" # keep the key alive until here to keep the map entry
end
it "returns nil when a key cannot be garbage collected" do
map = ObjectSpace::WeakKeyMap.new
map.getkey(1).should == nil
map.getkey(1.0).should == nil
map.getkey(:a).should == nil
map.getkey(true).should == nil
map.getkey(false).should == nil
map.getkey(nil).should == nil
end
end
end

View File

@ -12,6 +12,10 @@ ruby_version_is "3.3" do
map.inspect.should =~ /\A\#<ObjectSpace::WeakKeyMap:0x\h+ size=2>\z/
map[key3] = 3
map.inspect.should =~ /\A\#<ObjectSpace::WeakKeyMap:0x\h+ size=2>\z/
key1.should == "foo" # keep the key alive until here to keep the map entry
key2.should == "bar" # keep the key alive until here to keep the map entry
key3.should == "bar" # keep the key alive until here to keep the map entry
end
end
end

Some files were not shown because too many files have changed in this diff Show More