diff options
Diffstat (limited to 'spec/ruby/core')
151 files changed, 2825 insertions, 2263 deletions
diff --git a/spec/ruby/core/array/drop_spec.rb b/spec/ruby/core/array/drop_spec.rb index 0ea748e47d..5926c291b8 100644 --- a/spec/ruby/core/array/drop_spec.rb +++ b/spec/ruby/core/array/drop_spec.rb @@ -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 diff --git a/spec/ruby/core/array/intersect_spec.rb b/spec/ruby/core/array/intersect_spec.rb index 62ac157278..456aa26c6e 100644 --- a/spec/ruby/core/array/intersect_spec.rb +++ b/spec/ruby/core/array/intersect_spec.rb @@ -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 + describe 'when at least one element in two Arrays is the same' do + it 'returns true' do + [1, 2].intersect?([2, 3, 4]).should == true + [2, 3, 4].intersect?([1, 2]).should == true end + end - describe 'when there are no elements in common between two Arrays' do - it 'returns false' do - [0, 1, 2].intersect?([3, 4]).should == false - [3, 4].intersect?([0, 1, 2]).should == false - [3, 4].intersect?([]).should == false - [].intersect?([0, 1, 2]).should == false - end + describe 'when there are no elements in common between two Arrays' do + it 'returns false' do + [0, 1, 2].intersect?([3, 4]).should == false + [3, 4].intersect?([0, 1, 2]).should == false + [3, 4].intersect?([]).should == false + [].intersect?([0, 1, 2]).should == false end + end - it "tries to convert the passed argument to an Array using #to_ary" do - obj = mock('[1,2,3]') - obj.should_receive(:to_ary).and_return([1, 2, 3]) + it "tries to convert the passed argument to an Array using #to_ary" do + obj = mock('[1,2,3]') + obj.should_receive(:to_ary).and_return([1, 2, 3]) - [1, 2].intersect?(obj).should == true - end + [1, 2].intersect?(obj).should == true + end - it "determines equivalence between elements in the sense of eql?" do - obj1 = mock('1') - obj2 = mock('2') - obj1.stub!(:hash).and_return(0) - obj2.stub!(:hash).and_return(0) - obj1.stub!(:eql?).and_return(true) - obj2.stub!(:eql?).and_return(true) + it "determines equivalence between elements in the sense of eql?" do + obj1 = mock('1') + obj2 = mock('2') + obj1.stub!(:hash).and_return(0) + obj2.stub!(:hash).and_return(0) + obj1.stub!(:eql?).and_return(true) + obj2.stub!(:eql?).and_return(true) - [obj1].intersect?([obj2]).should == true + [obj1].intersect?([obj2]).should == true - obj1 = mock('3') - obj2 = mock('4') - obj1.stub!(:hash).and_return(0) - obj2.stub!(:hash).and_return(0) - obj1.stub!(:eql?).and_return(false) - obj2.stub!(:eql?).and_return(false) + obj1 = mock('3') + obj2 = mock('4') + obj1.stub!(:hash).and_return(0) + obj2.stub!(:hash).and_return(0) + obj1.stub!(:eql?).and_return(false) + obj2.stub!(:eql?).and_return(false) - [obj1].intersect?([obj2]).should == false - end + [obj1].intersect?([obj2]).should == false + end - it "does not call to_ary on array subclasses" do - [5, 6].intersect?(ArraySpecs::ToAryArray[1, 2, 5, 6]).should == true - end + it "does not call to_ary on array subclasses" do + [5, 6].intersect?(ArraySpecs::ToAryArray[1, 2, 5, 6]).should == true + end - it "properly handles an identical item even when its #eql? isn't reflexive" do - x = mock('x') - x.stub!(:hash).and_return(42) - x.stub!(:eql?).and_return(false) # Stubbed for clarity and latitude in implementation; not actually sent by MRI. + it "properly handles an identical item even when its #eql? isn't reflexive" do + x = mock('x') + x.stub!(:hash).and_return(42) + x.stub!(:eql?).and_return(false) # Stubbed for clarity and latitude in implementation; not actually sent by MRI. - [x].intersect?([x]).should == true - end + [x].intersect?([x]).should == true + end - it "has semantic of !(a & b).empty?" do - [].intersect?([]).should == false - [nil].intersect?([nil]).should == true - end + it "has semantic of !(a & b).empty?" do + [].intersect?([]).should == false + [nil].intersect?([nil]).should == true end end diff --git a/spec/ruby/core/basicobject/instance_eval_spec.rb b/spec/ruby/core/basicobject/instance_eval_spec.rb index 1f3a43f341..633b5c2cb1 100644 --- a/spec/ruby/core/basicobject/instance_eval_spec.rb +++ b/spec/ruby/core/basicobject/instance_eval_spec.rb @@ -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 diff --git a/spec/ruby/core/basicobject/singleton_method_added_spec.rb b/spec/ruby/core/basicobject/singleton_method_added_spec.rb index fc65a091aa..bd21458ea7 100644 --- a/spec/ruby/core/basicobject/singleton_method_added_spec.rb +++ b/spec/ruby/core/basicobject/singleton_method_added_spec.rb @@ -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 diff --git a/spec/ruby/core/class/dup_spec.rb b/spec/ruby/core/class/dup_spec.rb index c09ed71b31..1ff9abf7b4 100644 --- a/spec/ruby/core/class/dup_spec.rb +++ b/spec/ruby/core/class/dup_spec.rb @@ -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 diff --git a/spec/ruby/core/class/new_spec.rb b/spec/ruby/core/class/new_spec.rb index 93152a83ee..6fe54c3209 100644 --- a/spec/ruby/core/class/new_spec.rb +++ b/spec/ruby/core/class/new_spec.rb @@ -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 diff --git a/spec/ruby/core/class/subclasses_spec.rb b/spec/ruby/core/class/subclasses_spec.rb index 50eb5358d9..f692152787 100644 --- a/spec/ruby/core/class/subclasses_spec.rb +++ b/spec/ruby/core/class/subclasses_spec.rb @@ -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]) - end +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) + 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 - 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) - 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 - 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) - 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 - 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) - it "does not return singleton classes" do - a = Class.new + assert_subclasses(parent, [child]) + end - a_obj = a.new - def a_obj.force_singleton_class - 42 - end + it "does not return singleton classes" do + a = Class.new - a.subclasses.should_not include(a_obj.singleton_class) + a_obj = a.new + def a_obj.force_singleton_class + 42 end - it "has 1 entry per module or class" do - ModuleSpecs::Parent.subclasses.should == ModuleSpecs::Parent.subclasses.uniq - 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 + 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 end + end - go = true - classes = threads.map(&:value) + go = true + classes = threads.map(&:value) - superclass.subclasses.size.should == t * n - superclass.subclasses.each { |c| c.should be_kind_of(Class) } - end + 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 + def assert_subclasses(mod,subclasses) + mod.subclasses.sort_by(&:inspect).should == subclasses.sort_by(&:inspect) end end diff --git a/spec/ruby/core/complex/shared/rect.rb b/spec/ruby/core/complex/shared/rect.rb index 9f5de1ffeb..4ac294e771 100644 --- a/spec/ruby/core/complex/shared/rect.rb +++ b/spec/ruby/core/complex/shared/rect.rb @@ -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 diff --git a/spec/ruby/core/data/deconstruct_keys_spec.rb b/spec/ruby/core/data/deconstruct_keys_spec.rb new file mode 100644 index 0000000000..07af87771d --- /dev/null +++ b/spec/ruby/core/data/deconstruct_keys_spec.rb @@ -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 diff --git a/spec/ruby/core/data/deconstruct_spec.rb b/spec/ruby/core/data/deconstruct_spec.rb new file mode 100644 index 0000000000..f0995e8fed --- /dev/null +++ b/spec/ruby/core/data/deconstruct_spec.rb @@ -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 diff --git a/spec/ruby/core/data/eql_spec.rb b/spec/ruby/core/data/eql_spec.rb new file mode 100644 index 0000000000..906e46316c --- /dev/null +++ b/spec/ruby/core/data/eql_spec.rb @@ -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 diff --git a/spec/ruby/core/data/equal_value_spec.rb b/spec/ruby/core/data/equal_value_spec.rb new file mode 100644 index 0000000000..f90a7d7a62 --- /dev/null +++ b/spec/ruby/core/data/equal_value_spec.rb @@ -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 diff --git a/spec/ruby/core/data/fixtures/classes.rb b/spec/ruby/core/data/fixtures/classes.rb index 46a6b48bb2..f0a526517d 100644 --- a/spec/ruby/core/data/fixtures/classes.rb +++ b/spec/ruby/core/data/fixtures/classes.rb @@ -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 diff --git a/spec/ruby/core/data/hash_spec.rb b/spec/ruby/core/data/hash_spec.rb new file mode 100644 index 0000000000..324a2abca4 --- /dev/null +++ b/spec/ruby/core/data/hash_spec.rb @@ -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 diff --git a/spec/ruby/core/data/inspect_spec.rb b/spec/ruby/core/data/inspect_spec.rb new file mode 100644 index 0000000000..3d337fac68 --- /dev/null +++ b/spec/ruby/core/data/inspect_spec.rb @@ -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 diff --git a/spec/ruby/core/data/members_spec.rb b/spec/ruby/core/data/members_spec.rb new file mode 100644 index 0000000000..1776b0b9c1 --- /dev/null +++ b/spec/ruby/core/data/members_spec.rb @@ -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 diff --git a/spec/ruby/core/data/shared/inspect.rb b/spec/ruby/core/data/shared/inspect.rb new file mode 100644 index 0000000000..7f54a46de3 --- /dev/null +++ b/spec/ruby/core/data/shared/inspect.rb @@ -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 diff --git a/spec/ruby/core/data/to_s_spec.rb b/spec/ruby/core/data/to_s_spec.rb new file mode 100644 index 0000000000..0b9099f035 --- /dev/null +++ b/spec/ruby/core/data/to_s_spec.rb @@ -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 diff --git a/spec/ruby/core/dir/chdir_spec.rb b/spec/ruby/core/dir/chdir_spec.rb index 015386a902..1da9307599 100644 --- a/spec/ruby/core/dir/chdir_spec.rb +++ b/spec/ruby/core/dir/chdir_spec.rb @@ -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') diff --git a/spec/ruby/core/dir/glob_spec.rb b/spec/ruby/core/dir/glob_spec.rb index 32f515c81d..a60b233bc0 100644 --- a/spec/ruby/core/dir/glob_spec.rb +++ b/spec/ruby/core/dir/glob_spec.rb @@ -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 - ] - - 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 - ] + 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 - - 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 + + Dir.glob('**/**', File::FNM_DOTMATCH, base: "deeply/nested").sort.should == expected end it "handles **/*pattern* with base keyword argument and FNM_DOTMATCH" do diff --git a/spec/ruby/core/dir/shared/glob.rb b/spec/ruby/core/dir/shared/glob.rb index 8db74881ba..b1fc924f08 100644 --- a/spec/ruby/core/dir/shared/glob.rb +++ b/spec/ruby/core/dir/shared/glob.rb @@ -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 diff --git a/spec/ruby/core/encoding/converter/finish_spec.rb b/spec/ruby/core/encoding/converter/finish_spec.rb index 239243430b..22e66df38c 100644 --- a/spec/ruby/core/encoding/converter/finish_spec.rb +++ b/spec/ruby/core/encoding/converter/finish_spec.rb @@ -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 diff --git a/spec/ruby/core/encoding/converter/search_convpath_spec.rb b/spec/ruby/core/encoding/converter/search_convpath_spec.rb index 0882af5539..59fe4520c0 100644 --- a/spec/ruby/core/encoding/converter/search_convpath_spec.rb +++ b/spec/ruby/core/encoding/converter/search_convpath_spec.rb @@ -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 diff --git a/spec/ruby/core/enumerable/compact_spec.rb b/spec/ruby/core/enumerable/compact_spec.rb index 86e95dce08..1895430c4e 100644 --- a/spec/ruby/core/enumerable/compact_spec.rb +++ b/spec/ruby/core/enumerable/compact_spec.rb @@ -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 diff --git a/spec/ruby/core/enumerable/each_cons_spec.rb b/spec/ruby/core/enumerable/each_cons_spec.rb index 8fb31fb925..ed77741862 100644 --- a/spec/ruby/core/enumerable/each_cons_spec.rb +++ b/spec/ruby/core/enumerable/each_cons_spec.rb @@ -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 diff --git a/spec/ruby/core/enumerable/each_slice_spec.rb b/spec/ruby/core/enumerable/each_slice_spec.rb index a57a1dba81..47b8c9ba33 100644 --- a/spec/ruby/core/enumerable/each_slice_spec.rb +++ b/spec/ruby/core/enumerable/each_slice_spec.rb @@ -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 diff --git a/spec/ruby/core/enumerable/tally_spec.rb b/spec/ruby/core/enumerable/tally_spec.rb index e0edc8dc75..95c64c1294 100644 --- a/spec/ruby/core/enumerable/tally_spec.rb +++ b/spec/ruby/core/enumerable/tally_spec.rb @@ -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 - - 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 "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 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 "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 "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 +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 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 "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 "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 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 end diff --git a/spec/ruby/core/enumerator/lazy/compact_spec.rb b/spec/ruby/core/enumerator/lazy/compact_spec.rb index e678bc71eb..65c544f062 100644 --- a/spec/ruby/core/enumerator/lazy/compact_spec.rb +++ b/spec/ruby/core/enumerator/lazy/compact_spec.rb @@ -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 diff --git a/spec/ruby/core/enumerator/lazy/lazy_spec.rb b/spec/ruby/core/enumerator/lazy/lazy_spec.rb index 0fb104e25a..b43864b673 100644 --- a/spec/ruby/core/enumerator/lazy/lazy_spec.rb +++ b/spec/ruby/core/enumerator/lazy/lazy_spec.rb @@ -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 diff --git a/spec/ruby/core/env/dup_spec.rb b/spec/ruby/core/env/dup_spec.rb index 46d125aca8..ac66b455cd 100644 --- a/spec/ruby/core/env/dup_spec.rb +++ b/spec/ruby/core/env/dup_spec.rb @@ -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 diff --git a/spec/ruby/core/env/fetch_spec.rb b/spec/ruby/core/env/fetch_spec.rb index b2e7a88cab..2c5d7cc3a0 100644 --- a/spec/ruby/core/env/fetch_spec.rb +++ b/spec/ruby/core/env/fetch_spec.rb @@ -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 diff --git a/spec/ruby/core/env/length_spec.rb b/spec/ruby/core/env/length_spec.rb index 536af9edf5..c6f9062892 100644 --- a/spec/ruby/core/env/length_spec.rb +++ b/spec/ruby/core/env/length_spec.rb @@ -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 diff --git a/spec/ruby/core/env/size_spec.rb b/spec/ruby/core/env/size_spec.rb index f050e9e5a9..7c8072481e 100644 --- a/spec/ruby/core/env/size_spec.rb +++ b/spec/ruby/core/env/size_spec.rb @@ -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 diff --git a/spec/ruby/core/exception/errno_spec.rb b/spec/ruby/core/exception/errno_spec.rb index a063e522ea..1ab4277700 100644 --- a/spec/ruby/core/exception/errno_spec.rb +++ b/spec/ruby/core/exception/errno_spec.rb @@ -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 diff --git a/spec/ruby/core/exception/system_call_error_spec.rb b/spec/ruby/core/exception/system_call_error_spec.rb index 07f807c0ca..4fe51901c8 100644 --- a/spec/ruby/core/exception/system_call_error_spec.rb +++ b/spec/ruby/core/exception/system_call_error_spec.rb @@ -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 diff --git a/spec/ruby/core/fiber/alive_spec.rb b/spec/ruby/core/fiber/alive_spec.rb new file mode 100644 index 0000000000..a1df582435 --- /dev/null +++ b/spec/ruby/core/fiber/alive_spec.rb @@ -0,0 +1,44 @@ +require_relative '../../spec_helper' + +describe "Fiber#alive?" do + it "returns true for a Fiber that hasn't had #resume called" do + fiber = Fiber.new { true } + fiber.alive?.should be_true + end + + # FIXME: Better description? + it "returns true for a Fiber that's yielded to the caller" do + fiber = Fiber.new { Fiber.yield } + fiber.resume + fiber.alive?.should be_true + end + + it "returns true when called from its Fiber" do + fiber = Fiber.new { fiber.alive?.should be_true } + fiber.resume + end + + it "doesn't invoke the block associated with the Fiber" do + offthehook = mock('do not call') + offthehook.should_not_receive(:ring) + fiber = Fiber.new { offthehook.ring } + fiber.alive? + end + + it "returns false for a Fiber that's dead" do + fiber = Fiber.new { true } + fiber.resume + -> { fiber.resume }.should raise_error(FiberError) + fiber.alive?.should be_false + end + + it "always returns false for a dead Fiber" do + fiber = Fiber.new { true } + fiber.resume + -> { fiber.resume }.should raise_error(FiberError) + fiber.alive?.should be_false + -> { fiber.resume }.should raise_error(FiberError) + fiber.alive?.should be_false + fiber.alive?.should be_false + end +end diff --git a/spec/ruby/core/fiber/blocking_spec.rb b/spec/ruby/core/fiber/blocking_spec.rb index ebefa116af..ed3c057516 100644 --- a/spec/ruby/core/fiber/blocking_spec.rb +++ b/spec/ruby/core/fiber/blocking_spec.rb @@ -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? } diff --git a/spec/ruby/core/fiber/current_spec.rb b/spec/ruby/core/fiber/current_spec.rb new file mode 100644 index 0000000000..b93df77a89 --- /dev/null +++ b/spec/ruby/core/fiber/current_spec.rb @@ -0,0 +1,50 @@ +require_relative '../../spec_helper' + +describe "Fiber.current" do + it "returns the root Fiber when called outside of a Fiber" do + root = Fiber.current + root.should be_an_instance_of(Fiber) + # We can always transfer to the root Fiber; it will never die + 5.times do + root.transfer.should be_nil + root.alive?.should be_true + end + end + + it "returns the current Fiber when called from a Fiber" do + fiber = Fiber.new do + this = Fiber.current + this.should be_an_instance_of(Fiber) + this.should == fiber + this.alive?.should be_true + end + fiber.resume + end + + it "returns the current Fiber when called from a Fiber that transferred to another" do + states = [] + fiber = Fiber.new do + states << :fiber + this = Fiber.current + this.should be_an_instance_of(Fiber) + this.should == fiber + this.alive?.should be_true + end + + fiber2 = Fiber.new do + states << :fiber2 + fiber.transfer + flunk + end + + fiber3 = Fiber.new do + states << :fiber3 + fiber2.transfer + states << :fiber3_terminated + end + + fiber3.resume + + states.should == [:fiber3, :fiber2, :fiber, :fiber3_terminated] + end +end diff --git a/spec/ruby/core/fiber/inspect_spec.rb b/spec/ruby/core/fiber/inspect_spec.rb index f20a153fc2..fcfef20716 100644 --- a/spec/ruby/core/fiber/inspect_spec.rb +++ b/spec/ruby/core/fiber/inspect_spec.rb @@ -1,5 +1,4 @@ require_relative '../../spec_helper' -require 'fiber' describe "Fiber#inspect" do describe "status" do diff --git a/spec/ruby/core/fiber/raise_spec.rb b/spec/ruby/core/fiber/raise_spec.rb index 2f2baa4a12..124f56fe7d 100644 --- a/spec/ruby/core/fiber/raise_spec.rb +++ b/spec/ruby/core/fiber/raise_spec.rb @@ -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 diff --git a/spec/ruby/core/fiber/resume_spec.rb b/spec/ruby/core/fiber/resume_spec.rb index ab9a6799ab..4b20f4b4bf 100644 --- a/spec/ruby/core/fiber/resume_spec.rb +++ b/spec/ruby/core/fiber/resume_spec.rb @@ -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 diff --git a/spec/ruby/core/fiber/shared/resume.rb b/spec/ruby/core/fiber/shared/resume.rb new file mode 100644 index 0000000000..5ee27d1d24 --- /dev/null +++ b/spec/ruby/core/fiber/shared/resume.rb @@ -0,0 +1,58 @@ +describe :fiber_resume, shared: true do + it "can be invoked from the root Fiber" do + fiber = Fiber.new { :fiber } + fiber.send(@method).should == :fiber + end + + it "raises a FiberError if invoked from a different Thread" do + fiber = Fiber.new { 42 } + Thread.new do + -> { + fiber.send(@method) + }.should raise_error(FiberError) + end.join + + # Check the Fiber can still be used + fiber.send(@method).should == 42 + end + + it "passes control to the beginning of the block on first invocation" do + invoked = false + fiber = Fiber.new { invoked = true } + fiber.send(@method) + invoked.should be_true + end + + it "returns the last value encountered on first invocation" do + fiber = Fiber.new { 1+1; true } + fiber.send(@method).should be_true + end + + it "runs until the end of the block" do + obj = mock('obj') + obj.should_receive(:do).once + fiber = Fiber.new { 1 + 2; a = "glark"; obj.do } + fiber.send(@method) + end + + it "accepts any number of arguments" do + fiber = Fiber.new { |a| } + -> { fiber.send(@method, *(1..10).to_a) }.should_not raise_error + end + + it "raises a FiberError if the Fiber is dead" do + fiber = Fiber.new { true } + fiber.send(@method) + -> { fiber.send(@method) }.should raise_error(FiberError) + end + + it "raises a LocalJumpError if the block includes a return statement" do + fiber = Fiber.new { return; } + -> { fiber.send(@method) }.should raise_error(LocalJumpError) + end + + it "raises a LocalJumpError if the block includes a break statement" do + fiber = Fiber.new { break; } + -> { fiber.send(@method) }.should raise_error(LocalJumpError) + end +end diff --git a/spec/ruby/core/fiber/transfer_spec.rb b/spec/ruby/core/fiber/transfer_spec.rb new file mode 100644 index 0000000000..238721475d --- /dev/null +++ b/spec/ruby/core/fiber/transfer_spec.rb @@ -0,0 +1,84 @@ +require_relative '../../spec_helper' +require_relative 'shared/resume' + +describe "Fiber#transfer" do + it_behaves_like :fiber_resume, :transfer +end + +describe "Fiber#transfer" do + it "transfers control from one Fiber to another when called from a Fiber" do + fiber1 = Fiber.new { :fiber1 } + fiber2 = Fiber.new { fiber1.transfer; :fiber2 } + fiber2.resume.should == :fiber2 + end + + it "returns to the root Fiber when finished" do + f1 = Fiber.new { :fiber_1 } + f2 = Fiber.new { f1.transfer; :fiber_2 } + + f2.transfer.should == :fiber_1 + f2.transfer.should == :fiber_2 + end + + it "can be invoked from the same Fiber it transfers control to" do + states = [] + fiber = Fiber.new { states << :start; fiber.transfer; states << :end } + fiber.transfer + states.should == [:start, :end] + + states = [] + fiber = Fiber.new { states << :start; fiber.transfer; states << :end } + fiber.resume + states.should == [:start, :end] + end + + it "can not transfer control to a Fiber that has suspended by Fiber.yield" do + states = [] + fiber1 = Fiber.new { states << :fiber1 } + fiber2 = Fiber.new { states << :fiber2_start; Fiber.yield fiber1.transfer; states << :fiber2_end} + fiber2.resume.should == [:fiber2_start, :fiber1] + -> { fiber2.transfer }.should raise_error(FiberError) + end + + it "raises a FiberError when transferring to a Fiber which resumes itself" do + fiber = Fiber.new { fiber.resume } + -> { fiber.transfer }.should raise_error(FiberError) + end + + it "works if Fibers in different Threads each transfer to a Fiber in the same Thread" do + # This catches a bug where Fibers are running on a thread-pool + # and Fibers from a different Ruby Thread reuse the same native thread. + # Caching the Ruby Thread based on the native thread is not correct in that case, + # and the check for "fiber called across threads" in Fiber#transfer + # might be incorrect based on that. + 2.times do + Thread.new do + io_fiber = Fiber.new do |calling_fiber| + calling_fiber.transfer + end + io_fiber.transfer(Fiber.current) + value = Object.new + io_fiber.transfer(value).should equal value + end.join + end + end + + it "transfers control between a non-main thread's root fiber to a child fiber and back again" do + states = [] + thread = Thread.new do + f1 = Fiber.new do |f0| + states << 0 + value2 = f0.transfer(1) + states << value2 + 3 + end + + value1 = f1.transfer(Fiber.current) + states << value1 + value3 = f1.transfer(2) + states << value3 + end + thread.join + states.should == [0, 1, 2, 3] + end +end diff --git a/spec/ruby/core/file/dirname_spec.rb b/spec/ruby/core/file/dirname_spec.rb index 8dd6c4ca88..8e6016ce6f 100644 --- a/spec/ruby/core/file/dirname_spec.rb +++ b/spec/ruby/core/file/dirname_spec.rb @@ -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 - - 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 "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 - - File.dirname("/a/b/c/d", object).should == '/a/b' - 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 "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 "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 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 diff --git a/spec/ruby/core/file/shared/path.rb b/spec/ruby/core/file/shared/path.rb index aa2a64cf25..5a9fe1b0c5 100644 --- a/spec/ruby/core/file/shared/path.rb +++ b/spec/ruby/core/file/shared/path.rb @@ -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 diff --git a/spec/ruby/core/float/comparison_spec.rb b/spec/ruby/core/float/comparison_spec.rb index d2e47937ff..0cd290f4ad 100644 --- a/spec/ruby/core/float/comparison_spec.rb +++ b/spec/ruby/core/float/comparison_spec.rb @@ -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 diff --git a/spec/ruby/core/float/round_spec.rb b/spec/ruby/core/float/round_spec.rb index 9b4c307f9d..7e8c792051 100644 --- a/spec/ruby/core/float/round_spec.rb +++ b/spec/ruby/core/float/round_spec.rb @@ -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 ) diff --git a/spec/ruby/core/gc/measure_total_time_spec.rb b/spec/ruby/core/gc/measure_total_time_spec.rb index 05d4598ebc..f5377c18fd 100644 --- a/spec/ruby/core/gc/measure_total_time_spec.rb +++ b/spec/ruby/core/gc/measure_total_time_spec.rb @@ -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 diff --git a/spec/ruby/core/gc/total_time_spec.rb b/spec/ruby/core/gc/total_time_spec.rb index fcc8f45a83..a8430fbe9a 100644 --- a/spec/ruby/core/gc/total_time_spec.rb +++ b/spec/ruby/core/gc/total_time_spec.rb @@ -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 diff --git a/spec/ruby/core/hash/hash_spec.rb b/spec/ruby/core/hash/hash_spec.rb index 9b47d4b2bf..cd67f7a652 100644 --- a/spec/ruby/core/hash/hash_spec.rb +++ b/spec/ruby/core/hash/hash_spec.rb @@ -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 diff --git a/spec/ruby/core/hash/shared/store.rb b/spec/ruby/core/hash/shared/store.rb index dd1bb52bac..72a462a42f 100644 --- a/spec/ruby/core/hash/shared/store.rb +++ b/spec/ruby/core/hash/shared/store.rb @@ -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 diff --git a/spec/ruby/core/hash/transform_keys_spec.rb b/spec/ruby/core/hash/transform_keys_spec.rb index 2fbb17a8e2..f63d39ecc8 100644 --- a/spec/ruby/core/hash/transform_keys_spec.rb +++ b/spec/ruby/core/hash/transform_keys_spec.rb @@ -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 diff --git a/spec/ruby/core/integer/try_convert_spec.rb b/spec/ruby/core/integer/try_convert_spec.rb index 4bc7d3851a..8a0ca671a9 100644 --- a/spec/ruby/core/integer/try_convert_spec.rb +++ b/spec/ruby/core/integer/try_convert_spec.rb @@ -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 diff --git a/spec/ruby/core/io/external_encoding_spec.rb b/spec/ruby/core/io/external_encoding_spec.rb index 2fcf1c7218..7765c6c0f5 100644 --- a/spec/ruby/core/io/external_encoding_spec.rb +++ b/spec/ruby/core/io/external_encoding_spec.rb @@ -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 diff --git a/spec/ruby/core/io/internal_encoding_spec.rb b/spec/ruby/core/io/internal_encoding_spec.rb index 60afaf2ebd..7a583d4bcb 100644 --- a/spec/ruby/core/io/internal_encoding_spec.rb +++ b/spec/ruby/core/io/internal_encoding_spec.rb @@ -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 diff --git a/spec/ruby/core/io/readpartial_spec.rb b/spec/ruby/core/io/readpartial_spec.rb index 0852f20b2d..547da0677d 100644 --- a/spec/ruby/core/io/readpartial_spec.rb +++ b/spec/ruby/core/io/readpartial_spec.rb @@ -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 diff --git a/spec/ruby/core/io/write_nonblock_spec.rb b/spec/ruby/core/io/write_nonblock_spec.rb index c403c864fd..5bfc690f9b 100644 --- a/spec/ruby/core/io/write_nonblock_spec.rb +++ b/spec/ruby/core/io/write_nonblock_spec.rb @@ -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 diff --git a/spec/ruby/core/kernel/block_given_spec.rb b/spec/ruby/core/kernel/block_given_spec.rb index b00bfabfc3..aece4c821d 100644 --- a/spec/ruby/core/kernel/block_given_spec.rb +++ b/spec/ruby/core/kernel/block_given_spec.rb @@ -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 diff --git a/spec/ruby/core/kernel/eval_spec.rb b/spec/ruby/core/kernel/eval_spec.rb index 5f4cd27da0..c189d5f0a2 100644 --- a/spec/ruby/core/kernel/eval_spec.rb +++ b/spec/ruby/core/kernel/eval_spec.rb @@ -313,6 +313,8 @@ CODE eval(code) EvalSpecs.constants(false).should include(:"Vπ") EvalSpecs::Vπ.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 diff --git a/spec/ruby/core/kernel/fixtures/classes.rb b/spec/ruby/core/kernel/fixtures/classes.rb index 541a4c075e..0e2b81988f 100644 --- a/spec/ruby/core/kernel/fixtures/classes.rb +++ b/spec/ruby/core/kernel/fixtures/classes.rb @@ -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 diff --git a/spec/ruby/core/kernel/require_spec.rb b/spec/ruby/core/kernel/require_spec.rb index 4029e68725..e78e7176ec 100644 --- a/spec/ruby/core/kernel/require_spec.rb +++ b/spec/ruby/core/kernel/require_spec.rb @@ -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') diff --git a/spec/ruby/core/kernel/shared/load.rb b/spec/ruby/core/kernel/shared/load.rb index 0fe2d5ce16..62c5c7be9b 100644 --- a/spec/ruby/core/kernel/shared/load.rb +++ b/spec/ruby/core/kernel/shared/load.rb @@ -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 diff --git a/spec/ruby/core/main/private_spec.rb b/spec/ruby/core/main/private_spec.rb index e8c1f3f44c..76895fd649 100644 --- a/spec/ruby/core/main/private_spec.rb +++ b/spec/ruby/core/main/private_spec.rb @@ -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 diff --git a/spec/ruby/core/main/public_spec.rb b/spec/ruby/core/main/public_spec.rb index 31baad4583..3c77798fbc 100644 --- a/spec/ruby/core/main/public_spec.rb +++ b/spec/ruby/core/main/public_spec.rb @@ -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 diff --git a/spec/ruby/core/marshal/dump_spec.rb b/spec/ruby/core/marshal/dump_spec.rb index cc5337b50e..c2a2b77999 100644 --- a/spec/ruby/core/marshal/dump_spec.rb +++ b/spec/ruby/core/marshal/dump_spec.rb @@ -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 diff --git a/spec/ruby/core/marshal/shared/load.rb b/spec/ruby/core/marshal/shared/load.rb index fd6490153c..f73fa67e9a 100644 --- a/spec/ruby/core/marshal/shared/load.rb +++ b/spec/ruby/core/marshal/shared/load.rb @@ -23,250 +23,164 @@ 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? - - 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 + 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? - 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 + 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 objects" do - source_object = Object.new + 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 - object = Marshal.send(@method, Marshal.dump(source_object), freeze: true) - object.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 - describe "deep freezing" do - it "returns hashes with frozen keys and values" do - key = Object.new - value = Object.new - source_object = {key => value} + it "returns frozen regexps" do + regexp = Marshal.send(@method, Marshal.dump(/foo/), freeze: true) + regexp.should == /foo/ + regexp.should.frozen? + 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 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 arrays with frozen elements" do - object = Object.new - source_object = [object] + it "returns frozen objects" do + source_object = Object.new - array = Marshal.send(@method, Marshal.dump(source_object), freeze: true) - array.size.should == 1 - array[0].should.frozen? - end + object = Marshal.send(@method, Marshal.dump(source_object), freeze: true) + object.should.frozen? + end - it "returns structs with frozen members" do - object1 = Object.new - object2 = Object.new - source_object = MarshalSpec::StructToDump.new(object1, object2) + describe "deep freezing" do + it "returns hashes with frozen keys and values" do + key = Object.new + value = Object.new + source_object = {key => value} - struct = Marshal.send(@method, Marshal.dump(source_object), freeze: true) - struct.a.should.frozen? - struct.b.should.frozen? - 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 objects with frozen instance variables" do - source_object = Object.new - instance_variable = Object.new - source_object.instance_variable_set(:@a, instance_variable) + it "returns arrays with frozen elements" do + object = Object.new + source_object = [object] - 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 + array = Marshal.send(@method, Marshal.dump(source_object), freeze: true) + array.size.should == 1 + array[0].should.frozen? + end - it "deduplicates frozen strings" do - source_object = ["foo" + "bar", "foobar"] - object = Marshal.send(@method, Marshal.dump(source_object), freeze: true) + it "returns structs with frozen members" do + object1 = Object.new + object2 = Object.new + source_object = MarshalSpec::StructToDump.new(object1, object2) - object[0].should equal(object[1]) - end + struct = Marshal.send(@method, Marshal.dump(source_object), freeze: true) + struct.a.should.frozen? + struct.b.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? - 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) - it "does not freeze classes" do - object = Marshal.send(@method, Marshal.dump(Object), freeze: true) - object.should_not.frozen? - Object.should_not.frozen? + 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 - 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 "deduplicates frozen strings" do + source_object = ["foo" + "bar", "foobar"] + object = Marshal.send(@method, Marshal.dump(source_object), freeze: true) - 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 + object[0].should equal(object[1]) 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 "does not freeze modules" do + object = Marshal.send(@method, Marshal.dump(Kernel), freeze: true) + object.should_not.frozen? + Kernel.should_not.frozen? + end - it "returns frozen object extended by a module" do - object = Object.new - object.extend(MarshalSpec::ModuleToExtendBy) + it "does not freeze classes" do + object = Marshal.send(@method, Marshal.dump(Object), freeze: true) + object.should_not.frozen? + Object.should_not.frozen? + end - object = Marshal.send(@method, Marshal.dump(object), freeze: true) - object.should.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 - it "does not call freeze method" do - object = MarshalSpec::ObjectWithFreezeRaisingException.new - object = Marshal.send(@method, Marshal.dump(object), freeze: true) + 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 - 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) + 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 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") - - object = Marshal.send(@method, Marshal.dump(source_object), freeze: true) + 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 - 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} - - 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.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]], - ] - - arr.each do |v| - v.should.frozen? - end - - Struct.send(:remove_const, :Brittle) - end + it "returns frozen object extended by a module" do + object = Object.new + object.extend(MarshalSpec::ModuleToExtendBy) - 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 + object = Marshal.send(@method, Marshal.dump(object), freeze: true) + object.should.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 "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 "does not call freeze method" do + object = MarshalSpec::ObjectWithFreezeRaisingException.new + object = Marshal.send(@method, Marshal.dump(object), freeze: true) + object.should.frozen? end - ruby_bug "#19427", ""..."3.3" do - it "call the proc with extended objects" do - objs = [] - obj = Marshal.load("\x04\be:\x0FEnumerableo:\vObject\x00", Proc.new { |o| objs << o; o }) - objs.should == [obj] - 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 "returns the value of the proc" do - Marshal.send(@method, Marshal.dump([1,2]), proc { [3,4] }).should == [3,4] - 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") - 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 + object = Marshal.send(@method, Marshal.dump(source_object), freeze: true) + object.should.frozen? + end - it "loads an Array with proc" do + describe "when called with a proc" do + it "call the proc with frozen objects" do arr = [] s = +'hi' s.instance_variable_set(:@foo, 5) @@ -279,16 +193,96 @@ describe :marshal_load, shared: true do 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} + proc = Proc.new { |o| arr << o; 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, + freeze: true, + ) 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]], ] + + arr.each do |v| + v.should.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 + 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 + + ruby_bug "#19427", ""..."3.3" do + it "call the proc with extended objects" do + objs = [] + obj = Marshal.load("\x04\be:\x0FEnumerableo:\vObject\x00", Proc.new { |o| objs << o; o }) + objs.should == [obj] + end + end + + it "returns the value of the proc" do + Marshal.send(@method, Marshal.dump([1,2]), proc { [3,4] }).should == [3,4] + 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} + + 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 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 diff --git a/spec/ruby/core/matchdata/match_length_spec.rb b/spec/ruby/core/matchdata/match_length_spec.rb index f7785ab1a0..824f94a397 100644 --- a/spec/ruby/core/matchdata/match_length_spec.rb +++ b/spec/ruby/core/matchdata/match_length_spec.rb @@ -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 diff --git a/spec/ruby/core/matchdata/match_spec.rb b/spec/ruby/core/matchdata/match_spec.rb index 545de6f93f..a16914ea15 100644 --- a/spec/ruby/core/matchdata/match_spec.rb +++ b/spec/ruby/core/matchdata/match_spec.rb @@ -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 diff --git a/spec/ruby/core/method/parameters_spec.rb b/spec/ruby/core/method/parameters_spec.rb index 8495aef4d2..0178a61de6 100644 --- a/spec/ruby/core/method/parameters_spec.rb +++ b/spec/ruby/core/method/parameters_spec.rb @@ -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 - 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 + object.method(:foo).parameters.should == [[:block, :&]] 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 diff --git a/spec/ruby/core/method/private_spec.rb b/spec/ruby/core/method/private_spec.rb index fd550036a3..9b67a77243 100644 --- a/spec/ruby/core/method/private_spec.rb +++ b/spec/ruby/core/method/private_spec.rb @@ -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 diff --git a/spec/ruby/core/method/protected_spec.rb b/spec/ruby/core/method/protected_spec.rb index 8423e8c64c..28c60c7536 100644 --- a/spec/ruby/core/method/protected_spec.rb +++ b/spec/ruby/core/method/protected_spec.rb @@ -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 diff --git a/spec/ruby/core/method/public_spec.rb b/spec/ruby/core/method/public_spec.rb index 20d0081a27..4844f4b90b 100644 --- a/spec/ruby/core/method/public_spec.rb +++ b/spec/ruby/core/method/public_spec.rb @@ -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 diff --git a/spec/ruby/core/module/autoload_spec.rb b/spec/ruby/core/module/autoload_spec.rb index 45d18b8608..3cdc48f9ba 100644 --- a/spec/ruby/core/module/autoload_spec.rb +++ b/spec/ruby/core/module/autoload_spec.rb @@ -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 - - ModuleSpecs::Autoload.const_defined?(:O).should == true - ModuleSpecs::Autoload.should have_constant(:O) - ModuleSpecs::Autoload.autoload?(:O).should == path - - -> { ModuleSpecs::Autoload::O }.should raise_error(NameError) - - ModuleSpecs::Autoload.const_defined?(:O).should == false - ModuleSpecs::Autoload.should_not have_constant(:O) - ModuleSpecs::Autoload.autoload?(:O).should == nil - -> { ModuleSpecs::Autoload.const_get(:O) }.should raise_error(NameError) - end - end - - ruby_version_is ""..."3.1" do - it "does not remove the constant from Module#constants if the loaded file does not define it, but leaves it as 'undefined'" do - path = fixture(__FILE__, "autoload_o.rb") - ScratchPad.record [] - ModuleSpecs::Autoload.autoload :O, path + it "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 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 - } - - class LexicalScope - autoload :DeclaredInCurrentDefinedInParent, fixture(__FILE__, "autoload_callback.rb") - -> { DeclaredInCurrentDefinedInParent }.should_not raise_error(NameError) - # Basically, the autoload constant remains in a "undefined" state - self.autoload?(:DeclaredInCurrentDefinedInParent).should == nil - const_defined?(:DeclaredInCurrentDefinedInParent).should == false - -> { const_get(:DeclaredInCurrentDefinedInParent) }.should raise_error(NameError) - end + it "looks up in parent scope after failed autoload" do + @remove << :DeclaredInCurrentDefinedInParent + module ModuleSpecs::Autoload + ScratchPad.record -> { + DeclaredInCurrentDefinedInParent = :declared_in_current_defined_in_parent + } - DeclaredInCurrentDefinedInParent.should == :declared_in_current_defined_in_parent + class LexicalScope + autoload :DeclaredInCurrentDefinedInParent, fixture(__FILE__, "autoload_callback.rb") + -> { DeclaredInCurrentDefinedInParent }.should_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 diff --git a/spec/ruby/core/module/const_defined_spec.rb b/spec/ruby/core/module/const_defined_spec.rb index 027cf5a245..8b137cd134 100644 --- a/spec/ruby/core/module/const_defined_spec.rb +++ b/spec/ruby/core/module/const_defined_spec.rb @@ -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 diff --git a/spec/ruby/core/module/const_get_spec.rb b/spec/ruby/core/module/const_get_spec.rb index 0233118f4b..4b53cbe7b3 100644 --- a/spec/ruby/core/module/const_get_spec.rb +++ b/spec/ruby/core/module/const_get_spec.rb @@ -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 diff --git a/spec/ruby/core/module/const_set_spec.rb b/spec/ruby/core/module/const_set_spec.rb index 5bdfd7b68f..823768b882 100644 --- a/spec/ruby/core/module/const_set_spec.rb +++ b/spec/ruby/core/module/const_set_spec.rb @@ -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 diff --git a/spec/ruby/core/module/const_source_location_spec.rb b/spec/ruby/core/module/const_source_location_spec.rb index c194c9113f..06b3b215c2 100644 --- a/spec/ruby/core/module/const_source_location_spec.rb +++ b/spec/ruby/core/module/const_source_location_spec.rb @@ -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 diff --git a/spec/ruby/core/module/define_method_spec.rb b/spec/ruby/core/module/define_method_spec.rb index e04bb87ceb..c5dfc53764 100644 --- a/spec/ruby/core/module/define_method_spec.rb +++ b/spec/ruby/core/module/define_method_spec.rb @@ -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 diff --git a/spec/ruby/core/module/include_spec.rb b/spec/ruby/core/module/include_spec.rb index 862c6976e1..a1bfd3a6f5 100644 --- a/spec/ruby/core/module/include_spec.rb +++ b/spec/ruby/core/module/include_spec.rb @@ -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 diff --git a/spec/ruby/core/module/module_function_spec.rb b/spec/ruby/core/module/module_function_spec.rb index 1c3ec5471b..51f647142e 100644 --- a/spec/ruby/core/module/module_function_spec.rb +++ b/spec/ruby/core/module/module_function_spec.rb @@ -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 diff --git a/spec/ruby/core/module/name_spec.rb b/spec/ruby/core/module/name_spec.rb index 33e8400e88..b5c1f771f8 100644 --- a/spec/ruby/core/module/name_spec.rb +++ b/spec/ruby/core/module/name_spec.rb @@ -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 diff --git a/spec/ruby/core/module/prepend_spec.rb b/spec/ruby/core/module/prepend_spec.rb index b40d12f0de..9508fbf182 100644 --- a/spec/ruby/core/module/prepend_spec.rb +++ b/spec/ruby/core/module/prepend_spec.rb @@ -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 - - b.include(a) - a.prepend(m) - b.ancestors.take(4).should == [b, m, a, Object] + it "modifies the ancestor chain" do + m = Module.new do; end + a = Module.new do; end + b = Class.new do; end - b.prepend(m) - b.ancestors.take(4).should == [b, m, a, Object] - end - end + b.include(a) + a.prepend(m) + b.ancestors.take(4).should == [b, m, a, Object] - 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 diff --git a/spec/ruby/core/module/private_spec.rb b/spec/ruby/core/module/private_spec.rb index ead806637c..9e1a297eea 100644 --- a/spec/ruby/core/module/private_spec.rb +++ b/spec/ruby/core/module/private_spec.rb @@ -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 diff --git a/spec/ruby/core/module/protected_spec.rb b/spec/ruby/core/module/protected_spec.rb index 058d49d751..9e37223e18 100644 --- a/spec/ruby/core/module/protected_spec.rb +++ b/spec/ruby/core/module/protected_spec.rb @@ -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 diff --git a/spec/ruby/core/module/public_spec.rb b/spec/ruby/core/module/public_spec.rb index e3b183f228..ce31eb5d0e 100644 --- a/spec/ruby/core/module/public_spec.rb +++ b/spec/ruby/core/module/public_spec.rb @@ -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 diff --git a/spec/ruby/core/module/refine_spec.rb b/spec/ruby/core/module/refine_spec.rb index 8b9ea5eca8..7a5d607c4f 100644 --- a/spec/ruby/core/module/refine_spec.rb +++ b/spec/ruby/core/module/refine_spec.rb @@ -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 diff --git a/spec/ruby/core/module/remove_const_spec.rb b/spec/ruby/core/module/remove_const_spec.rb index 0ac23f05a5..35a9d65105 100644 --- a/spec/ruby/core/module/remove_const_spec.rb +++ b/spec/ruby/core/module/remove_const_spec.rb @@ -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 diff --git a/spec/ruby/core/module/to_s_spec.rb b/spec/ruby/core/module/to_s_spec.rb index 6b1a615ef9..83c0ae0825 100644 --- a/spec/ruby/core/module/to_s_spec.rb +++ b/spec/ruby/core/module/to_s_spec.rb @@ -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 diff --git a/spec/ruby/core/numeric/shared/imag.rb b/spec/ruby/core/numeric/shared/imag.rb index ac2da40a3b..4f117e243a 100644 --- a/spec/ruby/core/numeric/shared/imag.rb +++ b/spec/ruby/core/numeric/shared/imag.rb @@ -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 diff --git a/spec/ruby/core/numeric/shared/rect.rb b/spec/ruby/core/numeric/shared/rect.rb index 9cde19a398..120a69b1c4 100644 --- a/spec/ruby/core/numeric/shared/rect.rb +++ b/spec/ruby/core/numeric/shared/rect.rb @@ -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 diff --git a/spec/ruby/core/objectspace/define_finalizer_spec.rb b/spec/ruby/core/objectspace/define_finalizer_spec.rb index 329f8e1f30..0f4b54c345 100644 --- a/spec/ruby/core/objectspace/define_finalizer_spec.rb +++ b/spec/ruby/core/objectspace/define_finalizer_spec.rb @@ -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 - - ruby_exe(code, args: "2>&1").should include("warning: Exception in finalizer", "finalizing") - end + 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 + 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 diff --git a/spec/ruby/core/objectspace/weakkeymap/clear_spec.rb b/spec/ruby/core/objectspace/weakkeymap/clear_spec.rb new file mode 100644 index 0000000000..8050e2c307 --- /dev/null +++ b/spec/ruby/core/objectspace/weakkeymap/clear_spec.rb @@ -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 diff --git a/spec/ruby/core/objectspace/weakkeymap/delete_spec.rb b/spec/ruby/core/objectspace/weakkeymap/delete_spec.rb index 6e534b8ea8..3cd61355d6 100644 --- a/spec/ruby/core/objectspace/weakkeymap/delete_spec.rb +++ b/spec/ruby/core/objectspace/weakkeymap/delete_spec.rb @@ -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 diff --git a/spec/ruby/core/objectspace/weakkeymap/element_reference_spec.rb b/spec/ruby/core/objectspace/weakkeymap/element_reference_spec.rb index 862480cd02..51368e8d3b 100644 --- a/spec/ruby/core/objectspace/weakkeymap/element_reference_spec.rb +++ b/spec/ruby/core/objectspace/weakkeymap/element_reference_spec.rb @@ -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 diff --git a/spec/ruby/core/objectspace/weakkeymap/element_set_spec.rb b/spec/ruby/core/objectspace/weakkeymap/element_set_spec.rb index c427e01ca5..8db8d780c7 100644 --- a/spec/ruby/core/objectspace/weakkeymap/element_set_spec.rb +++ b/spec/ruby/core/objectspace/weakkeymap/element_set_spec.rb @@ -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) - end + key = +"a" + map[key] = 1 - it "rejects integers as keys" do - map = ObjectSpace::WeakKeyMap.new - should_not_accept(map, 42, true) - should_not_accept(map, 2 ** 68, true) - end + map.getkey("a").should.equal? key + map.getkey("a").should_not.frozen? - it "rejects floats as keys" do - map = ObjectSpace::WeakKeyMap.new - should_not_accept(map, 4.2, true) + key.should == "a" # keep the key alive until here to keep the map entry end - it "rejects booleans as keys" do - map = ObjectSpace::WeakKeyMap.new - should_not_accept(map, true, true) - should_not_accept(map, false, 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 nil as keys" do - map = ObjectSpace::WeakKeyMap.new - should_not_accept(map, nil, true) + 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 "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 "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 diff --git a/spec/ruby/core/objectspace/weakkeymap/fixtures/classes.rb b/spec/ruby/core/objectspace/weakkeymap/fixtures/classes.rb new file mode 100644 index 0000000000..0fd04551b5 --- /dev/null +++ b/spec/ruby/core/objectspace/weakkeymap/fixtures/classes.rb @@ -0,0 +1,5 @@ +module WeakKeyMapSpecs + class KeyWithPrivateHash + private :hash + end +end diff --git a/spec/ruby/core/objectspace/weakkeymap/getkey_spec.rb b/spec/ruby/core/objectspace/weakkeymap/getkey_spec.rb index 3af0186f27..8a2dbf809d 100644 --- a/spec/ruby/core/objectspace/weakkeymap/getkey_spec.rb +++ b/spec/ruby/core/objectspace/weakkeymap/getkey_spec.rb @@ -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 diff --git a/spec/ruby/core/objectspace/weakkeymap/inspect_spec.rb b/spec/ruby/core/objectspace/weakkeymap/inspect_spec.rb index 557fbc8733..319f050970 100644 --- a/spec/ruby/core/objectspace/weakkeymap/inspect_spec.rb +++ b/spec/ruby/core/objectspace/weakkeymap/inspect_spec.rb @@ -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 diff --git a/spec/ruby/core/objectspace/weakkeymap/key_spec.rb b/spec/ruby/core/objectspace/weakkeymap/key_spec.rb index 2af9c2b8e7..a9a2e12432 100644 --- a/spec/ruby/core/objectspace/weakkeymap/key_spec.rb +++ b/spec/ruby/core/objectspace/weakkeymap/key_spec.rb @@ -29,5 +29,16 @@ ruby_version_is "3.3" do map[key] = nil map.key?(key).should == true end + + it "returns false when a key cannot be garbage collected" do + map = ObjectSpace::WeakKeyMap.new + + map.key?(1).should == false + map.key?(1.0).should == false + map.key?(:a).should == false + map.key?(true).should == false + map.key?(false).should == false + map.key?(nil).should == false + end end end diff --git a/spec/ruby/core/proc/parameters_spec.rb b/spec/ruby/core/proc/parameters_spec.rb index 972596d2ea..7a2723487d 100644 --- a/spec/ruby/core/proc/parameters_spec.rb +++ b/spec/ruby/core/proc/parameters_spec.rb @@ -64,7 +64,7 @@ describe "Proc#parameters" do end it "regards keyword parameters in lambdas as required" do - eval("lambda {|x:| }").parameters.first.first.should == :keyreq + -> x: { }.parameters.first.first.should == :keyreq end it "sets the first element of each sub-Array to :rest for parameters prefixed with asterisks" do @@ -130,10 +130,8 @@ describe "Proc#parameters" do end end - ruby_version_is '3.1' do - it "adds block arg with name & for anonymous block argument" do - eval('-> & {}.parameters').should == [[:block, :&]] - end + it "adds block arg with name & for anonymous block argument" do + -> & {}.parameters.should == [[:block, :&]] end it "does not add locals as block options with a block and splat" do diff --git a/spec/ruby/core/process/_fork_spec.rb b/spec/ruby/core/process/_fork_spec.rb index 6f711ad2dd..8e907f54bb 100644 --- a/spec/ruby/core/process/_fork_spec.rb +++ b/spec/ruby/core/process/_fork_spec.rb @@ -1,24 +1,22 @@ require_relative '../../spec_helper' -ruby_version_is "3.1" do - describe "Process._fork" do - it "for #respond_to? returns the same as Process.respond_to?(:fork)" do - Process.respond_to?(:_fork).should == Process.respond_to?(:fork) - end +describe "Process._fork" do + it "for #respond_to? returns the same as Process.respond_to?(:fork)" do + Process.respond_to?(:_fork).should == Process.respond_to?(:fork) + end - guard_not -> { Process.respond_to?(:fork) } do - it "raises a NotImplementedError when called" do - -> { Process._fork }.should raise_error(NotImplementedError) - end + guard_not -> { Process.respond_to?(:fork) } do + it "raises a NotImplementedError when called" do + -> { Process._fork }.should raise_error(NotImplementedError) end + end - guard -> { Process.respond_to?(:fork) } do - it "is called by Process#fork" do - Process.should_receive(:_fork).once.and_return(42) + guard -> { Process.respond_to?(:fork) } do + it "is called by Process#fork" do + Process.should_receive(:_fork).once.and_return(42) - pid = Process.fork {} - pid.should equal(42) - end + pid = Process.fork {} + pid.should equal(42) end end end diff --git a/spec/ruby/core/process/gid_spec.rb b/spec/ruby/core/process/gid_spec.rb index 07221da420..ca935ed520 100644 --- a/spec/ruby/core/process/gid_spec.rb +++ b/spec/ruby/core/process/gid_spec.rb @@ -3,8 +3,8 @@ require_relative '../../spec_helper' describe "Process.gid" do platform_is_not :windows do it "returns the correct gid for the user executing this process" do - current_gid_according_to_unix = `id -gr`.to_i - Process.gid.should == current_gid_according_to_unix + current_gid_according_to_unix = `id -gr`.to_i + Process.gid.should == current_gid_according_to_unix end end diff --git a/spec/ruby/core/process/tms/cstime_spec.rb b/spec/ruby/core/process/tms/cstime_spec.rb new file mode 100644 index 0000000000..9c2d9e8632 --- /dev/null +++ b/spec/ruby/core/process/tms/cstime_spec.rb @@ -0,0 +1,17 @@ +require_relative '../../../spec_helper' + +describe "Process::Tms#cstime" do + it "returns cstime attribute" do + cstime = Object.new + Process::Tms.new(nil, nil, nil, cstime).cstime.should == cstime + end +end + +describe "Process::Tms#cstime=" do + it "assigns a value to the cstime attribute" do + cstime = Object.new + tms = Process::Tms.new + tms.cstime = cstime + tms.cstime.should == cstime + end +end diff --git a/spec/ruby/core/process/tms/cutime_spec.rb b/spec/ruby/core/process/tms/cutime_spec.rb new file mode 100644 index 0000000000..0ac3ff1964 --- /dev/null +++ b/spec/ruby/core/process/tms/cutime_spec.rb @@ -0,0 +1,17 @@ +require_relative '../../../spec_helper' + +describe "Process::Tms#cutime" do + it "returns cutime attribute" do + cutime = Object.new + Process::Tms.new(nil, nil, cutime, nil).cutime.should == cutime + end +end + +describe "Process::Tms#cutime=" do + it "assigns a value to the cutime attribute" do + cutime = Object.new + tms = Process::Tms.new + tms.cutime = cutime + tms.cutime.should == cutime + end +end diff --git a/spec/ruby/core/process/tms/stime_spec.rb b/spec/ruby/core/process/tms/stime_spec.rb new file mode 100644 index 0000000000..1e8371475f --- /dev/null +++ b/spec/ruby/core/process/tms/stime_spec.rb @@ -0,0 +1,17 @@ +require_relative '../../../spec_helper' + +describe "Process::Tms#stime" do + it "returns stime attribute" do + stime = Object.new + Process::Tms.new(nil, stime, nil, nil).stime.should == stime + end +end + +describe "Process::Tms#stime=" do + it "assigns a value to the stime attribute" do + stime = Object.new + tms = Process::Tms.new + tms.stime = stime + tms.stime.should == stime + end +end diff --git a/spec/ruby/core/process/tms/utime_spec.rb b/spec/ruby/core/process/tms/utime_spec.rb new file mode 100644 index 0000000000..403a31e2e6 --- /dev/null +++ b/spec/ruby/core/process/tms/utime_spec.rb @@ -0,0 +1,17 @@ +require_relative '../../../spec_helper' + +describe "Process::Tms#utime" do + it "returns utime attribute" do + utime = Object.new + Process::Tms.new(utime, nil, nil, nil).utime.should == utime + end +end + +describe "Process::Tms#utime=" do + it "assigns a value to the ctime attribute" do + utime = Object.new + tms = Process::Tms.new + tms.utime = utime + tms.utime.should == utime + end +end diff --git a/spec/ruby/core/queue/initialize_spec.rb b/spec/ruby/core/queue/initialize_spec.rb index c6c1ae63c5..592fbe2487 100644 --- a/spec/ruby/core/queue/initialize_spec.rb +++ b/spec/ruby/core/queue/initialize_spec.rb @@ -11,9 +11,21 @@ describe "Queue#initialize" do Queue.private_instance_methods.include?(:initialize).should == true end - ruby_version_is '3.1' do - it "adds all elements of the passed Enumerable to self" do - q = Queue.new([1, 2, 3]) + it "adds all elements of the passed Enumerable to self" do + q = Queue.new([1, 2, 3]) + q.size.should == 3 + q.should_not.empty? + q.pop.should == 1 + q.pop.should == 2 + q.pop.should == 3 + q.should.empty? + end + + describe "converts the given argument to an Array using #to_a" do + it "uses #to_a on the provided Enumerable" do + enumerable = MockObject.new('mock-enumerable') + enumerable.should_receive(:to_a).and_return([1, 2, 3]) + q = Queue.new(enumerable) q.size.should == 3 q.should_not.empty? q.pop.should == 1 @@ -22,41 +34,27 @@ describe "Queue#initialize" do q.should.empty? end - describe "converts the given argument to an Array using #to_a" do - it "uses #to_a on the provided Enumerable" do - enumerable = MockObject.new('mock-enumerable') - enumerable.should_receive(:to_a).and_return([1, 2, 3]) - q = Queue.new(enumerable) - q.size.should == 3 - q.should_not.empty? - q.pop.should == 1 - q.pop.should == 2 - q.pop.should == 3 - q.should.empty? - end - - it "raises a TypeError if the given argument can't be converted to an Array" do - -> { Queue.new(42) }.should raise_error(TypeError) - -> { Queue.new(:abc) }.should raise_error(TypeError) - end - - it "raises a NoMethodError if the given argument raises a NoMethodError during type coercion to an Array" do - enumerable = MockObject.new('mock-enumerable') - enumerable.should_receive(:to_a).and_raise(NoMethodError) - -> { Queue.new(enumerable) }.should raise_error(NoMethodError) - end + it "raises a TypeError if the given argument can't be converted to an Array" do + -> { Queue.new(42) }.should raise_error(TypeError) + -> { Queue.new(:abc) }.should raise_error(TypeError) end - it "raises TypeError if the provided Enumerable does not respond to #to_a" do + it "raises a NoMethodError if the given argument raises a NoMethodError during type coercion to an Array" do enumerable = MockObject.new('mock-enumerable') - -> { Queue.new(enumerable) }.should raise_error(TypeError, "can't convert MockObject into Array") + enumerable.should_receive(:to_a).and_raise(NoMethodError) + -> { Queue.new(enumerable) }.should raise_error(NoMethodError) end + end - it "raises TypeError if #to_a does not return Array" do - enumerable = MockObject.new('mock-enumerable') - enumerable.should_receive(:to_a).and_return("string") + it "raises TypeError if the provided Enumerable does not respond to #to_a" do + enumerable = MockObject.new('mock-enumerable') + -> { Queue.new(enumerable) }.should raise_error(TypeError, "can't convert MockObject into Array") + end - -> { Queue.new(enumerable) }.should raise_error(TypeError, "can't convert MockObject to Array (MockObject#to_a gives String)") - end + it "raises TypeError if #to_a does not return Array" do + enumerable = MockObject.new('mock-enumerable') + enumerable.should_receive(:to_a).and_return("string") + + -> { Queue.new(enumerable) }.should raise_error(TypeError, "can't convert MockObject to Array (MockObject#to_a gives String)") end end diff --git a/spec/ruby/core/range/each_spec.rb b/spec/ruby/core/range/each_spec.rb index ecae17c881..f10330d61d 100644 --- a/spec/ruby/core/range/each_spec.rb +++ b/spec/ruby/core/range/each_spec.rb @@ -40,21 +40,21 @@ describe "Range#each" do it "works with endless ranges" do a = [] - eval("(-2..)").each { |x| break if x > 2; a << x } + (-2..).each { |x| break if x > 2; a << x } a.should == [-2, -1, 0, 1, 2] a = [] - eval("(-2...)").each { |x| break if x > 2; a << x } + (-2...).each { |x| break if x > 2; a << x } a.should == [-2, -1, 0, 1, 2] end it "works with String endless ranges" do a = [] - eval("('A'..)").each { |x| break if x > "D"; a << x } + ('A'..).each { |x| break if x > "D"; a << x } a.should == ["A", "B", "C", "D"] a = [] - eval("('A'...)").each { |x| break if x > "D"; a << x } + ('A'...).each { |x| break if x > "D"; a << x } a.should == ["A", "B", "C", "D"] end @@ -82,27 +82,14 @@ describe "Range#each" do enum.to_a.should == [1, 2, 3] end - ruby_version_is "3.1" do - it "supports Time objects that respond to #succ" do - t = Time.utc(1970) - def t.succ; self + 1 end - t_succ = t.succ - def t_succ.succ; self + 1; end + it "supports Time objects that respond to #succ" do + t = Time.utc(1970) + def t.succ; self + 1 end + t_succ = t.succ + def t_succ.succ; self + 1; end - (t..t_succ).to_a.should == [Time.utc(1970), Time.utc(1970, nil, nil, nil, nil, 1)] - (t...t_succ).to_a.should == [Time.utc(1970)] - end - end - - ruby_version_is ""..."3.1" do - it "raises a TypeError if the first element is a Time object even if it responds to #succ" do - t = Time.utc(1970) - def t.succ; self + 1 end - t_succ = t.succ - def t_succ.succ; self + 1; end - - -> { (t..t_succ).each { |i| i } }.should raise_error(TypeError) - end + (t..t_succ).to_a.should == [Time.utc(1970), Time.utc(1970, nil, nil, nil, nil, 1)] + (t...t_succ).to_a.should == [Time.utc(1970)] end it "passes each Symbol element by using #succ" do diff --git a/spec/ruby/core/range/shared/cover_and_include.rb b/spec/ruby/core/range/shared/cover_and_include.rb index f36a2cef8b..cd2b3621bb 100644 --- a/spec/ruby/core/range/shared/cover_and_include.rb +++ b/spec/ruby/core/range/shared/cover_and_include.rb @@ -20,8 +20,8 @@ describe :range_cover_and_include, shared: true do end it "returns true if other is an element of self for endless ranges" do - eval("(1..)").send(@method, 2.4).should == true - eval("(0.5...)").send(@method, 2.4).should == true + (1..).send(@method, 2.4).should == true + (0.5...).send(@method, 2.4).should == true end it "returns true if other is an element of self for beginless ranges" do @@ -29,6 +29,17 @@ describe :range_cover_and_include, shared: true do (...10.5).send(@method, 2.4).should == true end + it "returns false if values are not comparable" do + (1..10).send(@method, nil).should == false + (1...10).send(@method, nil).should == false + + (..10).send(@method, nil).should == false + (...10).send(@method, nil).should == false + + (1..).send(@method, nil).should == false + (1...).send(@method, nil).should == false + end + it "compares values using <=>" do rng = (1..5) m = mock("int") diff --git a/spec/ruby/core/range/step_spec.rb b/spec/ruby/core/range/step_spec.rb index 31cfd400cc..0d0caf746d 100644 --- a/spec/ruby/core/range/step_spec.rb +++ b/spec/ruby/core/range/step_spec.rb @@ -322,13 +322,11 @@ describe "Range#step" do ScratchPad.recorded.should eql([1.0, 2.8, 4.6]) end - ruby_version_is '3.1' do - it "correctly handles values near the upper limit" do # https://bugs.ruby-lang.org/issues/16612 - (1.0...55.6).step(18.2) { |x| ScratchPad << x } - ScratchPad.recorded.should eql([1.0, 19.2, 37.4, 55.599999999999994]) + it "correctly handles values near the upper limit" do # https://bugs.ruby-lang.org/issues/16612 + (1.0...55.6).step(18.2) { |x| ScratchPad << x } + ScratchPad.recorded.should eql([1.0, 19.2, 37.4, 55.599999999999994]) - (1.0...55.6).step(18.2).size.should == 4 - end + (1.0...55.6).step(18.2).size.should == 4 end it "handles infinite values at either end" do @@ -408,108 +406,108 @@ describe "Range#step" do describe "with an endless range" do describe "and Integer values" do it "yield Integer values incremented by 1 when not passed a step" do - eval("(-2..)").step { |x| break if x > 2; ScratchPad << x } + (-2..).step { |x| break if x > 2; ScratchPad << x } ScratchPad.recorded.should eql([-2, -1, 0, 1, 2]) ScratchPad.record [] - eval("(-2...)").step { |x| break if x > 2; ScratchPad << x } + (-2...).step { |x| break if x > 2; ScratchPad << x } ScratchPad.recorded.should eql([-2, -1, 0, 1, 2]) end it "yields Integer values incremented by an Integer step" do - eval("(-5..)").step(2) { |x| break if x > 3; ScratchPad << x } + (-5..).step(2) { |x| break if x > 3; ScratchPad << x } ScratchPad.recorded.should eql([-5, -3, -1, 1, 3]) ScratchPad.record [] - eval("(-5...)").step(2) { |x| break if x > 3; ScratchPad << x } + (-5...).step(2) { |x| break if x > 3; ScratchPad << x } ScratchPad.recorded.should eql([-5, -3, -1, 1, 3]) end it "yields Float values incremented by a Float step" do - eval("(-2..)").step(1.5) { |x| break if x > 1.0; ScratchPad << x } + (-2..).step(1.5) { |x| break if x > 1.0; ScratchPad << x } ScratchPad.recorded.should eql([-2.0, -0.5, 1.0]) ScratchPad.record [] - eval("(-2..)").step(1.5) { |x| break if x > 1.0; ScratchPad << x } + (-2..).step(1.5) { |x| break if x > 1.0; ScratchPad << x } ScratchPad.recorded.should eql([-2.0, -0.5, 1.0]) end end describe "and Float values" do it "yields Float values incremented by 1 and less than end when not passed a step" do - eval("(-2.0..)").step { |x| break if x > 1.5; ScratchPad << x } + (-2.0..).step { |x| break if x > 1.5; ScratchPad << x } ScratchPad.recorded.should eql([-2.0, -1.0, 0.0, 1.0]) ScratchPad.record [] - eval("(-2.0...)").step { |x| break if x > 1.5; ScratchPad << x } + (-2.0...).step { |x| break if x > 1.5; ScratchPad << x } ScratchPad.recorded.should eql([-2.0, -1.0, 0.0, 1.0]) end it "yields Float values incremented by an Integer step" do - eval("(-5.0..)").step(2) { |x| break if x > 3.5; ScratchPad << x } + (-5.0..).step(2) { |x| break if x > 3.5; ScratchPad << x } ScratchPad.recorded.should eql([-5.0, -3.0, -1.0, 1.0, 3.0]) ScratchPad.record [] - eval("(-5.0...)").step(2) { |x| break if x > 3.5; ScratchPad << x } + (-5.0...).step(2) { |x| break if x > 3.5; ScratchPad << x } ScratchPad.recorded.should eql([-5.0, -3.0, -1.0, 1.0, 3.0]) end it "yields Float values incremented by a Float step" do - eval("(-1.0..)").step(0.5) { |x| break if x > 0.6; ScratchPad << x } + (-1.0..).step(0.5) { |x| break if x > 0.6; ScratchPad << x } ScratchPad.recorded.should eql([-1.0, -0.5, 0.0, 0.5]) ScratchPad.record [] - eval("(-1.0...)").step(0.5) { |x| break if x > 0.6; ScratchPad << x } + (-1.0...).step(0.5) { |x| break if x > 0.6; ScratchPad << x } ScratchPad.recorded.should eql([-1.0, -0.5, 0.0, 0.5]) end it "handles infinite values at the start" do - eval("(-Float::INFINITY..)").step(2) { |x| ScratchPad << x; break if ScratchPad.recorded.size == 3 } + (-Float::INFINITY..).step(2) { |x| ScratchPad << x; break if ScratchPad.recorded.size == 3 } ScratchPad.recorded.should eql([-Float::INFINITY, -Float::INFINITY, -Float::INFINITY]) ScratchPad.record [] - eval("(-Float::INFINITY...)").step(2) { |x| ScratchPad << x; break if ScratchPad.recorded.size == 3 } + (-Float::INFINITY...).step(2) { |x| ScratchPad << x; break if ScratchPad.recorded.size == 3 } ScratchPad.recorded.should eql([-Float::INFINITY, -Float::INFINITY, -Float::INFINITY]) end end describe "and String values" do it "yields String values incremented by #succ and less than or equal to end when not passed a step" do - eval("('A'..)").step { |x| break if x > "D"; ScratchPad << x } + ('A'..).step { |x| break if x > "D"; ScratchPad << x } ScratchPad.recorded.should == ["A", "B", "C", "D"] ScratchPad.record [] - eval("('A'...)").step { |x| break if x > "D"; ScratchPad << x } + ('A'...).step { |x| break if x > "D"; ScratchPad << x } ScratchPad.recorded.should == ["A", "B", "C", "D"] end it "yields String values incremented by #succ called Integer step times" do - eval("('A'..)").step(2) { |x| break if x > "F"; ScratchPad << x } + ('A'..).step(2) { |x| break if x > "F"; ScratchPad << x } ScratchPad.recorded.should == ["A", "C", "E"] ScratchPad.record [] - eval("('A'...)").step(2) { |x| break if x > "F"; ScratchPad << x } + ('A'...).step(2) { |x| break if x > "F"; ScratchPad << x } ScratchPad.recorded.should == ["A", "C", "E"] end it "raises a TypeError when passed a Float step" do - -> { eval("('A'..)").step(2.0) { } }.should raise_error(TypeError) - -> { eval("('A'...)").step(2.0) { } }.should raise_error(TypeError) + -> { ('A'..).step(2.0) { } }.should raise_error(TypeError) + -> { ('A'...).step(2.0) { } }.should raise_error(TypeError) end ruby_version_is "3.4" do it "yields String values adjusted by step" do - eval("('A'..)").step("A") { |x| break if x > "AAA"; ScratchPad << x } + ('A'..).step("A") { |x| break if x > "AAA"; ScratchPad << x } ScratchPad.recorded.should == ["A", "AA", "AAA"] ScratchPad.record [] - eval("('A'...)").step("A") { |x| break if x > "AAA"; ScratchPad << x } + ('A'...).step("A") { |x| break if x > "AAA"; ScratchPad << x } ScratchPad.recorded.should == ["A", "AA", "AAA"] end it "raises a TypeError when passed an incompatible type step" do - -> { eval("('A'..)").step([]) { } }.should raise_error(TypeError) - -> { eval("('A'...)").step([]) { } }.should raise_error(TypeError) + -> { ('A'..).step([]) { } }.should raise_error(TypeError) + -> { ('A'...).step([]) { } }.should raise_error(TypeError) end end end diff --git a/spec/ruby/core/refinement/import_methods_spec.rb b/spec/ruby/core/refinement/import_methods_spec.rb index 614c54dff8..13c0b1004c 100644 --- a/spec/ruby/core/refinement/import_methods_spec.rb +++ b/spec/ruby/core/refinement/import_methods_spec.rb @@ -2,137 +2,76 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' describe "Refinement#import_methods" do - ruby_version_is "3.1" do - context "when methods are defined in Ruby code" do - it "imports methods" do - str_utils = Module.new do - def indent(level) - " " * level + self - end - end - - Module.new do - refine String do - import_methods str_utils - "foo".indent(3).should == " foo" - end + context "when methods are defined in Ruby code" do + it "imports methods" do + str_utils = Module.new do + def indent(level) + " " * level + self end end - it "throws an exception when argument is not a module" do - Module.new do - refine String do - -> { - import_methods Integer - }.should raise_error(TypeError, "wrong argument type Class (expected Module)") - end + Module.new do + refine String do + import_methods str_utils + "foo".indent(3).should == " foo" end end + end - it "imports methods from multiple modules" do - str_utils = Module.new do - def indent(level) - " " * level + self - end - end - - str_utils_fancy = Module.new do - def indent_star(level) - "*" * level + self - end - end - - Module.new do - refine String do - import_methods str_utils, str_utils_fancy - "foo".indent(3).should == " foo" - "foo".indent_star(3).should == "***foo" - end + it "throws an exception when argument is not a module" do + Module.new do + refine String do + -> { + import_methods Integer + }.should raise_error(TypeError, "wrong argument type Class (expected Module)") end end + end - it "imports a method defined in the last module if method with same name is defined in multiple modules" do - str_utils = Module.new do - def indent(level) - " " * level + self - end - end - - str_utils_fancy = Module.new do - def indent(level) - "*" * level + self - end - end - - Module.new do - refine String do - import_methods str_utils, str_utils_fancy - "foo".indent(3).should == "***foo" - end + it "imports methods from multiple modules" do + str_utils = Module.new do + def indent(level) + " " * level + self end end - it "still imports methods of modules listed before a module that contains method not defined in Ruby" do - str_utils = Module.new do - def indent(level) - " " * level + self - end - end - - string_refined = Module.new do - refine String do - -> { - import_methods str_utils, Kernel - }.should raise_error(ArgumentError) - end + str_utils_fancy = Module.new do + def indent_star(level) + "*" * level + self end + end - Module.new do - using string_refined + Module.new do + refine String do + import_methods str_utils, str_utils_fancy "foo".indent(3).should == " foo" + "foo".indent_star(3).should == "***foo" end end end - it "warns if a module includes/prepends some other module" do - module1 = Module.new do - end - - module2 = Module.new do - include module1 - end - - Module.new do - refine String do - -> { - import_methods module2 - }.should complain(/warning: #<Module:\w*> has ancestors, but Refinement#import_methods doesn't import their methods/) + it "imports a method defined in the last module if method with same name is defined in multiple modules" do + str_utils = Module.new do + def indent(level) + " " * level + self end end - Module.new do - refine String do - -> { - import_methods RefinementSpec::ModuleWithAncestors - }.should complain(/warning: RefinementSpec::ModuleWithAncestors has ancestors, but Refinement#import_methods doesn't import their methods/) + str_utils_fancy = Module.new do + def indent(level) + "*" * level + self end end - end - it "doesn't import methods from included/prepended modules" do Module.new do refine String do - suppress_warning { import_methods RefinementSpec::ModuleWithAncestors } + import_methods str_utils, str_utils_fancy + "foo".indent(3).should == "***foo" end - - using self - -> { - "foo".indent(3) - }.should raise_error(NoMethodError, /undefined method [`']indent' for ("foo":String|an instance of String)/) end end - it "doesn't import any methods if one of the arguments is not a module" do + it "still imports methods of modules listed before a module that contains method not defined in Ruby" do str_utils = Module.new do def indent(level) " " * level + self @@ -142,126 +81,185 @@ describe "Refinement#import_methods" do string_refined = Module.new do refine String do -> { - import_methods str_utils, Integer - }.should raise_error(TypeError) + import_methods str_utils, Kernel + }.should raise_error(ArgumentError) end end Module.new do using string_refined + "foo".indent(3).should == " foo" + end + end + end + + it "warns if a module includes/prepends some other module" do + module1 = Module.new do + end + + module2 = Module.new do + include module1 + end + + Module.new do + refine String do -> { - "foo".indent(3) - }.should raise_error(NoMethodError) + import_methods module2 + }.should complain(/warning: #<Module:\w*> has ancestors, but Refinement#import_methods doesn't import their methods/) end end - it "imports methods from multiple modules so that methods see other's module's methods" do - str_utils = Module.new do - def indent(level) - " " * level + self - end + Module.new do + refine String do + -> { + import_methods RefinementSpec::ModuleWithAncestors + }.should complain(/warning: RefinementSpec::ModuleWithAncestors has ancestors, but Refinement#import_methods doesn't import their methods/) + end + end + end + + it "doesn't import methods from included/prepended modules" do + Module.new do + refine String do + suppress_warning { import_methods RefinementSpec::ModuleWithAncestors } end - str_utils_normal = Module.new do - def indent_normal(level) - self.indent(level) - end + using self + -> { + "foo".indent(3) + }.should raise_error(NoMethodError, /undefined method [`']indent' for ("foo":String|an instance of String)/) + end + end + + it "doesn't import any methods if one of the arguments is not a module" do + str_utils = Module.new do + def indent(level) + " " * level + self end + end - Module.new do - refine String do - import_methods str_utils, str_utils_normal - end + string_refined = Module.new do + refine String do + -> { + import_methods str_utils, Integer + }.should raise_error(TypeError) + end + end - using self - "foo".indent_normal(3).should == " foo" + Module.new do + using string_refined + -> { + "foo".indent(3) + }.should raise_error(NoMethodError) + end + end + + it "imports methods from multiple modules so that methods see other's module's methods" do + str_utils = Module.new do + def indent(level) + " " * level + self end end - it "imports methods from module so that methods can see each other" do - str_utils = Module.new do - def indent(level) - " " * level + self - end + str_utils_normal = Module.new do + def indent_normal(level) + self.indent(level) + end + end - def indent_with_dot(level) - self.indent(level) + "." - end + Module.new do + refine String do + import_methods str_utils, str_utils_normal end - Module.new do - refine String do - import_methods str_utils - end + using self + "foo".indent_normal(3).should == " foo" + end + end - using self - "foo".indent_with_dot(3).should == " foo." + it "imports methods from module so that methods can see each other" do + str_utils = Module.new do + def indent(level) + " " * level + self + end + + def indent_with_dot(level) + self.indent(level) + "." end end - it "doesn't import module's class methods" do - str_utils = Module.new do - def self.indent(level) - " " * level + self - end + Module.new do + refine String do + import_methods str_utils end - Module.new do - refine String do - import_methods str_utils - end + using self + "foo".indent_with_dot(3).should == " foo." + end + end - using self - -> { - String.indent(3) - }.should raise_error(NoMethodError, /undefined method [`']indent' for (String:Class|class String)/) + it "doesn't import module's class methods" do + str_utils = Module.new do + def self.indent(level) + " " * level + self end end - it "imports module methods with super" do - class_to_refine = Class.new do - def foo(number) - 2 * number - end + Module.new do + refine String do + import_methods str_utils end - extension = Module.new do - def foo(number) - super * 2 - end + using self + -> { + String.indent(3) + }.should raise_error(NoMethodError, /undefined method [`']indent' for (String:Class|class String)/) + end + end + + it "imports module methods with super" do + class_to_refine = Class.new do + def foo(number) + 2 * number end + end - refinement = Module.new do - refine class_to_refine do - import_methods extension - end + extension = Module.new do + def foo(number) + super * 2 end + end - Module.new do - using refinement - class_to_refine.new.foo(2).should == 8 + refinement = Module.new do + refine class_to_refine do + import_methods extension end end - context "when methods are not defined in Ruby code" do - it "raises ArgumentError" do - Module.new do - refine String do - -> { - import_methods Kernel - }.should raise_error(ArgumentError) - end + Module.new do + using refinement + class_to_refine.new.foo(2).should == 8 + end + end + + context "when methods are not defined in Ruby code" do + it "raises ArgumentError" do + Module.new do + refine String do + -> { + import_methods Kernel + }.should raise_error(ArgumentError) end end + end - it "raises ArgumentError when importing methods from C extension" do - require 'zlib' - Module.new do - refine String do - -> { - import_methods Zlib - }.should raise_error(ArgumentError, /Can't import method which is not defined with Ruby code: Zlib#*/) - end + it "raises ArgumentError when importing methods from C extension" do + require 'zlib' + Module.new do + refine String do + -> { + import_methods Zlib + }.should raise_error(ArgumentError, /Can't import method which is not defined with Ruby code: Zlib#*/) end end end diff --git a/spec/ruby/core/refinement/include_spec.rb b/spec/ruby/core/refinement/include_spec.rb index 25a53f0ec7..d20ab47e33 100644 --- a/spec/ruby/core/refinement/include_spec.rb +++ b/spec/ruby/core/refinement/include_spec.rb @@ -1,7 +1,7 @@ require_relative '../../spec_helper' describe "Refinement#include" do - ruby_version_is "3.1"..."3.2" do + ruby_version_is ""..."3.2" do it "warns about deprecation" do Module.new do refine String do diff --git a/spec/ruby/core/refinement/prepend_spec.rb b/spec/ruby/core/refinement/prepend_spec.rb index 27b70d392a..5d66766689 100644 --- a/spec/ruby/core/refinement/prepend_spec.rb +++ b/spec/ruby/core/refinement/prepend_spec.rb @@ -1,7 +1,7 @@ require_relative '../../spec_helper' describe "Refinement#prepend" do - ruby_version_is "3.1"..."3.2" do + ruby_version_is ""..."3.2" do it "warns about deprecation" do Module.new do refine String do diff --git a/spec/ruby/core/string/byterindex_spec.rb b/spec/ruby/core/string/byterindex_spec.rb index 150f709b90..34ecbfbd21 100644 --- a/spec/ruby/core/string/byterindex_spec.rb +++ b/spec/ruby/core/string/byterindex_spec.rb @@ -352,8 +352,8 @@ describe "String#byterindex with Regexp" do end it "returns the character index before the finish" do - "ありがりがとう".byterindex("が", 9).should == 6 - "ありがりがとう".byterindex(/が/, 9).should == 6 + "ありがりがとう".byterindex("が", 9).should == 6 + "ありがりがとう".byterindex(/が/, 9).should == 6 end end end diff --git a/spec/ruby/core/string/chilled_string_spec.rb b/spec/ruby/core/string/chilled_string_spec.rb index b8fb6eedc9..968e4ec1f0 100644 --- a/spec/ruby/core/string/chilled_string_spec.rb +++ b/spec/ruby/core/string/chilled_string_spec.rb @@ -64,7 +64,7 @@ describe "chilled String" do input.freeze -> { -> { - input << "mutated" + input << "mutated" }.should raise_error(FrozenError) }.should_not complain(/literal string will be frozen in the future/) end @@ -133,7 +133,7 @@ describe "chilled String" do input.freeze -> { -> { - input << "mutated" + input << "mutated" }.should raise_error(FrozenError) }.should_not complain(/string returned by :chilled\.to_s will be frozen in the future/) end diff --git a/spec/ruby/core/string/lstrip_spec.rb b/spec/ruby/core/string/lstrip_spec.rb index 99bab6f349..c83650207e 100644 --- a/spec/ruby/core/string/lstrip_spec.rb +++ b/spec/ruby/core/string/lstrip_spec.rb @@ -7,11 +7,11 @@ describe "String#lstrip" do it_behaves_like :string_strip, :lstrip it "returns a copy of self with leading whitespace removed" do - " hello ".lstrip.should == "hello " - " hello world ".lstrip.should == "hello world " - "\n\r\t\n\v\r hello world ".lstrip.should == "hello world " - "hello".lstrip.should == "hello" - " こにちわ".lstrip.should == "こにちわ" + " hello ".lstrip.should == "hello " + " hello world ".lstrip.should == "hello world " + "\n\r\t\n\v\r hello world ".lstrip.should == "hello world " + "hello".lstrip.should == "hello" + " こにちわ".lstrip.should == "こにちわ" end it "works with lazy substrings" do @@ -22,8 +22,8 @@ describe "String#lstrip" do end it "strips leading \\0" do - "\x00hello".lstrip.should == "hello" - "\000 \000hello\000 \000".lstrip.should == "hello\000 \000" + "\x00hello".lstrip.should == "hello" + "\000 \000hello\000 \000".lstrip.should == "hello\000 \000" end end diff --git a/spec/ruby/core/string/rindex_spec.rb b/spec/ruby/core/string/rindex_spec.rb index 88ce733583..0863a9c3be 100644 --- a/spec/ruby/core/string/rindex_spec.rb +++ b/spec/ruby/core/string/rindex_spec.rb @@ -371,8 +371,8 @@ describe "String#rindex with Regexp" do end it "returns the character index before the finish" do - "ありがりがとう".rindex("が", 3).should == 2 - "ありがりがとう".rindex(/が/, 3).should == 2 + "ありがりがとう".rindex("が", 3).should == 2 + "ありがりがとう".rindex(/が/, 3).should == 2 end it "raises an Encoding::CompatibilityError if the encodings are incompatible" do diff --git a/spec/ruby/core/string/scan_spec.rb b/spec/ruby/core/string/scan_spec.rb index 70c3b7fb7b..bbe843b591 100644 --- a/spec/ruby/core/string/scan_spec.rb +++ b/spec/ruby/core/string/scan_spec.rb @@ -103,11 +103,11 @@ describe "String#scan with pattern and block" do offsets = [] str.scan(/([aeiou])/) do - md = $~ - md.string.should == str - matches << md.to_a - offsets << md.offset(0) - str + md = $~ + md.string.should == str + matches << md.to_a + offsets << md.offset(0) + str end matches.should == [["e", "e"], ["o", "o"]] @@ -117,11 +117,11 @@ describe "String#scan with pattern and block" do offsets = [] str.scan("l") do - md = $~ - md.string.should == str - matches << md.to_a - offsets << md.offset(0) - str + md = $~ + md.string.should == str + matches << md.to_a + offsets << md.offset(0) + str end matches.should == [["l"], ["l"]] diff --git a/spec/ruby/core/string/shared/slice.rb b/spec/ruby/core/string/shared/slice.rb index 2f69b9ddce..7b9b9f6a14 100644 --- a/spec/ruby/core/string/shared/slice.rb +++ b/spec/ruby/core/string/shared/slice.rb @@ -119,6 +119,18 @@ describe :string_slice_index_length, shared: true do "hello there".send(@method, -4,-3).should == nil end + platform_is pointer_size: 64 do + it "returns nil if the length is negative big value" do + "hello there".send(@method, 4, -(1 << 31)).should == nil + + # by some reason length < -(1 << 31) on CI on Windows leads to + # 'RangeError: bignum too big to convert into `long'' error + platform_is_not :windows do + "hello there".send(@method, 4, -(1 << 63)).should == nil + end + end + end + it "calls to_int on the given index and the given length" do "hello".send(@method, 0.5, 1).should == "h" "hello".send(@method, 0.5, 2.5).should == "he" @@ -152,6 +164,11 @@ describe :string_slice_index_length, shared: true do -> { "hello".send(@method, 0, bignum_value) }.should raise_error(RangeError) end + it "raises a RangeError if the index or length is too small" do + -> { "hello".send(@method, -bignum_value, 1) }.should raise_error(RangeError) + -> { "hello".send(@method, 0, -bignum_value) }.should raise_error(RangeError) + end + it "returns String instances" do s = StringSpecs::MyString.new("hello") s.send(@method, 0,0).should be_an_instance_of(String) diff --git a/spec/ruby/core/string/sub_spec.rb b/spec/ruby/core/string/sub_spec.rb index 4f9f87a433..6ff28ec851 100644 --- a/spec/ruby/core/string/sub_spec.rb +++ b/spec/ruby/core/string/sub_spec.rb @@ -232,10 +232,10 @@ describe "String#sub with pattern and block" do offsets = [] str.sub(/([aeiou])/) do - md = $~ - md.string.should == str - offsets << md.offset(0) - str + md = $~ + md.string.should == str + offsets << md.offset(0) + str end.should == "hhellollo" offsets.should == [[1, 2]] @@ -339,10 +339,10 @@ describe "String#sub! with pattern and block" do offsets = [] str.dup.sub!(/([aeiou])/) do - md = $~ - md.string.should == str - offsets << md.offset(0) - str + md = $~ + md.string.should == str + offsets << md.offset(0) + str end.should == "hhellollo" offsets.should == [[1, 2]] diff --git a/spec/ruby/core/string/swapcase_spec.rb b/spec/ruby/core/string/swapcase_spec.rb index 7f4c68366d..011a213501 100644 --- a/spec/ruby/core/string/swapcase_spec.rb +++ b/spec/ruby/core/string/swapcase_spec.rb @@ -5,9 +5,9 @@ require_relative 'fixtures/classes' describe "String#swapcase" do it "returns a new string with all uppercase chars from self converted to lowercase and vice versa" do - "Hello".swapcase.should == "hELLO" - "cYbEr_PuNk11".swapcase.should == "CyBeR_pUnK11" - "+++---111222???".swapcase.should == "+++---111222???" + "Hello".swapcase.should == "hELLO" + "cYbEr_PuNk11".swapcase.should == "CyBeR_pUnK11" + "+++---111222???".swapcase.should == "+++---111222???" end it "returns a String in the same encoding as self" do diff --git a/spec/ruby/core/string/to_c_spec.rb b/spec/ruby/core/string/to_c_spec.rb index 9d24f1f56c..4864a98e39 100644 --- a/spec/ruby/core/string/to_c_spec.rb +++ b/spec/ruby/core/string/to_c_spec.rb @@ -18,13 +18,17 @@ describe "String#to_c" do end end - it "understands Float::INFINITY" do - 'Infinity'.to_c.should == Complex(0, 1) - '-Infinity'.to_c.should == Complex(0, -1) - end + context "it treats special float value strings as characters" do + it "parses any string that starts with 'I' as 1i" do + 'Infinity'.to_c.should == Complex(0, 1) + '-Infinity'.to_c.should == Complex(0, -1) + 'Insecure'.to_c.should == Complex(0, 1) + '-Insecure'.to_c.should == Complex(0, -1) + end - it "understands Float::NAN" do - 'NaN'.to_c.should == Complex(0, 0) + it "does not parse any numeric information in 'NaN'" do + 'NaN'.to_c.should == Complex(0, 0) + end end it "allows null-byte" do diff --git a/spec/ruby/core/string/to_f_spec.rb b/spec/ruby/core/string/to_f_spec.rb index cf64ecfc5d..72e2a90b13 100644 --- a/spec/ruby/core/string/to_f_spec.rb +++ b/spec/ruby/core/string/to_f_spec.rb @@ -5,16 +5,15 @@ require_relative 'fixtures/classes' describe "String#to_f" do it "treats leading characters of self as a floating point number" do - "123.45e1".to_f.should == 1234.5 - "45.67 degrees".to_f.should == 45.67 - "0".to_f.should == 0.0 - "123.45e1".to_f.should == 1234.5 + "123.45e1".to_f.should == 1234.5 + "45.67 degrees".to_f.should == 45.67 + "0".to_f.should == 0.0 - ".5".to_f.should == 0.5 - ".5e1".to_f.should == 5.0 - "5.".to_f.should == 5.0 - "5e".to_f.should == 5.0 - "5E".to_f.should == 5.0 + ".5".to_f.should == 0.5 + ".5e1".to_f.should == 5.0 + "5.".to_f.should == 5.0 + "5e".to_f.should == 5.0 + "5E".to_f.should == 5.0 end it "treats special float value strings as characters" do @@ -43,18 +42,39 @@ describe "String#to_f" do "1_234_567.890_1".to_f.should == 1_234_567.890_1 end - it "returns 0 for strings with any non-digit in them" do - "blah".to_f.should == 0 - "0b5".to_f.should == 0 - "0d5".to_f.should == 0 - "0o5".to_f.should == 0 - "0xx5".to_f.should == 0 - end - it "returns 0 for strings with leading underscores" do "_9".to_f.should == 0 end + it "stops if the underscore is not followed or preceded by a number" do + "1__2".to_f.should == 1.0 + "1_.2".to_f.should == 1.0 + "1._2".to_f.should == 1.0 + "1.2_e2".to_f.should == 1.2 + "1.2e_2".to_f.should == 1.2 + "1_x2".to_f.should == 1.0 + "1x_2".to_f.should == 1.0 + "+_1".to_f.should == 0.0 + "-_1".to_f.should == 0.0 + end + + it "does not allow prefixes to autodetect the base" do + "0b10".to_f.should == 0 + "010".to_f.should == 10 + "0o10".to_f.should == 0 + "0d10".to_f.should == 0 + "0x10".to_f.should == 0 + end + + it "treats any non-numeric character other than '.', 'e' and '_' as terminals" do + "blah".to_f.should == 0 + "1b5".to_f.should == 1 + "1d5".to_f.should == 1 + "1o5".to_f.should == 1 + "1xx5".to_f.should == 1 + "x5".to_f.should == 0 + end + it "takes an optional sign" do "-45.67 degrees".to_f.should == -45.67 "+45.67 degrees".to_f.should == 45.67 @@ -63,8 +83,48 @@ describe "String#to_f" do (1.0 / "-0".to_f).to_s.should == "-Infinity" end + it "treats a second 'e' as terminal" do + "1.234e1e2".to_f.should == 1.234e1 + end + + it "treats a second '.' as terminal" do + "1.2.3".to_f.should == 1.2 + end + + it "treats a '.' after an 'e' as terminal" do + "1.234e1.9".to_f.should == 1.234e1 + end + it "returns 0.0 if the conversion fails" do "bad".to_f.should == 0.0 "thx1138".to_f.should == 0.0 end + + it "ignores leading and trailing whitespace" do + " 1.2".to_f.should == 1.2 + "1.2 ".to_f.should == 1.2 + " 1.2 ".to_f.should == 1.2 + "\t1.2".to_f.should == 1.2 + "\n1.2".to_f.should == 1.2 + "\v1.2".to_f.should == 1.2 + "\f1.2".to_f.should == 1.2 + "\r1.2".to_f.should == 1.2 + end + + it "treats non-printable ASCII characters as terminals" do + "\0001.2".to_f.should == 0 + "\0011.2".to_f.should == 0 + "\0371.2".to_f.should == 0 + "\1771.2".to_f.should == 0 + "\2001.2".b.to_f.should == 0 + "\3771.2".b.to_f.should == 0 + end + + ruby_version_is "3.2" do + it "raises Encoding::CompatibilityError if String is in not ASCII-compatible encoding" do + -> { + '1.2'.encode("UTF-16").to_f + }.should raise_error(Encoding::CompatibilityError, "ASCII incompatible encoding: UTF-16") + end + end end diff --git a/spec/ruby/core/string/to_i_spec.rb b/spec/ruby/core/string/to_i_spec.rb index 9931502baa..39f69acda3 100644 --- a/spec/ruby/core/string/to_i_spec.rb +++ b/spec/ruby/core/string/to_i_spec.rb @@ -10,7 +10,7 @@ describe "String#to_i" do "1_2_3asdf".to_i.should == 123 end - it "ignores multiple non-consecutive underscoes when the first digit is 0" do + it "ignores multiple non-consecutive underscores when the first digit is 0" do (2..16).each do |base| "0_0_010".to_i(base).should == base; end diff --git a/spec/ruby/core/string/to_r_spec.rb b/spec/ruby/core/string/to_r_spec.rb index 7e1d635d3b..4ffbb10d98 100644 --- a/spec/ruby/core/string/to_r_spec.rb +++ b/spec/ruby/core/string/to_r_spec.rb @@ -33,6 +33,10 @@ describe "String#to_r" do "-20".to_r.should == Rational(-20, 1) end + it "accepts leading plus signs" do + "+20".to_r.should == Rational(20, 1) + end + it "does not treat a leading period without a numeric prefix as a decimal point" do ".9".to_r.should_not == Rational(8106479329266893, 9007199254740992) end diff --git a/spec/ruby/core/string/unpack1_spec.rb b/spec/ruby/core/string/unpack1_spec.rb index df830916a3..3b3b879f75 100644 --- a/spec/ruby/core/string/unpack1_spec.rb +++ b/spec/ruby/core/string/unpack1_spec.rb @@ -8,29 +8,27 @@ describe "String#unpack1" do "A".unpack1("B*").should == "01000001" end - ruby_version_is "3.1" do - it "starts unpacking from the given offset" do - "ZZABCD".unpack1('x3C', offset: 2).should == "ABCD".unpack('x3C')[0] - "ZZZZaG9nZWZ1Z2E=".unpack1("m", offset: 4).should == "hogefuga" - "ZA".unpack1("B*", offset: 1).should == "01000001" - end + it "starts unpacking from the given offset" do + "ZZABCD".unpack1('x3C', offset: 2).should == "ABCD".unpack('x3C')[0] + "ZZZZaG9nZWZ1Z2E=".unpack1("m", offset: 4).should == "hogefuga" + "ZA".unpack1("B*", offset: 1).should == "01000001" + end - it "traits offset as a bytes offset" do - "؈".unpack("CC").should == [216, 136] - "؈".unpack1("C").should == 216 - "؈".unpack1("C", offset: 1).should == 136 - end + it "traits offset as a bytes offset" do + "؈".unpack("CC").should == [216, 136] + "؈".unpack1("C").should == 216 + "؈".unpack1("C", offset: 1).should == 136 + end - it "raises an ArgumentError when the offset is negative" do - -> { "a".unpack1("C", offset: -1) }.should raise_error(ArgumentError, "offset can't be negative") - end + it "raises an ArgumentError when the offset is negative" do + -> { "a".unpack1("C", offset: -1) }.should raise_error(ArgumentError, "offset can't be negative") + end - it "returns nil if the offset is at the end of the string" do - "a".unpack1("C", offset: 1).should == nil - end + it "returns nil if the offset is at the end of the string" do + "a".unpack1("C", offset: 1).should == nil + end - it "raises an ArgumentError when the offset is larger than the string bytesize" do - -> { "a".unpack1("C", offset: 2) }.should raise_error(ArgumentError, "offset outside of string") - end + it "raises an ArgumentError when the offset is larger than the string bytesize" do + -> { "a".unpack1("C", offset: 2) }.should raise_error(ArgumentError, "offset outside of string") end end diff --git a/spec/ruby/core/string/unpack_spec.rb b/spec/ruby/core/string/unpack_spec.rb index 52b4af3a95..083484ebe9 100644 --- a/spec/ruby/core/string/unpack_spec.rb +++ b/spec/ruby/core/string/unpack_spec.rb @@ -9,26 +9,24 @@ describe "String#unpack" do -> { "abc".unpack(1) }.should raise_error(TypeError) end - ruby_version_is "3.1" do - it "starts unpacking from the given offset" do - "abc".unpack("CC", offset: 1).should == [98, 99] - end + it "starts unpacking from the given offset" do + "abc".unpack("CC", offset: 1).should == [98, 99] + end - it "traits offset as a bytes offset" do - "؈".unpack("CC").should == [216, 136] - "؈".unpack("CC", offset: 1).should == [136, nil] - end + it "traits offset as a bytes offset" do + "؈".unpack("CC").should == [216, 136] + "؈".unpack("CC", offset: 1).should == [136, nil] + end - it "raises an ArgumentError when the offset is negative" do - -> { "a".unpack("C", offset: -1) }.should raise_error(ArgumentError, "offset can't be negative") - end + it "raises an ArgumentError when the offset is negative" do + -> { "a".unpack("C", offset: -1) }.should raise_error(ArgumentError, "offset can't be negative") + end - it "returns nil if the offset is at the end of the string" do - "a".unpack("C", offset: 1).should == [nil] - end + it "returns nil if the offset is at the end of the string" do + "a".unpack("C", offset: 1).should == [nil] + end - it "raises an ArgumentError when the offset is larget than the string" do - -> { "a".unpack("C", offset: 2) }.should raise_error(ArgumentError, "offset outside of string") - end + it "raises an ArgumentError when the offset is larget than the string" do + -> { "a".unpack("C", offset: 2) }.should raise_error(ArgumentError, "offset outside of string") end end diff --git a/spec/ruby/core/struct/deconstruct_keys_spec.rb b/spec/ruby/core/struct/deconstruct_keys_spec.rb index b4c84c49df..cd05aee056 100644 --- a/spec/ruby/core/struct/deconstruct_keys_spec.rb +++ b/spec/ruby/core/struct/deconstruct_keys_spec.rb @@ -40,6 +40,14 @@ describe "Struct#deconstruct_keys" do s.deconstruct_keys([0, 1, 2]).should == {0 => 10, 1 => 20, 2 => 30} s.deconstruct_keys([0, 1] ).should == {0 => 10, 1 => 20} s.deconstruct_keys([0] ).should == {0 => 10} + s.deconstruct_keys([-1] ).should == {-1 => 30} + end + + it "support mixing attribute names and argument position numbers" do + struct = Struct.new(:x, :y) + s = struct.new(1, 2) + + s.deconstruct_keys([0, :x]).should == {0 => 1, :x => 1} end it "returns an empty hash when there are more keys than attributes" do @@ -57,6 +65,14 @@ describe "Struct#deconstruct_keys" do s.deconstruct_keys([:x, :a]).should == {x: 1} end + it "returns at first not existing argument position number" do + struct = Struct.new(:x, :y) + s = struct.new(1, 2) + + s.deconstruct_keys([3, 0]).should == {} + s.deconstruct_keys([0, 3]).should == {0 => 1} + end + it "accepts nil argument and return all the attributes" do struct = Struct.new(:x, :y) obj = struct.new(1, 2) @@ -64,6 +80,15 @@ describe "Struct#deconstruct_keys" do obj.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 + struct = Struct.new(:x, :y) + s = struct.new(1, 2) + + -> { + s.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 struct = Struct.new(:x, :y) s = struct.new(1, 2) diff --git a/spec/ruby/core/struct/fixtures/classes.rb b/spec/ruby/core/struct/fixtures/classes.rb index bf838d05df..7b80b814ef 100644 --- a/spec/ruby/core/struct/fixtures/classes.rb +++ b/spec/ruby/core/struct/fixtures/classes.rb @@ -29,4 +29,6 @@ module StructClasses super end end + + class StructSubclass < Struct; end end diff --git a/spec/ruby/core/struct/initialize_spec.rb b/spec/ruby/core/struct/initialize_spec.rb index a5ebe9551c..1861bcafb0 100644 --- a/spec/ruby/core/struct/initialize_spec.rb +++ b/spec/ruby/core/struct/initialize_spec.rb @@ -41,7 +41,7 @@ describe "Struct#initialize" do StructClasses::SubclassX.new(:y).new.key.should == :value end - ruby_version_is "3.1"..."3.2" do + ruby_version_is ""..."3.2" do it "warns about passing only keyword arguments" do -> { StructClasses::Ruby.new(version: "3.1", platform: "OS") diff --git a/spec/ruby/core/struct/keyword_init_spec.rb b/spec/ruby/core/struct/keyword_init_spec.rb index 8de4c14351..536b82041a 100644 --- a/spec/ruby/core/struct/keyword_init_spec.rb +++ b/spec/ruby/core/struct/keyword_init_spec.rb @@ -1,40 +1,45 @@ require_relative '../../spec_helper' +require_relative 'fixtures/classes' -ruby_version_is "3.1" do - # See https://bugs.ruby-lang.org/issues/18008 - describe "StructClass#keyword_init?" do - it "returns true for a struct that accepts keyword arguments to initialize" do - struct = Struct.new(:arg, keyword_init: true) - struct.keyword_init?.should be_true - end +# See https://bugs.ruby-lang.org/issues/18008 +describe "StructClass#keyword_init?" do + it "returns true for a struct that accepts keyword arguments to initialize" do + struct = Struct.new(:arg, keyword_init: true) + struct.keyword_init?.should be_true + end - it "returns false for a struct that does not accept keyword arguments to initialize" do - struct = Struct.new(:arg, keyword_init: false) - struct.keyword_init?.should be_false - end + it "returns false for a struct that does not accept keyword arguments to initialize" do + struct = Struct.new(:arg, keyword_init: false) + struct.keyword_init?.should be_false + end - it "returns nil for a struct that did not explicitly specify keyword_init" do - struct = Struct.new(:arg) - struct.keyword_init?.should be_nil - end + it "returns nil for a struct that did not explicitly specify keyword_init" do + struct = Struct.new(:arg) + struct.keyword_init?.should be_nil + end - it "returns nil for a struct that does specify keyword_init to be nil" do - struct = Struct.new(:arg, keyword_init: nil) - struct.keyword_init?.should be_nil - end + it "returns nil for a struct that does specify keyword_init to be nil" do + struct = Struct.new(:arg, keyword_init: nil) + struct.keyword_init?.should be_nil + end - it "returns true for any truthy value, not just for true" do - struct = Struct.new(:arg, keyword_init: 1) - struct.keyword_init?.should be_true + it "returns true for any truthy value, not just for true" do + struct = Struct.new(:arg, keyword_init: 1) + struct.keyword_init?.should be_true - struct = Struct.new(:arg, keyword_init: "") - struct.keyword_init?.should be_true + struct = Struct.new(:arg, keyword_init: "") + struct.keyword_init?.should be_true - struct = Struct.new(:arg, keyword_init: []) - struct.keyword_init?.should be_true + struct = Struct.new(:arg, keyword_init: []) + struct.keyword_init?.should be_true + + struct = Struct.new(:arg, keyword_init: {}) + struct.keyword_init?.should be_true + end - struct = Struct.new(:arg, keyword_init: {}) - struct.keyword_init?.should be_true + context "class inheriting Struct" do + it "isn't available in a subclass" do + StructClasses::StructSubclass.should_not.respond_to?(:keyword_init?) end end end diff --git a/spec/ruby/core/struct/members_spec.rb b/spec/ruby/core/struct/members_spec.rb index 1f2ff950d9..1ff7b9387a 100644 --- a/spec/ruby/core/struct/members_spec.rb +++ b/spec/ruby/core/struct/members_spec.rb @@ -11,3 +11,15 @@ describe "Struct#members" do it_behaves_like :struct_accessor, :members end + +describe "StructClass#members" do + it "returns an array of attribute names" do + StructClasses::Car.members.should == [:make, :model, :year] + end + + context "class inheriting Struct" do + it "isn't available in a subclass" do + StructClasses::StructSubclass.should_not.respond_to?(:members) + end + end +end diff --git a/spec/ruby/core/struct/new_spec.rb b/spec/ruby/core/struct/new_spec.rb index a94eb852e1..73e88a81c1 100644 --- a/spec/ruby/core/struct/new_spec.rb +++ b/spec/ruby/core/struct/new_spec.rb @@ -6,6 +6,8 @@ describe "Struct.new" do struct = Struct.new('Animal', :name, :legs, :eyeballs) struct.should == Struct::Animal struct.name.should == "Struct::Animal" + ensure + Struct.send(:remove_const, :Animal) end it "overwrites previously defined constants with string as first argument" do @@ -19,6 +21,8 @@ describe "Struct.new" do second.should == Struct::Person first.members.should_not == second.members + ensure + Struct.send(:remove_const, :Person) end it "calls to_str on its first argument (constant name)" do @@ -27,6 +31,8 @@ describe "Struct.new" do struct = Struct.new(obj) struct.should == Struct::Foo struct.name.should == "Struct::Foo" + ensure + Struct.send(:remove_const, :Foo) end it "creates a new anonymous class with nil first argument" do @@ -138,6 +144,8 @@ describe "Struct.new" do it "creates a constant in subclass' namespace" do struct = StructClasses::Apple.new('Computer', :size) struct.should == StructClasses::Apple::Computer + ensure + StructClasses::Apple.send(:remove_const, :Computer) end it "creates an instance" do @@ -158,19 +166,6 @@ describe "Struct.new" do -> { StructClasses::Ruby.new('2.0', 'i686', true) }.should raise_error(ArgumentError) end - ruby_version_is ''...'3.1' do - it "passes a hash as a normal argument" do - type = Struct.new(:args) - - obj = suppress_warning {type.new(keyword: :arg)} - obj2 = type.new(*[{keyword: :arg}]) - - obj.should == obj2 - obj.args.should == {keyword: :arg} - obj2.args.should == {keyword: :arg} - end - end - ruby_version_is '3.2' do it "accepts keyword arguments to initialize" do type = Struct.new(:args) diff --git a/spec/ruby/core/symbol/shared/slice.rb b/spec/ruby/core/symbol/shared/slice.rb index 0df87e183d..d3d4aad617 100644 --- a/spec/ruby/core/symbol/shared/slice.rb +++ b/spec/ruby/core/symbol/shared/slice.rb @@ -7,7 +7,7 @@ describe :symbol_slice, shared: true do end it "returns nil if the index starts from the end and is greater than the length" do - :symbol.send(@method, -10).should be_nil + :symbol.send(@method, -10).should be_nil end it "returns nil if the index is greater than the length" do diff --git a/spec/ruby/core/thread/abort_on_exception_spec.rb b/spec/ruby/core/thread/abort_on_exception_spec.rb index 34b648ca0f..49be84ea9f 100644 --- a/spec/ruby/core/thread/abort_on_exception_spec.rb +++ b/spec/ruby/core/thread/abort_on_exception_spec.rb @@ -72,7 +72,7 @@ describe "Thread.abort_on_exception" do end after do - Thread.abort_on_exception = @abort_on_exception + Thread.abort_on_exception = @abort_on_exception end it "is false by default" do diff --git a/spec/ruby/core/thread/backtrace/limit_spec.rb b/spec/ruby/core/thread/backtrace/limit_spec.rb index 26a87a806c..b55ca67ea0 100644 --- a/spec/ruby/core/thread/backtrace/limit_spec.rb +++ b/spec/ruby/core/thread/backtrace/limit_spec.rb @@ -1,15 +1,13 @@ require_relative '../../../spec_helper' -ruby_version_is "3.1" do - describe "Thread::Backtrace.limit" do - it "returns maximum backtrace length set by --backtrace-limit command-line option" do - out = ruby_exe("print Thread::Backtrace.limit", options: "--backtrace-limit=2") - out.should == "2" - end +describe "Thread::Backtrace.limit" do + it "returns maximum backtrace length set by --backtrace-limit command-line option" do + out = ruby_exe("print Thread::Backtrace.limit", options: "--backtrace-limit=2") + out.should == "2" + end - it "returns -1 when --backtrace-limit command-line option is not set" do - out = ruby_exe("print Thread::Backtrace.limit") - out.should == "-1" - end + it "returns -1 when --backtrace-limit command-line option is not set" do + out = ruby_exe("print Thread::Backtrace.limit") + out.should == "-1" end end diff --git a/spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb b/spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb index 6e381e4868..68a69049d9 100644 --- a/spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb +++ b/spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb @@ -27,20 +27,11 @@ describe 'Thread::Backtrace::Location#absolute_path' do end context "when used in eval with a given filename" do - code = "caller_locations(0)[0].absolute_path" + it "returns nil with absolute_path" do + code = "caller_locations(0)[0].absolute_path" - ruby_version_is ""..."3.1" do - it "returns filename with absolute_path" do - eval(code, nil, "foo.rb").should == "foo.rb" - eval(code, nil, "foo/bar.rb").should == "foo/bar.rb" - end - end - - ruby_version_is "3.1" do - it "returns nil with absolute_path" do - eval(code, nil, "foo.rb").should == nil - eval(code, nil, "foo/bar.rb").should == nil - end + eval(code, nil, "foo.rb").should == nil + eval(code, nil, "foo/bar.rb").should == nil end end diff --git a/spec/ruby/core/thread/native_thread_id_spec.rb b/spec/ruby/core/thread/native_thread_id_spec.rb index 17a08c8a15..374cc59279 100644 --- a/spec/ruby/core/thread/native_thread_id_spec.rb +++ b/spec/ruby/core/thread/native_thread_id_spec.rb @@ -1,37 +1,35 @@ require_relative '../../spec_helper' -ruby_version_is "3.1" do - platform_is :linux, :darwin, :windows, :freebsd do - describe "Thread#native_thread_id" do - it "returns an integer when the thread is alive" do - Thread.current.native_thread_id.should be_kind_of(Integer) - end +platform_is :linux, :darwin, :windows, :freebsd do + describe "Thread#native_thread_id" do + it "returns an integer when the thread is alive" do + Thread.current.native_thread_id.should be_kind_of(Integer) + end - it "returns nil when the thread is not running" do - t = Thread.new {} - t.join - t.native_thread_id.should == nil - end + it "returns nil when the thread is not running" do + t = Thread.new {} + t.join + t.native_thread_id.should == nil + end - it "each thread has different native thread id" do - t = Thread.new { sleep } - Thread.pass until t.stop? - main_thread_id = Thread.current.native_thread_id - t_thread_id = t.native_thread_id + it "each thread has different native thread id" do + t = Thread.new { sleep } + Thread.pass until t.stop? + main_thread_id = Thread.current.native_thread_id + t_thread_id = t.native_thread_id - if ruby_version_is "3.3" - # native_thread_id can be nil on a M:N scheduler - t_thread_id.should be_kind_of(Integer) if t_thread_id != nil - else - t_thread_id.should be_kind_of(Integer) - end + if ruby_version_is "3.3" + # native_thread_id can be nil on a M:N scheduler + t_thread_id.should be_kind_of(Integer) if t_thread_id != nil + else + t_thread_id.should be_kind_of(Integer) + end - main_thread_id.should_not == t_thread_id + main_thread_id.should_not == t_thread_id - t.run - t.join - t.native_thread_id.should == nil - end + t.run + t.join + t.native_thread_id.should == nil end end end diff --git a/spec/ruby/core/time/at_spec.rb b/spec/ruby/core/time/at_spec.rb index 85bb6d7ebf..97906b8c8c 100644 --- a/spec/ruby/core/time/at_spec.rb +++ b/spec/ruby/core/time/at_spec.rb @@ -102,8 +102,8 @@ describe "Time.at" do it "needs for the argument to respond to #to_int too" do o = mock('rational-but-no-to_int') - o.should_receive(:to_r).and_return(Rational(5, 2)) - -> { Time.at(o) }.should raise_error(TypeError) + def o.to_r; Rational(5, 2) end + -> { Time.at(o) }.should raise_error(TypeError, "can't convert MockObject into an exact number") end end end @@ -288,39 +288,19 @@ describe "Time.at" do end it "raises ArgumentError if hours greater than 23" do # TODO - ruby_version_is ""..."3.1" do - -> { Time.at(@epoch_time, in: "+24:00") }.should raise_error(ArgumentError, 'utc_offset out of range') - -> { Time.at(@epoch_time, in: "+2400") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset') - - -> { Time.at(@epoch_time, in: "+99:00") }.should raise_error(ArgumentError, 'utc_offset out of range') - -> { Time.at(@epoch_time, in: "+9900") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset') - end + -> { Time.at(@epoch_time, in: "+24:00") }.should raise_error(ArgumentError, "utc_offset out of range") + -> { Time.at(@epoch_time, in: "+2400") }.should raise_error(ArgumentError, "utc_offset out of range") - ruby_version_is "3.1" do - -> { Time.at(@epoch_time, in: "+24:00") }.should raise_error(ArgumentError, "utc_offset out of range") - -> { Time.at(@epoch_time, in: "+2400") }.should raise_error(ArgumentError, "utc_offset out of range") - - -> { Time.at(@epoch_time, in: "+99:00") }.should raise_error(ArgumentError, "utc_offset out of range") - -> { Time.at(@epoch_time, in: "+9900") }.should raise_error(ArgumentError, "utc_offset out of range") - end + -> { Time.at(@epoch_time, in: "+99:00") }.should raise_error(ArgumentError, "utc_offset out of range") + -> { Time.at(@epoch_time, in: "+9900") }.should raise_error(ArgumentError, "utc_offset out of range") end it "raises ArgumentError if minutes greater than 59" do # TODO - ruby_version_is ""..."3.1" do - -> { Time.at(@epoch_time, in: "+00:60") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset') - -> { Time.at(@epoch_time, in: "+0060") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset') + -> { Time.at(@epoch_time, in: "+00:60") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:60') + -> { Time.at(@epoch_time, in: "+0060") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0060') - -> { Time.at(@epoch_time, in: "+00:99") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset') - -> { Time.at(@epoch_time, in: "+0099") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset') - end - - ruby_version_is "3.1" do - -> { Time.at(@epoch_time, in: "+00:60") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:60') - -> { Time.at(@epoch_time, in: "+0060") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0060') - - -> { Time.at(@epoch_time, in: "+00:99") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:99') - -> { Time.at(@epoch_time, in: "+0099") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0099') - end + -> { Time.at(@epoch_time, in: "+00:99") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:99') + -> { Time.at(@epoch_time, in: "+0099") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0099') end ruby_bug '#20797', ''...'3.4' do diff --git a/spec/ruby/core/time/getlocal_spec.rb b/spec/ruby/core/time/getlocal_spec.rb index ff3e3d8dd1..398596f400 100644 --- a/spec/ruby/core/time/getlocal_spec.rb +++ b/spec/ruby/core/time/getlocal_spec.rb @@ -14,6 +14,7 @@ describe "Time#getlocal" do t = Time.gm(2007, 1, 9, 12, 0, 0).getlocal(3630) t.should == Time.new(2007, 1, 9, 13, 0, 30, 3630) t.utc_offset.should == 3630 + t.zone.should be_nil end platform_is_not :windows do @@ -110,39 +111,19 @@ describe "Time#getlocal" do end it "raises ArgumentError if String argument and hours greater than 23" do - ruby_version_is ""..."3.1" do - -> { Time.now.getlocal("+24:00") }.should raise_error(ArgumentError, "utc_offset out of range") - -> { Time.now.getlocal("+2400") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset') + -> { Time.now.getlocal("+24:00") }.should raise_error(ArgumentError, "utc_offset out of range") + -> { Time.now.getlocal("+2400") }.should raise_error(ArgumentError, "utc_offset out of range") - -> { Time.now.getlocal("+99:00") }.should raise_error(ArgumentError, "utc_offset out of range") - -> { Time.now.getlocal("+9900") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset') - end - - ruby_version_is "3.1" do - -> { Time.now.getlocal("+24:00") }.should raise_error(ArgumentError, "utc_offset out of range") - -> { Time.now.getlocal("+2400") }.should raise_error(ArgumentError, "utc_offset out of range") - - -> { Time.now.getlocal("+99:00") }.should raise_error(ArgumentError, "utc_offset out of range") - -> { Time.now.getlocal("+9900") }.should raise_error(ArgumentError, "utc_offset out of range") - end + -> { Time.now.getlocal("+99:00") }.should raise_error(ArgumentError, "utc_offset out of range") + -> { Time.now.getlocal("+9900") }.should raise_error(ArgumentError, "utc_offset out of range") end it "raises ArgumentError if String argument and minutes greater than 59" do - ruby_version_is ""..."3.1" do - -> { Time.now.getlocal("+00:60") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset') - -> { Time.now.getlocal("+0060") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset') + -> { Time.now.getlocal("+00:60") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:60') + -> { Time.now.getlocal("+0060") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0060') - -> { Time.now.getlocal("+00:99") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset') - -> { Time.now.getlocal("+0099") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset') - end - - ruby_version_is "3.1" do - -> { Time.now.getlocal("+00:60") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:60') - -> { Time.now.getlocal("+0060") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0060') - - -> { Time.now.getlocal("+00:99") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:99') - -> { Time.now.getlocal("+0099") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0099') - end + -> { Time.now.getlocal("+00:99") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:99') + -> { Time.now.getlocal("+0099") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0099') end ruby_bug '#20797', ''...'3.4' do diff --git a/spec/ruby/core/time/localtime_spec.rb b/spec/ruby/core/time/localtime_spec.rb index 5badba9fb2..71c0dfebde 100644 --- a/spec/ruby/core/time/localtime_spec.rb +++ b/spec/ruby/core/time/localtime_spec.rb @@ -106,39 +106,19 @@ describe "Time#localtime" do end it "raises ArgumentError if String argument and hours greater than 23" do - ruby_version_is ""..."3.1" do - -> { Time.now.localtime("+24:00") }.should raise_error(ArgumentError, "utc_offset out of range") - -> { Time.now.localtime("+2400") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset') + -> { Time.now.localtime("+24:00") }.should raise_error(ArgumentError, "utc_offset out of range") + -> { Time.now.localtime("+2400") }.should raise_error(ArgumentError, "utc_offset out of range") - -> { Time.now.localtime("+99:00") }.should raise_error(ArgumentError, "utc_offset out of range") - -> { Time.now.localtime("+9900") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset') - end - - ruby_version_is "3.1" do - -> { Time.now.localtime("+24:00") }.should raise_error(ArgumentError, "utc_offset out of range") - -> { Time.now.localtime("+2400") }.should raise_error(ArgumentError, "utc_offset out of range") - - -> { Time.now.localtime("+99:00") }.should raise_error(ArgumentError, "utc_offset out of range") - -> { Time.now.localtime("+9900") }.should raise_error(ArgumentError, "utc_offset out of range") - end + -> { Time.now.localtime("+99:00") }.should raise_error(ArgumentError, "utc_offset out of range") + -> { Time.now.localtime("+9900") }.should raise_error(ArgumentError, "utc_offset out of range") end it "raises ArgumentError if String argument and minutes greater than 59" do - ruby_version_is ""..."3.1" do - -> { Time.now.localtime("+00:60") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset') - -> { Time.now.localtime("+0060") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset') + -> { Time.now.localtime("+00:60") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:60') + -> { Time.now.localtime("+0060") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0060') - -> { Time.now.localtime("+00:99") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset') - -> { Time.now.localtime("+0099") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset') - end - - ruby_version_is "3.1" do - -> { Time.now.localtime("+00:60") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:60') - -> { Time.now.localtime("+0060") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0060') - - -> { Time.now.localtime("+00:99") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:99') - -> { Time.now.localtime("+0099") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0099') - end + -> { Time.now.localtime("+00:99") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:99') + -> { Time.now.localtime("+0099") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0099') end ruby_bug '#20797', ''...'3.4' do @@ -188,6 +168,17 @@ describe "Time#localtime" do end end + describe "with an argument that responds to #utc_to_local" do + it "coerces using #utc_to_local" do + o = mock('string') + o.should_receive(:utc_to_local).and_return(Time.new(2007, 1, 9, 13, 0, 0, 3600)) + t = Time.gm(2007, 1, 9, 12, 0, 0) + t.localtime(o) + t.should == Time.new(2007, 1, 9, 13, 0, 0, 3600) + t.utc_offset.should == 3600 + end + end + it "raises ArgumentError if the String argument is not of the form (+|-)HH:MM" do t = Time.now -> { t.localtime("3600") }.should raise_error(ArgumentError) diff --git a/spec/ruby/core/time/new_spec.rb b/spec/ruby/core/time/new_spec.rb index 1a743b485e..0fd48640d4 100644 --- a/spec/ruby/core/time/new_spec.rb +++ b/spec/ruby/core/time/new_spec.rb @@ -58,30 +58,28 @@ describe "Time.new with a utc_offset argument" do Time.new(2000, 1, 1, 0, 0, 0, "-04:10:43").utc_offset.should == -15043 end - ruby_bug '#13669', ''...'3.1' do - it "returns a Time with a UTC offset specified as +HH" do - Time.new(2000, 1, 1, 0, 0, 0, "+05").utc_offset.should == 3600 * 5 - end + it "returns a Time with a UTC offset specified as +HH" do + Time.new(2000, 1, 1, 0, 0, 0, "+05").utc_offset.should == 3600 * 5 + end - it "returns a Time with a UTC offset specified as -HH" do - Time.new(2000, 1, 1, 0, 0, 0, "-05").utc_offset.should == -3600 * 5 - end + it "returns a Time with a UTC offset specified as -HH" do + Time.new(2000, 1, 1, 0, 0, 0, "-05").utc_offset.should == -3600 * 5 + end - it "returns a Time with a UTC offset specified as +HHMM" do - Time.new(2000, 1, 1, 0, 0, 0, "+0530").utc_offset.should == 19800 - end + it "returns a Time with a UTC offset specified as +HHMM" do + Time.new(2000, 1, 1, 0, 0, 0, "+0530").utc_offset.should == 19800 + end - it "returns a Time with a UTC offset specified as -HHMM" do - Time.new(2000, 1, 1, 0, 0, 0, "-0530").utc_offset.should == -19800 - end + it "returns a Time with a UTC offset specified as -HHMM" do + Time.new(2000, 1, 1, 0, 0, 0, "-0530").utc_offset.should == -19800 + end - it "returns a Time with a UTC offset specified as +HHMMSS" do - Time.new(2000, 1, 1, 0, 0, 0, "+053037").utc_offset.should == 19837 - end + it "returns a Time with a UTC offset specified as +HHMMSS" do + Time.new(2000, 1, 1, 0, 0, 0, "+053037").utc_offset.should == 19837 + end - it "returns a Time with a UTC offset specified as -HHMMSS" do - Time.new(2000, 1, 1, 0, 0, 0, "-053037").utc_offset.should == -19837 - end + it "returns a Time with a UTC offset specified as -HHMMSS" do + Time.new(2000, 1, 1, 0, 0, 0, "-053037").utc_offset.should == -19837 end describe "with an argument that responds to #to_str" do @@ -129,18 +127,9 @@ describe "Time.new with a utc_offset argument" do end end - ruby_version_is ""..."3.1" do - it "raises ArgumentError if the string argument is J" do - message = '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset' - -> { Time.new(2000, 1, 1, 0, 0, 0, "J") }.should raise_error(ArgumentError, message) - end - end - - ruby_version_is "3.1" do - it "raises ArgumentError if the string argument is J" do - message = '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: J' - -> { Time.new(2000, 1, 1, 0, 0, 0, "J") }.should raise_error(ArgumentError, message) - end + it "raises ArgumentError if the string argument is J" do + message = '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: J' + -> { Time.new(2000, 1, 1, 0, 0, 0, "J") }.should raise_error(ArgumentError, message) end it "returns a local Time if the argument is nil" do @@ -193,6 +182,7 @@ describe "Time.new with a utc_offset argument" do end end +# The method #local_to_utc is tested only here because Time.new is the only method that calls #local_to_utc. describe "Time.new with a timezone argument" do it "returns a Time in the timezone" do zone = TimeSpecs::Timezone.new(offset: (5*3600+30*60)) @@ -213,9 +203,7 @@ describe "Time.new with a timezone argument" do time end - -> { - Time.new(2000, 1, 1, 12, 0, 0, zone).should be_kind_of(Time) - }.should_not raise_error + Time.new(2000, 1, 1, 12, 0, 0, zone).should be_kind_of(Time) end it "raises TypeError if timezone does not implement #local_to_utc method" do @@ -226,7 +214,7 @@ describe "Time.new with a timezone argument" do -> { Time.new(2000, 1, 1, 12, 0, 0, zone) - }.should raise_error(TypeError, /can't convert \w+ into an exact number/) + }.should raise_error(TypeError, /can't convert Object into an exact number/) end it "does not raise exception if timezone does not implement #utc_to_local method" do @@ -235,51 +223,48 @@ describe "Time.new with a timezone argument" do time end - -> { - Time.new(2000, 1, 1, 12, 0, 0, zone).should be_kind_of(Time) - }.should_not raise_error + Time.new(2000, 1, 1, 12, 0, 0, zone).should be_kind_of(Time) end # The result also should be a Time or Time-like object (not necessary to be the same class) - # The zone of the result is just ignored + # or respond to #to_int method. The zone of the result is just ignored. describe "returned value by #utc_to_local and #local_to_utc methods" do it "could be Time instance" do zone = Object.new def zone.local_to_utc(t) - Time.utc(t.year, t.mon, t.day, t.hour - 1, t.min, t.sec) + time = Time.utc(t.year, t.mon, t.day, t.hour, t.min, t.sec) + time - 60 * 60 # - 1 hour end - -> { - Time.new(2000, 1, 1, 12, 0, 0, zone).should be_kind_of(Time) - Time.new(2000, 1, 1, 12, 0, 0, zone).utc_offset.should == 60*60 - }.should_not raise_error + Time.new(2000, 1, 1, 12, 0, 0, zone).should be_kind_of(Time) + Time.new(2000, 1, 1, 12, 0, 0, zone).utc_offset.should == 60*60 end it "could be Time subclass instance" do zone = Object.new def zone.local_to_utc(t) - Class.new(Time).utc(t.year, t.mon, t.day, t.hour - 1, t.min, t.sec) + time = Time.utc(t.year, t.mon, t.day, t.hour, t.min, t.sec) + time -= 60 * 60 # - 1 hour + Class.new(Time).utc(time.year, time.mon, time.day, time.hour, t.min, t.sec) end - -> { - Time.new(2000, 1, 1, 12, 0, 0, zone).should be_kind_of(Time) - Time.new(2000, 1, 1, 12, 0, 0, zone).utc_offset.should == 60*60 - }.should_not raise_error + Time.new(2000, 1, 1, 12, 0, 0, zone).should be_kind_of(Time) + Time.new(2000, 1, 1, 12, 0, 0, zone).utc_offset.should == 60*60 end it "could be any object with #to_i method" do zone = Object.new def zone.local_to_utc(time) - Struct.new(:to_i).new(time.to_i - 60*60) + obj = Object.new + obj.singleton_class.define_method(:to_i) { time.to_i - 60*60 } + obj end - -> { - Time.new(2000, 1, 1, 12, 0, 0, zone).should be_kind_of(Time) - Time.new(2000, 1, 1, 12, 0, 0, zone).utc_offset.should == 60*60 - }.should_not raise_error + Time.new(2000, 1, 1, 12, 0, 0, zone).should be_kind_of(Time) + Time.new(2000, 1, 1, 12, 0, 0, zone).utc_offset.should == 60*60 end - it "could have any #zone and #utc_offset because they are ignored" do + it "could have any #zone and #utc_offset because they are ignored if it isn't an instance of Time" do zone = Object.new def zone.local_to_utc(time) Struct.new(:to_i, :zone, :utc_offset).new(time.to_i, 'America/New_York', -5*60*60) @@ -293,7 +278,15 @@ describe "Time.new with a timezone argument" do Time.new(2000, 1, 1, 12, 0, 0, zone).utc_offset.should == 0 end - it "leads to raising Argument error if difference between argument and result is too large" do + it "cannot have arbitrary #utc_offset if it is an instance of Time" do + zone = Object.new + def zone.local_to_utc(t) + Time.new(t.year, t.mon, t.mday, t.hour, t.min, t.sec, 9*60*60) + end + Time.new(2000, 1, 1, 12, 0, 0, zone).utc_offset.should == 9*60*60 + end + + it "raises ArgumentError if difference between argument and result is too large" do zone = Object.new def zone.local_to_utc(t) Time.utc(t.year, t.mon, t.day + 1, t.hour, t.min, t.sec) @@ -318,12 +311,9 @@ describe "Time.new with a timezone argument" do end it "implements subset of Time methods" do + # List only methods that are explicitly documented. [ - :year, :mon, :month, :mday, :hour, :min, :sec, - :tv_sec, :tv_usec, :usec, :tv_nsec, :nsec, :subsec, - :to_i, :to_f, :to_r, :+, :-, - :isdst, :dst?, :zone, :gmtoff, :gmt_offset, :utc_offset, :utc?, :gmt?, - :to_s, :inspect, :to_a, :to_time, + :year, :mon, :mday, :hour, :min, :sec, :to_i, :isdst ].each do |name| @obj.respond_to?(name).should == true end @@ -403,79 +393,77 @@ describe "Time.new with a timezone argument" do end end - ruby_version_is '3.1' do # https://bugs.ruby-lang.org/issues/17485 - describe ":in keyword argument" do - it "could be UTC offset as a String in '+HH:MM or '-HH:MM' format" do - time = Time.new(2000, 1, 1, 12, 0, 0, in: "+05:00") + describe ":in keyword argument" do + it "could be UTC offset as a String in '+HH:MM or '-HH:MM' format" do + time = Time.new(2000, 1, 1, 12, 0, 0, in: "+05:00") - time.utc_offset.should == 5*60*60 - time.zone.should == nil + time.utc_offset.should == 5*60*60 + time.zone.should == nil - time = Time.new(2000, 1, 1, 12, 0, 0, in: "-09:00") + time = Time.new(2000, 1, 1, 12, 0, 0, in: "-09:00") - time.utc_offset.should == -9*60*60 - time.zone.should == nil + time.utc_offset.should == -9*60*60 + time.zone.should == nil - time = Time.new(2000, 1, 1, 12, 0, 0, in: "-09:00:01") + time = Time.new(2000, 1, 1, 12, 0, 0, in: "-09:00:01") - time.utc_offset.should == -(9*60*60 + 1) - time.zone.should == nil - end + time.utc_offset.should == -(9*60*60 + 1) + time.zone.should == nil + end - it "could be UTC offset as a number of seconds" do - time = Time.new(2000, 1, 1, 12, 0, 0, in: 5*60*60) + it "could be UTC offset as a number of seconds" do + time = Time.new(2000, 1, 1, 12, 0, 0, in: 5*60*60) - time.utc_offset.should == 5*60*60 - time.zone.should == nil + time.utc_offset.should == 5*60*60 + time.zone.should == nil - time = Time.new(2000, 1, 1, 12, 0, 0, in: -9*60*60) + time = Time.new(2000, 1, 1, 12, 0, 0, in: -9*60*60) - time.utc_offset.should == -9*60*60 - time.zone.should == nil - end + time.utc_offset.should == -9*60*60 + time.zone.should == nil + end - it "returns a Time with UTC offset specified as a single letter military timezone" do - Time.new(2000, 1, 1, 0, 0, 0, in: "W").utc_offset.should == 3600 * -10 - end + it "returns a Time with UTC offset specified as a single letter military timezone" do + Time.new(2000, 1, 1, 0, 0, 0, in: "W").utc_offset.should == 3600 * -10 + end - it "could be a timezone object" do - zone = TimeSpecs::TimezoneWithName.new(name: "Asia/Colombo") - time = Time.new(2000, 1, 1, 12, 0, 0, in: zone) + it "could be a timezone object" do + zone = TimeSpecs::TimezoneWithName.new(name: "Asia/Colombo") + time = Time.new(2000, 1, 1, 12, 0, 0, in: zone) - time.utc_offset.should == 5*3600+30*60 - time.zone.should == zone + time.utc_offset.should == 5*3600+30*60 + time.zone.should == zone - zone = TimeSpecs::TimezoneWithName.new(name: "PST") - time = Time.new(2000, 1, 1, 12, 0, 0, in: zone) + zone = TimeSpecs::TimezoneWithName.new(name: "PST") + time = Time.new(2000, 1, 1, 12, 0, 0, in: zone) - time.utc_offset.should == -9*60*60 - time.zone.should == zone - end + time.utc_offset.should == -9*60*60 + time.zone.should == zone + end - it "allows omitting minor arguments" do - Time.new(2000, 1, 1, 12, 1, 1, in: "+05:00").should == Time.new(2000, 1, 1, 12, 1, 1, "+05:00") - Time.new(2000, 1, 1, 12, 1, in: "+05:00").should == Time.new(2000, 1, 1, 12, 1, 0, "+05:00") - Time.new(2000, 1, 1, 12, in: "+05:00").should == Time.new(2000, 1, 1, 12, 0, 0, "+05:00") - Time.new(2000, 1, 1, in: "+05:00").should == Time.new(2000, 1, 1, 0, 0, 0, "+05:00") - Time.new(2000, 1, in: "+05:00").should == Time.new(2000, 1, 1, 0, 0, 0, "+05:00") - Time.new(2000, in: "+05:00").should == Time.new(2000, 1, 1, 0, 0, 0, "+05:00") - Time.new(in: "+05:00").should be_close(Time.now.getlocal("+05:00"), TIME_TOLERANCE) - end + it "allows omitting minor arguments" do + Time.new(2000, 1, 1, 12, 1, 1, in: "+05:00").should == Time.new(2000, 1, 1, 12, 1, 1, "+05:00") + Time.new(2000, 1, 1, 12, 1, in: "+05:00").should == Time.new(2000, 1, 1, 12, 1, 0, "+05:00") + Time.new(2000, 1, 1, 12, in: "+05:00").should == Time.new(2000, 1, 1, 12, 0, 0, "+05:00") + Time.new(2000, 1, 1, in: "+05:00").should == Time.new(2000, 1, 1, 0, 0, 0, "+05:00") + Time.new(2000, 1, in: "+05:00").should == Time.new(2000, 1, 1, 0, 0, 0, "+05:00") + Time.new(2000, in: "+05:00").should == Time.new(2000, 1, 1, 0, 0, 0, "+05:00") + Time.new(in: "+05:00").should be_close(Time.now.getlocal("+05:00"), TIME_TOLERANCE) + end - it "converts to a provided timezone if all the positional arguments are omitted" do - Time.new(in: "+05:00").utc_offset.should == 5*3600 - end + it "converts to a provided timezone if all the positional arguments are omitted" do + Time.new(in: "+05:00").utc_offset.should == 5*3600 + end - it "raises ArgumentError if format is invalid" do - -> { Time.new(2000, 1, 1, 12, 0, 0, in: "+09:99") }.should raise_error(ArgumentError) - -> { Time.new(2000, 1, 1, 12, 0, 0, in: "ABC") }.should raise_error(ArgumentError) - end + it "raises ArgumentError if format is invalid" do + -> { Time.new(2000, 1, 1, 12, 0, 0, in: "+09:99") }.should raise_error(ArgumentError) + -> { Time.new(2000, 1, 1, 12, 0, 0, in: "ABC") }.should raise_error(ArgumentError) + end - it "raises ArgumentError if two offset arguments are given" do - -> { - Time.new(2000, 1, 1, 12, 0, 0, "+05:00", in: "+05:00") - }.should raise_error(ArgumentError, "timezone argument given as positional and keyword arguments") - end + it "raises ArgumentError if two offset arguments are given" do + -> { + Time.new(2000, 1, 1, 12, 0, 0, "+05:00", in: "+05:00") + }.should raise_error(ArgumentError, "timezone argument given as positional and keyword arguments") end end diff --git a/spec/ruby/core/time/now_spec.rb b/spec/ruby/core/time/now_spec.rb index 7c2425411a..f19e015461 100644 --- a/spec/ruby/core/time/now_spec.rb +++ b/spec/ruby/core/time/now_spec.rb @@ -4,83 +4,178 @@ require_relative 'shared/now' describe "Time.now" do it_behaves_like :time_now, :now - ruby_version_is '3.1' do # https://bugs.ruby-lang.org/issues/17485 - describe ":in keyword argument" do - it "could be UTC offset as a String in '+HH:MM or '-HH:MM' format" do - time = Time.now(in: "+05:00") + describe ":in keyword argument" do + it "could be UTC offset as a String in '+HH:MM or '-HH:MM' format" do + time = Time.now(in: "+05:00") - time.utc_offset.should == 5*60*60 - time.zone.should == nil + time.utc_offset.should == 5*60*60 + time.zone.should == nil - time = Time.now(in: "-09:00") + time = Time.now(in: "-09:00") - time.utc_offset.should == -9*60*60 - time.zone.should == nil + time.utc_offset.should == -9*60*60 + time.zone.should == nil - time = Time.now(in: "-09:00:01") + time = Time.now(in: "-09:00:01") - time.utc_offset.should == -(9*60*60 + 1) - time.zone.should == nil - end + time.utc_offset.should == -(9*60*60 + 1) + time.zone.should == nil + end - it "could be UTC offset as a number of seconds" do - time = Time.now(in: 5*60*60) + it "could be UTC offset as a number of seconds" do + time = Time.now(in: 5*60*60) - time.utc_offset.should == 5*60*60 - time.zone.should == nil + time.utc_offset.should == 5*60*60 + time.zone.should == nil - time = Time.now(in: -9*60*60) + time = Time.now(in: -9*60*60) - time.utc_offset.should == -9*60*60 - time.zone.should == nil - end + time.utc_offset.should == -9*60*60 + time.zone.should == nil + end - it "returns a Time with UTC offset specified as a single letter military timezone" do - Time.now(in: "W").utc_offset.should == 3600 * -10 - end + it "returns a Time with UTC offset specified as a single letter military timezone" do + Time.now(in: "W").utc_offset.should == 3600 * -10 + end - it "could be a timezone object" do - zone = TimeSpecs::TimezoneWithName.new(name: "Asia/Colombo") - time = Time.now(in: zone) + it "could be a timezone object" do + zone = TimeSpecs::TimezoneWithName.new(name: "Asia/Colombo") + time = Time.now(in: zone) - time.utc_offset.should == 5*3600+30*60 - time.zone.should == zone + time.utc_offset.should == 5*3600+30*60 + time.zone.should == zone - zone = TimeSpecs::TimezoneWithName.new(name: "PST") - time = Time.now(in: zone) + zone = TimeSpecs::TimezoneWithName.new(name: "PST") + time = Time.now(in: zone) - time.utc_offset.should == -9*60*60 - time.zone.should == zone - end + time.utc_offset.should == -9*60*60 + time.zone.should == zone + end + + it "raises ArgumentError if format is invalid" do + -> { Time.now(in: "+09:99") }.should raise_error(ArgumentError) + -> { Time.now(in: "ABC") }.should raise_error(ArgumentError) + end + + it "raises ArgumentError if String argument and hours greater than 23" do + -> { Time.now(in: "+24:00") }.should raise_error(ArgumentError, "utc_offset out of range") + -> { Time.now(in: "+2400") }.should raise_error(ArgumentError, "utc_offset out of range") + + -> { Time.now(in: "+99:00") }.should raise_error(ArgumentError, "utc_offset out of range") + -> { Time.now(in: "+9900") }.should raise_error(ArgumentError, "utc_offset out of range") + end + + it "raises ArgumentError if String argument and minutes greater than 59" do + -> { Time.now(in: "+00:60") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:60') + -> { Time.now(in: "+0060") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0060') + + -> { Time.now(in: "+00:99") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:99') + -> { Time.now(in: "+0099") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0099') + end - it "raises ArgumentError if format is invalid" do - -> { Time.now(in: "+09:99") }.should raise_error(ArgumentError) - -> { Time.now(in: "ABC") }.should raise_error(ArgumentError) + ruby_bug '#20797', ''...'3.4' do + it "raises ArgumentError if String argument and seconds greater than 59" do + -> { Time.now(in: "+00:00:60") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:60') + -> { Time.now(in: "+000060") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000060') + + -> { Time.now(in: "+00:00:99") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:99') + -> { Time.now(in: "+000099") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000099') end + end + end - it "raises ArgumentError if String argument and hours greater than 23" do - -> { Time.now(in: "+24:00") }.should raise_error(ArgumentError, "utc_offset out of range") - -> { Time.now(in: "+2400") }.should raise_error(ArgumentError, "utc_offset out of range") + ruby_version_is '3.1' do # https://bugs.ruby-lang.org/issues/17485 + describe "Timezone object" do + it "raises TypeError if timezone does not implement #utc_to_local method" do + zone = Object.new + def zone.local_to_utc(time) + time + end - -> { Time.now(in: "+99:00") }.should raise_error(ArgumentError, "utc_offset out of range") - -> { Time.now(in: "+9900") }.should raise_error(ArgumentError, "utc_offset out of range") + -> { + Time.now(in: zone) + }.should raise_error(TypeError, /can't convert Object into an exact number/) end - it "raises ArgumentError if String argument and minutes greater than 59" do - -> { Time.now(in: "+00:60") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:60') - -> { Time.now(in: "+0060") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0060') + it "does not raise exception if timezone does not implement #local_to_utc method" do + zone = Object.new + def zone.utc_to_local(time) + time + end - -> { Time.now(in: "+00:99") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:99') - -> { Time.now(in: "+0099") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0099') + Time.now(in: zone).should be_kind_of(Time) end - ruby_bug '#20797', ''...'3.4' do - it "raises ArgumentError if String argument and seconds greater than 59" do - -> { Time.now(in: "+00:00:60") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:60') - -> { Time.now(in: "+000060") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000060') + # The result also should be a Time or Time-like object (not necessary to be the same class) + # or Integer. The zone of the result is just ignored. + describe "returned value by #utc_to_local and #local_to_utc methods" do + it "could be Time instance" do + zone = Object.new + def zone.utc_to_local(t) + time = Time.new(t.year, t.mon, t.day, t.hour, t.min, t.sec, t.utc_offset) + time + 60 * 60 # + 1 hour + end + + Time.now(in: zone).should be_kind_of(Time) + Time.now(in: zone).utc_offset.should == 3600 + end + + it "could be Time subclass instance" do + zone = Object.new + def zone.utc_to_local(t) + time = Time.new(t.year, t.mon, t.day, t.hour, t.min, t.sec, t.utc_offset) + time += 60 * 60 # + 1 hour + + Class.new(Time).new(time.year, time.mon, time.day, time.hour, time.min, time.sec, time.utc_offset) + end + + Time.now(in: zone).should be_kind_of(Time) + Time.now(in: zone).utc_offset.should == 3600 + end + + it "could be Integer" do + zone = Object.new + def zone.utc_to_local(time) + time.to_i + 60*60 + end + + Time.now(in: zone).should be_kind_of(Time) + Time.now(in: zone).utc_offset.should == 60*60 + end + + it "could have any #zone and #utc_offset because they are ignored" do + zone = Object.new + def zone.utc_to_local(t) + Struct.new(:year, :mon, :mday, :hour, :min, :sec, :isdst, :to_i, :zone, :utc_offset) # rubocop:disable Lint/StructNewOverride + .new(t.year, t.mon, t.mday, t.hour, t.min, t.sec, t.isdst, t.to_i, 'America/New_York', -5*60*60) + end + Time.now(in: zone).utc_offset.should == 0 + + zone = Object.new + def zone.utc_to_local(t) + Struct.new(:year, :mon, :mday, :hour, :min, :sec, :isdst, :to_i, :zone, :utc_offset) # rubocop:disable Lint/StructNewOverride + .new(t.year, t.mon, t.mday, t.hour, t.min, t.sec, t.isdst, t.to_i, 'Asia/Tokyo', 9*60*60) + end + Time.now(in: zone).utc_offset.should == 0 + + zone = Object.new + def zone.utc_to_local(t) + Time.new(t.year, t.mon, t.mday, t.hour, t.min, t.sec, 9*60*60) + end + Time.now(in: zone).utc_offset.should == 0 + end - -> { Time.now(in: "+00:00:99") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:99') - -> { Time.now(in: "+000099") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000099') + it "raises ArgumentError if difference between argument and result is too large" do + zone = Object.new + def zone.utc_to_local(t) + time = Time.utc(t.year, t.mon, t.day, t.hour, t.min, t.sec, t.utc_offset) + time -= 24 * 60 * 60 # - 1 day + Time.utc(time.year, time.mon, time.day, time.hour, time.min, time.sec, time.utc_offset) + end + + -> { + Time.now(in: zone) + }.should raise_error(ArgumentError, "utc_offset out of range") end end end diff --git a/spec/ruby/core/time/strftime_spec.rb b/spec/ruby/core/time/strftime_spec.rb index 4cb300c916..fd233f3577 100644 --- a/spec/ruby/core/time/strftime_spec.rb +++ b/spec/ruby/core/time/strftime_spec.rb @@ -50,44 +50,42 @@ describe "Time#strftime" do time.strftime("%::z").should == "+01:01:05" end - ruby_version_is "3.1" do - it "supports RFC 3339 UTC for unknown offset local time, -0000, as %-z" do - time = Time.gm(2022) - - time.strftime("%z").should == "+0000" - time.strftime("%-z").should == "-0000" - time.strftime("%-:z").should == "-00:00" - time.strftime("%-::z").should == "-00:00:00" - end + it "supports RFC 3339 UTC for unknown offset local time, -0000, as %-z" do + time = Time.gm(2022) - it "applies '-' flag to UTC time" do - time = Time.utc(2022) - time.strftime("%-z").should == "-0000" + time.strftime("%z").should == "+0000" + time.strftime("%-z").should == "-0000" + time.strftime("%-:z").should == "-00:00" + time.strftime("%-::z").should == "-00:00:00" + end - time = Time.gm(2022) - time.strftime("%-z").should == "-0000" + it "applies '-' flag to UTC time" do + time = Time.utc(2022) + time.strftime("%-z").should == "-0000" - time = Time.new(2022, 1, 1, 0, 0, 0, "Z") - time.strftime("%-z").should == "-0000" + time = Time.gm(2022) + time.strftime("%-z").should == "-0000" - time = Time.new(2022, 1, 1, 0, 0, 0, "-00:00") - time.strftime("%-z").should == "-0000" + time = Time.new(2022, 1, 1, 0, 0, 0, "Z") + time.strftime("%-z").should == "-0000" - time = Time.new(2022, 1, 1, 0, 0, 0, "+03:00").utc - time.strftime("%-z").should == "-0000" - end + time = Time.new(2022, 1, 1, 0, 0, 0, "-00:00") + time.strftime("%-z").should == "-0000" - it "ignores '-' flag for non-UTC time" do - time = Time.new(2022, 1, 1, 0, 0, 0, "+03:00") - time.strftime("%-z").should == "+0300" - end + time = Time.new(2022, 1, 1, 0, 0, 0, "+03:00").utc + time.strftime("%-z").should == "-0000" + end - it "works correctly with width, _ and 0 flags, and :" do - Time.now.utc.strftime("%-_10z").should == " -000" - Time.now.utc.strftime("%-10z").should == "-000000000" - Time.now.utc.strftime("%-010:z").should == "-000000:00" - Time.now.utc.strftime("%-_10:z").should == " -0:00" - Time.now.utc.strftime("%-_10::z").should == " -0:00:00" - end + it "ignores '-' flag for non-UTC time" do + time = Time.new(2022, 1, 1, 0, 0, 0, "+03:00") + time.strftime("%-z").should == "+0300" + end + + it "works correctly with width, _ and 0 flags, and :" do + Time.now.utc.strftime("%-_10z").should == " -000" + Time.now.utc.strftime("%-10z").should == "-000000000" + Time.now.utc.strftime("%-010:z").should == "-000000:00" + Time.now.utc.strftime("%-_10:z").should == " -0:00" + Time.now.utc.strftime("%-_10::z").should == " -0:00:00" end end diff --git a/spec/ruby/core/time/utc_spec.rb b/spec/ruby/core/time/utc_spec.rb index 566509fd33..3d36e13ccf 100644 --- a/spec/ruby/core/time/utc_spec.rb +++ b/spec/ruby/core/time/utc_spec.rb @@ -22,10 +22,8 @@ describe "Time#utc?" do Time.now.localtime("UTC").utc?.should == true Time.at(Time.now, in: 'UTC').utc?.should == true - ruby_version_is "3.1" do - Time.new(2022, 1, 1, 0, 0, 0, in: "UTC").utc?.should == true - Time.now(in: "UTC").utc?.should == true - end + Time.new(2022, 1, 1, 0, 0, 0, in: "UTC").utc?.should == true + Time.now(in: "UTC").utc?.should == true end it "does treat time with Z offset as UTC" do @@ -33,18 +31,14 @@ describe "Time#utc?" do Time.now.localtime("Z").utc?.should == true Time.at(Time.now, in: 'Z').utc?.should == true - ruby_version_is "3.1" do - Time.new(2022, 1, 1, 0, 0, 0, in: "Z").utc?.should == true - Time.now(in: "Z").utc?.should == true - end + Time.new(2022, 1, 1, 0, 0, 0, in: "Z").utc?.should == true + Time.now(in: "Z").utc?.should == true end - ruby_version_is "3.1" do - it "does treat time with -00:00 offset as UTC" do - Time.new(2022, 1, 1, 0, 0, 0, "-00:00").utc?.should == true - Time.now.localtime("-00:00").utc?.should == true - Time.at(Time.now, in: '-00:00').utc?.should == true - end + it "does treat time with -00:00 offset as UTC" do + Time.new(2022, 1, 1, 0, 0, 0, "-00:00").utc?.should == true + Time.now.localtime("-00:00").utc?.should == true + Time.at(Time.now, in: '-00:00').utc?.should == true end it "does not treat time with +00:00 offset as UTC" do diff --git a/spec/ruby/core/time/zone_spec.rb b/spec/ruby/core/time/zone_spec.rb index 63c92602d1..9a15bd569b 100644 --- a/spec/ruby/core/time/zone_spec.rb +++ b/spec/ruby/core/time/zone_spec.rb @@ -69,22 +69,18 @@ describe "Time#zone" do Time.at(Time.now, in: 'UTC').zone.should == "UTC" Time.at(Time.now, in: 'Z').zone.should == "UTC" - ruby_version_is "3.1" do - Time.new(2022, 1, 1, 0, 0, 0, "-00:00").zone.should == "UTC" - Time.now.localtime("-00:00").zone.should == "UTC" - Time.at(Time.now, in: '-00:00').zone.should == "UTC" - end + Time.new(2022, 1, 1, 0, 0, 0, "-00:00").zone.should == "UTC" + Time.now.localtime("-00:00").zone.should == "UTC" + Time.at(Time.now, in: '-00:00').zone.should == "UTC" - ruby_version_is "3.1" do - Time.new(2022, 1, 1, 0, 0, 0, in: "UTC").zone.should == "UTC" - Time.new(2022, 1, 1, 0, 0, 0, in: "Z").zone.should == "UTC" + Time.new(2022, 1, 1, 0, 0, 0, in: "UTC").zone.should == "UTC" + Time.new(2022, 1, 1, 0, 0, 0, in: "Z").zone.should == "UTC" - Time.now(in: 'UTC').zone.should == "UTC" - Time.now(in: 'Z').zone.should == "UTC" + Time.now(in: 'UTC').zone.should == "UTC" + Time.now(in: 'Z').zone.should == "UTC" - Time.at(Time.now, in: 'UTC').zone.should == "UTC" - Time.at(Time.now, in: 'Z').zone.should == "UTC" - end + Time.at(Time.now, in: 'UTC').zone.should == "UTC" + Time.at(Time.now, in: 'Z').zone.should == "UTC" end platform_is_not :aix, :windows do diff --git a/spec/ruby/core/tracepoint/allow_reentry_spec.rb b/spec/ruby/core/tracepoint/allow_reentry_spec.rb index 6bff1bed76..75e9e859a9 100644 --- a/spec/ruby/core/tracepoint/allow_reentry_spec.rb +++ b/spec/ruby/core/tracepoint/allow_reentry_spec.rb @@ -1,32 +1,30 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' -ruby_version_is "3.1" do - describe 'TracePoint.allow_reentry' do - it 'allows the reentrance in a given block' do - event_lines = [] - l1 = l2 = l3 = l4 = nil - TracePoint.new(:line) do |tp| - next unless TracePointSpec.target_thread? +describe 'TracePoint.allow_reentry' do + it 'allows the reentrance in a given block' do + event_lines = [] + l1 = l2 = l3 = l4 = nil + TracePoint.new(:line) do |tp| + next unless TracePointSpec.target_thread? - event_lines << tp.lineno - next if (__LINE__ + 2 .. __LINE__ + 4).cover?(tp.lineno) - TracePoint.allow_reentry do - a = 1; l3 = __LINE__ - b = 2; l4 = __LINE__ - end - end.enable do - c = 3; l1 = __LINE__ - d = 4; l2 = __LINE__ + event_lines << tp.lineno + next if (__LINE__ + 2 .. __LINE__ + 4).cover?(tp.lineno) + TracePoint.allow_reentry do + a = 1; l3 = __LINE__ + b = 2; l4 = __LINE__ end - - event_lines.should == [l1, l3, l4, l2, l3, l4] + end.enable do + c = 3; l1 = __LINE__ + d = 4; l2 = __LINE__ end - it 'raises RuntimeError when not called inside a TracePoint' do - -> { - TracePoint.allow_reentry{} - }.should raise_error(RuntimeError) - end + event_lines.should == [l1, l3, l4, l2, l3, l4] + end + + it 'raises RuntimeError when not called inside a TracePoint' do + -> { + TracePoint.allow_reentry{} + }.should raise_error(RuntimeError) end end diff --git a/spec/ruby/core/unboundmethod/private_spec.rb b/spec/ruby/core/unboundmethod/private_spec.rb index 8ea50bb5d4..9a890db6fd 100644 --- a/spec/ruby/core/unboundmethod/private_spec.rb +++ b/spec/ruby/core/unboundmethod/private_spec.rb @@ -2,7 +2,7 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' describe "UnboundMethod#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 = UnboundMethodSpecs::Methods.new obj.method(:my_public_method).unbind.private?.should == false diff --git a/spec/ruby/core/unboundmethod/protected_spec.rb b/spec/ruby/core/unboundmethod/protected_spec.rb index 0c215d8638..b79e2da63b 100644 --- a/spec/ruby/core/unboundmethod/protected_spec.rb +++ b/spec/ruby/core/unboundmethod/protected_spec.rb @@ -2,7 +2,7 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' describe "UnboundMethod#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 = UnboundMethodSpecs::Methods.new obj.method(:my_public_method).unbind.protected?.should == false diff --git a/spec/ruby/core/unboundmethod/public_spec.rb b/spec/ruby/core/unboundmethod/public_spec.rb index 552bbf6eab..c2a2795a84 100644 --- a/spec/ruby/core/unboundmethod/public_spec.rb +++ b/spec/ruby/core/unboundmethod/public_spec.rb @@ -2,7 +2,7 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' describe "UnboundMethod#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 = UnboundMethodSpecs::Methods.new obj.method(:my_public_method).unbind.public?.should == true diff --git a/spec/ruby/core/unboundmethod/source_location_spec.rb b/spec/ruby/core/unboundmethod/source_location_spec.rb index 45bd69438c..2391d07d99 100644 --- a/spec/ruby/core/unboundmethod/source_location_spec.rb +++ b/spec/ruby/core/unboundmethod/source_location_spec.rb @@ -61,5 +61,5 @@ describe "UnboundMethod#source_location" do ruby_version_is("3.5") do location.should == ["foo", 100, 0, 100, 10] end - end + end end |