diff options
Diffstat (limited to 'spec/ruby/shared')
119 files changed, 1670 insertions, 2859 deletions
diff --git a/spec/ruby/shared/basicobject/method_missing.rb b/spec/ruby/shared/basicobject/method_missing.rb index 97ece14c03..4871603dce 100644 --- a/spec/ruby/shared/basicobject/method_missing.rb +++ b/spec/ruby/shared/basicobject/method_missing.rb @@ -1,5 +1,5 @@ -require File.expand_path('../../../spec_helper', __FILE__) -require File.expand_path('../../../fixtures/basicobject/method_missing', __FILE__) +require_relative '../../spec_helper' +require_relative '../../fixtures/basicobject/method_missing' describe :method_missing_defined_module, shared: true do describe "for a Module with #method_missing defined" do @@ -24,15 +24,15 @@ end describe :method_missing_module, shared: true do describe "for a Module" do it "raises a NoMethodError when an undefined method is called" do - lambda { @object.no_such_method }.should raise_error(NoMethodError) + -> { @object.no_such_method }.should raise_error(NoMethodError) end it "raises a NoMethodError when a protected method is called" do - lambda { @object.method_protected }.should raise_error(NoMethodError) + -> { @object.method_protected }.should raise_error(NoMethodError) end it "raises a NoMethodError when a private method is called" do - lambda { @object.method_private }.should raise_error(NoMethodError) + -> { @object.method_private }.should raise_error(NoMethodError) end end end @@ -60,15 +60,15 @@ end describe :method_missing_class, shared: true do describe "for a Class" do it "raises a NoMethodError when an undefined method is called" do - lambda { @object.no_such_method }.should raise_error(NoMethodError) + -> { @object.no_such_method }.should raise_error(NoMethodError) end it "raises a NoMethodError when a protected method is called" do - lambda { @object.method_protected }.should raise_error(NoMethodError) + -> { @object.method_protected }.should raise_error(NoMethodError) end it "raises a NoMethodError when a private method is called" do - lambda { @object.method_private }.should raise_error(NoMethodError) + -> { @object.method_private }.should raise_error(NoMethodError) end end end @@ -100,26 +100,24 @@ end describe :method_missing_instance, shared: true do describe "for an instance" do it "raises a NoMethodError when an undefined method is called" do - lambda { @object.new.no_such_method }.should raise_error(NoMethodError) + -> { @object.new.no_such_method }.should raise_error(NoMethodError) end it "raises a NoMethodError when a protected method is called" do - lambda { @object.new.method_protected }.should raise_error(NoMethodError) + -> { @object.new.method_protected }.should raise_error(NoMethodError) end it "raises a NoMethodError when a private method is called" do - lambda { @object.new.method_private }.should raise_error(NoMethodError) + -> { @object.new.method_private }.should raise_error(NoMethodError) end - ruby_version_is "2.3" do - it 'sets the receiver of the raised NoMethodError' do - obj = @object.new + it 'sets the receiver of the raised NoMethodError' do + obj = @object.new - begin - obj.method_private - rescue NoMethodError => error - (error.receiver == obj).should == true - end + begin + obj.method_private + rescue NoMethodError => error + (error.receiver == obj).should == true end end end diff --git a/spec/ruby/shared/basicobject/send.rb b/spec/ruby/shared/basicobject/send.rb index f8c63c5522..625aaa2917 100644 --- a/spec/ruby/shared/basicobject/send.rb +++ b/spec/ruby/shared/basicobject/send.rb @@ -29,13 +29,20 @@ describe :basicobject_send, shared: true do SendSpecs::Foo.send(@method, :bar).should == 'done' end + it "raises a TypeError if the method name is not a string or symbol" do + -> { SendSpecs.send(@method, nil) }.should raise_error(TypeError, /not a symbol nor a string/) + -> { SendSpecs.send(@method, 42) }.should raise_error(TypeError, /not a symbol nor a string/) + -> { SendSpecs.send(@method, 3.14) }.should raise_error(TypeError, /not a symbol nor a string/) + -> { SendSpecs.send(@method, true) }.should raise_error(TypeError, /not a symbol nor a string/) + end + it "raises a NameError if the corresponding method can't be found" do class SendSpecs::Foo def bar 'done' end end - lambda { SendSpecs::Foo.new.send(@method, :syegsywhwua) }.should raise_error(NameError) + -> { SendSpecs::Foo.new.send(@method, :syegsywhwua) }.should raise_error(NameError) end it "raises a NameError if the corresponding singleton method can't be found" do @@ -44,12 +51,12 @@ describe :basicobject_send, shared: true do 'done' end end - lambda { SendSpecs::Foo.send(@method, :baz) }.should raise_error(NameError) + -> { SendSpecs::Foo.send(@method, :baz) }.should raise_error(NameError) end it "raises an ArgumentError if no arguments are given" do class SendSpecs::Foo; end - lambda { SendSpecs::Foo.new.send @method }.should raise_error(ArgumentError) + -> { SendSpecs::Foo.new.send @method }.should raise_error(ArgumentError) end it "raises an ArgumentError if called with more arguments than available parameters" do @@ -57,7 +64,7 @@ describe :basicobject_send, shared: true do def bar; end end - lambda { SendSpecs::Foo.new.send(@method, :bar, :arg) }.should raise_error(ArgumentError) + -> { SendSpecs::Foo.new.send(@method, :bar, :arg) }.should raise_error(ArgumentError) end it "raises an ArgumentError if called with fewer arguments than required parameters" do @@ -65,7 +72,7 @@ describe :basicobject_send, shared: true do def foo(arg); end end - lambda { SendSpecs::Foo.new.send(@method, :foo) }.should raise_error(ArgumentError) + -> { SendSpecs::Foo.new.send(@method, :foo) }.should raise_error(ArgumentError) end it "succeeds if passed an arbitrary number of arguments as a splat parameter" do @@ -107,4 +114,15 @@ describe :basicobject_send, shared: true do it "has a negative arity" do method(@method).arity.should < 0 end + + it "invokes module methods with super correctly" do + m1 = Module.new { def foo(ary); ary << :m1; end; } + m2 = Module.new { def foo(ary = []); super(ary); ary << :m2; end; } + c2 = Class.new do + include m1 + include m2 + end + + c2.new.send(@method, :foo, *[[]]).should == %i[m1 m2] + end end diff --git a/spec/ruby/shared/complex/Complex.rb b/spec/ruby/shared/complex/Complex.rb deleted file mode 100644 index 5a9715b161..0000000000 --- a/spec/ruby/shared/complex/Complex.rb +++ /dev/null @@ -1,133 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :kernel_Complex, shared: true do - describe "when passed [Complex, Complex]" do - it "returns a new Complex number based on the two given numbers" do - Complex(Complex(3, 4), Complex(5, 6)).should == Complex(3 - 6, 4 + 5) - Complex(Complex(1.5, 2), Complex(-5, 6.3)).should == Complex(1.5 - 6.3, 2 - 5) - end - end - - describe "when passed [Complex]" do - it "returns the passed Complex number" do - Complex(Complex(1, 2)).should == Complex(1, 2) - Complex(Complex(-3.4, bignum_value)).should == Complex(-3.4, bignum_value) - end - end - - describe "when passed [Integer, Integer]" do - it "returns a new Complex number" do - Complex(1, 2).should be_an_instance_of(Complex) - Complex(1, 2).real.should == 1 - Complex(1, 2).imag.should == 2 - - Complex(-3, -5).should be_an_instance_of(Complex) - Complex(-3, -5).real.should == -3 - Complex(-3, -5).imag.should == -5 - - Complex(3.5, -4.5).should be_an_instance_of(Complex) - Complex(3.5, -4.5).real.should == 3.5 - Complex(3.5, -4.5).imag.should == -4.5 - - Complex(bignum_value, 30).should be_an_instance_of(Complex) - Complex(bignum_value, 30).real.should == bignum_value - Complex(bignum_value, 30).imag.should == 30 - end - end - - describe "when passed [Integer]" do - it "returns a new Complex number with 0 as the imaginary component" do - # Guard against the Mathn library - conflicts_with :Prime do - Complex(1).should be_an_instance_of(Complex) - Complex(1).imag.should == 0 - Complex(1).real.should == 1 - - Complex(-3).should be_an_instance_of(Complex) - Complex(-3).imag.should == 0 - Complex(-3).real.should == -3 - - Complex(-4.5).should be_an_instance_of(Complex) - Complex(-4.5).imag.should == 0 - Complex(-4.5).real.should == -4.5 - - Complex(bignum_value).should be_an_instance_of(Complex) - Complex(bignum_value).imag.should == 0 - Complex(bignum_value).real.should == bignum_value - end - end - end - - describe "when passed a String" do - it "needs to be reviewed for spec completeness" - end - - describe "when passed an Objectc which responds to #to_c" do - it "returns the passed argument" do - obj = Object.new; def obj.to_c; 1i end - Complex(obj).should == Complex(0, 1) - end - end - - describe "when passed a Numeric which responds to #real? with false" do - it "returns the passed argument" do - n = mock_numeric("unreal") - n.should_receive(:real?).and_return(false) - Complex(n).should equal(n) - end - end - - describe "when passed a Numeric which responds to #real? with true" do - it "returns a Complex with the passed argument as the real component and 0 as the imaginary component" do - n = mock_numeric("real") - n.should_receive(:real?).any_number_of_times.and_return(true) - result = Complex(n) - result.real.should equal(n) - result.imag.should equal(0) - end - end - - describe "when passed Numerics n1 and n2 and at least one responds to #real? with false" do - [[false, false], [false, true], [true, false]].each do |r1, r2| - it "returns n1 + n2 * Complex(0, 1)" do - n1 = mock_numeric("n1") - n2 = mock_numeric("n2") - n3 = mock_numeric("n3") - n4 = mock_numeric("n4") - n1.should_receive(:real?).any_number_of_times.and_return(r1) - n2.should_receive(:real?).any_number_of_times.and_return(r2) - n2.should_receive(:*).with(Complex(0, 1)).and_return(n3) - n1.should_receive(:+).with(n3).and_return(n4) - Complex(n1, n2).should equal(n4) - end - end - end - - describe "when passed two Numerics and both respond to #real? with true" do - it "returns a Complex with the passed arguments as real and imaginary components respectively" do - n1 = mock_numeric("n1") - n2 = mock_numeric("n2") - n1.should_receive(:real?).any_number_of_times.and_return(true) - n2.should_receive(:real?).any_number_of_times.and_return(true) - result = Complex(n1, n2) - result.real.should equal(n1) - result.imag.should equal(n2) - end - end - - describe "when passed a single non-Numeric" do - it "coerces the passed argument using #to_c" do - n = mock("n") - c = Complex(0, 0) - n.should_receive(:to_c).and_return(c) - Complex(n).should equal(c) - end - end - - describe "when passed a non-Numeric second argument" do - it "raises TypeError" do - lambda { Complex.send(@method, :sym, :sym) }.should raise_error(TypeError) - lambda { Complex.send(@method, 0, :sym) }.should raise_error(TypeError) - end - end -end diff --git a/spec/ruby/shared/complex/abs.rb b/spec/ruby/shared/complex/abs.rb deleted file mode 100644 index 1f8d861f65..0000000000 --- a/spec/ruby/shared/complex/abs.rb +++ /dev/null @@ -1,12 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :complex_abs, shared: true do - it "returns the modulus: |a + bi| = sqrt((a ^ 2) + (b ^ 2))" do - Complex(0, 0).send(@method).should == 0 - Complex(3, 4).send(@method).should == 5 # well-known integer case - Complex(-3, 4).send(@method).should == 5 - Complex(1, -1).send(@method).should be_close(Math.sqrt(2), TOLERANCE) - Complex(6.5, 0).send(@method).should be_close(6.5, TOLERANCE) - Complex(0, -7.2).send(@method).should be_close(7.2, TOLERANCE) - end -end diff --git a/spec/ruby/shared/complex/abs2.rb b/spec/ruby/shared/complex/abs2.rb deleted file mode 100644 index f899a41a3e..0000000000 --- a/spec/ruby/shared/complex/abs2.rb +++ /dev/null @@ -1,12 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :complex_abs2, shared: true do - it "returns the sum of the squares of the real and imaginary parts" do - Complex(1, -2).abs2.should == 1 + 4 - Complex(-0.1, 0.2).abs2.should be_close(0.01 + 0.04, TOLERANCE) - # Guard against Mathn library - conflicts_with :Prime do - Complex(0).abs2.should == 0 - end - end -end diff --git a/spec/ruby/shared/complex/arg.rb b/spec/ruby/shared/complex/arg.rb deleted file mode 100644 index c81f197433..0000000000 --- a/spec/ruby/shared/complex/arg.rb +++ /dev/null @@ -1,9 +0,0 @@ -describe :complex_arg, shared: true do - it "returns the argument -- i.e., the angle from (1, 0) in the complex plane" do - two_pi = 2 * Math::PI - (Complex(1, 0).send(@method) % two_pi).should be_close(0, TOLERANCE) - (Complex(0, 2).send(@method) % two_pi).should be_close(Math::PI * 0.5, TOLERANCE) - (Complex(-100, 0).send(@method) % two_pi).should be_close(Math::PI, TOLERANCE) - (Complex(0, -75.3).send(@method) % two_pi).should be_close(Math::PI * 1.5, TOLERANCE) - end -end diff --git a/spec/ruby/shared/complex/coerce.rb b/spec/ruby/shared/complex/coerce.rb deleted file mode 100644 index b8a230dfb5..0000000000 --- a/spec/ruby/shared/complex/coerce.rb +++ /dev/null @@ -1,70 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :complex_coerce, shared: true do - before :each do - @one = Complex(1) - end - - it "returns an array containing other and self as Complex when other is an Integer" do - result = @one.coerce(2) - result.should == [2, 1] - result.first.should be_kind_of(Complex) - result.last.should be_kind_of(Complex) - end - - it "returns an array containing other and self as Complex when other is a Float" do - result = @one.coerce(20.5) - result.should == [20.5, 1] - result.first.should be_kind_of(Complex) - result.last.should be_kind_of(Complex) - end - - it "returns an array containing other and self as Complex when other is a Bignum" do - result = @one.coerce(4294967296) - result.should == [4294967296, 1] - result.first.should be_kind_of(Complex) - result.last.should be_kind_of(Complex) - end - - it "returns an array containing other and self as Complex when other is a Rational" do - result = @one.coerce(Rational(5,6)) - result.should == [Rational(5,6), 1] - result.first.should be_kind_of(Complex) - result.last.should be_kind_of(Complex) - end - - it "returns an array containing other and self when other is a Complex" do - other = Complex(2) - result = @one.coerce(other) - result.should == [other, @one] - result.first.should equal(other) - result.last.should equal(@one) - end - - it "returns an array containing other as Complex and self when other is a Numeric which responds to #real? with true" do - other = mock_numeric('other') - other.should_receive(:real?).any_number_of_times.and_return(true) - result = @one.coerce(other) - result.should == [other, @one] - result.first.should eql(Complex(other)) - result.last.should equal(@one) - end - - it "raises TypeError when other is a Numeric which responds to #real? with false" do - other = mock_numeric('other') - other.should_receive(:real?).any_number_of_times.and_return(false) - lambda { @one.coerce(other) }.should raise_error(TypeError) - end - - it "raises a TypeError when other is a String" do - lambda { @one.coerce("20") }.should raise_error(TypeError) - end - - it "raises a TypeError when other is nil" do - lambda { @one.coerce(nil) }.should raise_error(TypeError) - end - - it "raises a TypeError when other is false" do - lambda { @one.coerce(false) }.should raise_error(TypeError) - end -end diff --git a/spec/ruby/shared/complex/conjugate.rb b/spec/ruby/shared/complex/conjugate.rb deleted file mode 100644 index d1ae47bcb6..0000000000 --- a/spec/ruby/shared/complex/conjugate.rb +++ /dev/null @@ -1,8 +0,0 @@ -describe :complex_conjugate, shared: true do - it "returns the complex conjugate: conj a + bi = a - bi" do - Complex(3, 5).send(@method).should == Complex(3, -5) - Complex(3, -5).send(@method).should == Complex(3, 5) - Complex(-3.0, 5.2).send(@method).should be_close(Complex(-3.0, -5.2), TOLERANCE) - Complex(3.0, -5.2).send(@method).should be_close(Complex(3.0, 5.2), TOLERANCE) - end -end diff --git a/spec/ruby/shared/complex/constants.rb b/spec/ruby/shared/complex/constants.rb deleted file mode 100644 index e8bb5fc907..0000000000 --- a/spec/ruby/shared/complex/constants.rb +++ /dev/null @@ -1,7 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :complex_I, shared: true do - it "is Complex(0, 1)" do - Complex::I.should eql(Complex(0, 1)) - end -end diff --git a/spec/ruby/shared/complex/denominator.rb b/spec/ruby/shared/complex/denominator.rb deleted file mode 100644 index 6084cbf672..0000000000 --- a/spec/ruby/shared/complex/denominator.rb +++ /dev/null @@ -1,13 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :complex_denominator, shared: true do - it "returns the least common multiple denominator of the real and imaginary parts" do - Complex(3, 4).denominator.should == 1 - Complex(3, bignum_value).denominator.should == 1 - - Complex(3, Rational(3,4)).denominator.should == 4 - - Complex(Rational(4,8), Rational(3,4)).denominator.should == 4 - Complex(Rational(3,8), Rational(3,4)).denominator.should == 8 - end -end diff --git a/spec/ruby/shared/complex/divide.rb b/spec/ruby/shared/complex/divide.rb deleted file mode 100644 index 0bd88f197e..0000000000 --- a/spec/ruby/shared/complex/divide.rb +++ /dev/null @@ -1,84 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :complex_divide, shared: true do - describe "with Complex" do - it "divides according to the usual rule for complex numbers" do - a = Complex((1 * 10) - (2 * 20), (1 * 20) + (2 * 10)) - b = Complex(1, 2) - a.send(@method, b).should == Complex(10, 20) - - c = Complex((1.5 * 100.2) - (2.1 * -30.3), (1.5 * -30.3) + (2.1 * 100.2)) - d = Complex(1.5, 2.1) - # remember the floating-point arithmetic - c.send(@method, d).should be_close(Complex(100.2, -30.3), TOLERANCE) - end - end - - describe "with Fixnum" do - it "divides both parts of the Complex number" do - Complex(20, 40).send(@method, 2).should == Complex(10, 20) - Complex(30, 30).send(@method, 10).should == Complex(3, 3) - end - - it "raises a ZeroDivisionError when given zero" do - lambda { Complex(20, 40).send(@method, 0) }.should raise_error(ZeroDivisionError) - end - - it "produces Rational parts" do - Complex(5, 9).send(@method, 2).should eql(Complex(Rational(5,2), Rational(9,2))) - end - end - - describe "with Bignum" do - it "divides both parts of the Complex number" do - Complex(20, 40).send(@method, 2).should == Complex(10, 20) - Complex(15, 16).send(@method, 2.0).should be_close(Complex(7.5, 8), TOLERANCE) - end - end - - describe "with Float" do - it "divides both parts of the Complex number" do - Complex(3, 9).send(@method, 1.5).should == Complex(2, 6) - Complex(15, 16).send(@method, 2.0).should be_close(Complex(7.5, 8), TOLERANCE) - end - - it "returns Complex(Infinity, Infinity) when given zero" do - Complex(20, 40).send(@method, 0.0).real.infinite?.should == 1 - Complex(20, 40).send(@method, 0.0).imag.infinite?.should == 1 - Complex(-20, 40).send(@method, 0.0).real.infinite?.should == -1 - Complex(-20, 40).send(@method, 0.0).imag.infinite?.should == 1 - end - end - - describe "with Object" do - it "tries to coerce self into other" do - value = Complex(3, 9) - - obj = mock("Object") - obj.should_receive(:coerce).with(value).and_return([4, 2]) - value.send(@method, obj).should == 2 - end - end - - describe "with a Numeric which responds to #real? with true" do - it "returns Complex(real.quo(other), imag.quo(other))" do - other = mock_numeric('other') - real = mock_numeric('real') - imag = mock_numeric('imag') - other.should_receive(:real?).and_return(true) - real.should_receive(:quo).with(other).and_return(1) - imag.should_receive(:quo).with(other).and_return(2) - Complex(real, imag).send(@method, other).should == Complex(1, 2) - end - end - - describe "with a Numeric which responds to #real? with false" do - it "coerces the passed argument to Complex and divides the resulting elements" do - complex = Complex(3, 0) - other = mock_numeric('other') - other.should_receive(:real?).any_number_of_times.and_return(false) - other.should_receive(:coerce).with(complex).and_return([5, 2]) - complex.send(@method, other).should eql(Rational(5, 2)) - end - end -end diff --git a/spec/ruby/shared/complex/equal_value.rb b/spec/ruby/shared/complex/equal_value.rb deleted file mode 100644 index d944698878..0000000000 --- a/spec/ruby/shared/complex/equal_value.rb +++ /dev/null @@ -1,93 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :complex_equal_value, shared: true do - describe "with Complex" do - it "returns true when self and other have numerical equality" do - Complex(1, 2).should == Complex(1, 2) - Complex(3, 9).should == Complex(3, 9) - Complex(-3, -9).should == Complex(-3, -9) - - Complex(1, 2).should_not == Complex(3, 4) - Complex(3, 9).should_not == Complex(9, 3) - - Complex(1.0, 2.0).should == Complex(1, 2) - Complex(3.0, 9.0).should_not == Complex(9.0, 3.0) - - Complex(1.5, 2.5).should == Complex(1.5, 2.5) - Complex(1.5, 2.5).should == Complex(1.5, 2.5) - Complex(-1.5, 2.5).should == Complex(-1.5, 2.5) - - Complex(1.5, 2.5).should_not == Complex(2.5, 1.5) - Complex(3.75, 2.5).should_not == Complex(1.5, 2.5) - - Complex(bignum_value, 2.5).should == Complex(bignum_value, 2.5) - Complex(3.75, bignum_value).should_not == Complex(1.5, bignum_value) - - Complex(nan_value).should_not == Complex(nan_value) - end - end - - describe "with Numeric" do - it "returns true when self's imaginary part is 0 and the real part and other have numerical equality" do - Complex(3, 0).should == 3 - Complex(-3, 0).should == -3 - - Complex(3.5, 0).should == 3.5 - Complex(-3.5, 0).should == -3.5 - - Complex(bignum_value, 0).should == bignum_value - Complex(-bignum_value, 0).should == -bignum_value - - Complex(3.0, 0).should == 3 - Complex(-3.0, 0).should == -3 - - Complex(3, 0).should_not == 4 - Complex(-3, 0).should_not == -4 - - Complex(3.5, 0).should_not == -4.5 - Complex(-3.5, 0).should_not == 2.5 - - Complex(bignum_value, 0).should_not == bignum_value(10) - Complex(-bignum_value, 0).should_not == -bignum_value(20) - end - end - - describe "with Object" do - # Fixnum#==, Float#== and Bignum#== only return booleans - Bug? - it "calls other#== with self" do - value = Complex(3, 0) - - obj = mock("Object") - obj.should_receive(:==).with(value).and_return(:expected) - - (value == obj).should_not be_false - end - end - - describe "with a Numeric which responds to #real? with true" do - before do - @other = mock_numeric('other') - @other.should_receive(:real?).any_number_of_times.and_return(true) - end - - it "returns real == other when the imaginary part is zero" do - real = mock_numeric('real') - real.should_receive(:==).with(@other).and_return(true) - (Complex(real, 0) == @other).should be_true - end - - it "returns false when when the imaginary part is not zero" do - (Complex(3, 1) == @other).should be_false - end - end - - describe "with a Numeric which responds to #real? with false" do - it "returns other == self" do - complex = Complex(3, 0) - other = mock_numeric('other') - other.should_receive(:real?).any_number_of_times.and_return(false) - other.should_receive(:==).with(complex).and_return(true) - (complex == other).should be_true - end - end -end diff --git a/spec/ruby/shared/complex/exponent.rb b/spec/ruby/shared/complex/exponent.rb deleted file mode 100644 index 8261db872a..0000000000 --- a/spec/ruby/shared/complex/exponent.rb +++ /dev/null @@ -1,61 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :complex_exponent, shared: true do - describe "with Fixnum 0" do - it "returns Complex(1)" do - (Complex(3, 4) ** 0).should eql(Complex(1)) - end - end - - describe "with Float 0.0" do - it "returns Complex(1.0, 0.0)" do - (Complex(3, 4) ** 0.0).should eql(Complex(1.0, 0.0)) - end - end - - describe "with Complex" do - it "returns self raised to the given power" do - (Complex(2, 1) ** Complex(2, 1)).should be_close(Complex(-0.504824688978319, 3.10414407699553), TOLERANCE) - (Complex(2, 1) ** Complex(3, 4)).should be_close(Complex(-0.179174656916581, -1.74071656397662), TOLERANCE) - - (Complex(2, 1) ** Complex(-2, -1)).should be_close(Complex(-0.051041070450869, -0.313849223270419), TOLERANCE) - (Complex(-2, -1) ** Complex(2, 1)).should be_close(Complex(-11.6819929610857, 71.8320439736158), TOLERANCE) - end - end - - describe "with Integer" do - it "returns self raised to the given power" do - (Complex(2, 1) ** 2).should == Complex(3, 4) - (Complex(3, 4) ** 2).should == Complex(-7, 24) - (Complex(3, 4) ** -2).should be_close(Complex(-0.0112, -0.0384), TOLERANCE) - - - (Complex(2, 1) ** 2.5).should be_close(Complex(2.99179707178602, 6.85206901006896), TOLERANCE) - (Complex(3, 4) ** 2.5).should be_close(Complex(-38.0, 41.0), TOLERANCE) - (Complex(3, 4) ** -2.5).should be_close(Complex(-0.01216, -0.01312), TOLERANCE) - - (Complex(1) ** 1).should == Complex(1) - - # NOTE: Takes way too long... - #(Complex(2, 1) ** bignum_value) - end - end - - describe "with Rational" do - it "returns self raised to the given power" do - (Complex(2, 1) ** Rational(3, 4)).should be_close(Complex(1.71913265276568, 0.623124744394697), TOLERANCE) - (Complex(2, 1) ** Rational(4, 3)).should be_close(Complex(2.3828547125173, 1.69466313833091), TOLERANCE) - (Complex(2, 1) ** Rational(-4, 3)).should be_close(Complex(0.278700377879388, -0.198209003071003), TOLERANCE) - end - end - - describe "with Object" do - it "tries to coerce self into other" do - value = Complex(3, 9) - - obj = mock("Object") - obj.should_receive(:coerce).with(value).and_return([2, 5]) - (value ** obj).should == 2 ** 5 - end - end -end diff --git a/spec/ruby/shared/complex/float/arg.rb b/spec/ruby/shared/complex/float/arg.rb deleted file mode 100644 index ca29796610..0000000000 --- a/spec/ruby/shared/complex/float/arg.rb +++ /dev/null @@ -1,38 +0,0 @@ -require File.expand_path('../../../../spec_helper', __FILE__) - -describe :float_arg, shared: true do - it "returns NaN if NaN" do - f = nan_value - f.send(@method).nan?.should be_true - end - - it "returns self if NaN" do - f = nan_value - f.send(@method).should equal(f) - end - - it "returns 0 if positive" do - 1.0.send(@method).should == 0 - end - - it "returns 0 if +0.0" do - 0.0.send(@method).should == 0 - end - - it "returns 0 if +Infinity" do - infinity_value.send(@method).should == 0 - end - - it "returns Pi if negative" do - (-1.0).send(@method).should == Math::PI - end - - # This was established in r23960 - it "returns Pi if -0.0" do - (-0.0).send(@method).should == Math::PI - end - - it "returns Pi if -Infinity" do - (-infinity_value).send(@method).should == Math::PI - end -end diff --git a/spec/ruby/shared/complex/hash.rb b/spec/ruby/shared/complex/hash.rb deleted file mode 100644 index 26ca59aeaf..0000000000 --- a/spec/ruby/shared/complex/hash.rb +++ /dev/null @@ -1,16 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :complex_hash, shared: true do - it "is static" do - Complex(1).hash.should == Complex(1).hash - Complex(1, 0).hash.should == Complex(1).hash - Complex(1, 1).hash.should == Complex(1, 1).hash - end - - it "is different for different instances" do - Complex(1, 2).hash.should_not == Complex(1, 1).hash - Complex(2, 1).hash.should_not == Complex(1, 1).hash - - Complex(1, 2).hash.should_not == Complex(2, 1).hash - end -end diff --git a/spec/ruby/shared/complex/image.rb b/spec/ruby/shared/complex/image.rb deleted file mode 100644 index 5d45210b45..0000000000 --- a/spec/ruby/shared/complex/image.rb +++ /dev/null @@ -1,10 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :complex_image, shared: true do - it "returns the imaginary part of self" do - Complex(1, 0).send(@method).should == 0 - Complex(2, 1).send(@method).should == 1 - Complex(6.7, 8.9).send(@method).should == 8.9 - Complex(1, bignum_value).send(@method).should == bignum_value - end -end diff --git a/spec/ruby/shared/complex/inspect.rb b/spec/ruby/shared/complex/inspect.rb deleted file mode 100644 index 7c0c3d6b9c..0000000000 --- a/spec/ruby/shared/complex/inspect.rb +++ /dev/null @@ -1,14 +0,0 @@ -describe :complex_inspect, shared: true do - it "returns (${real}+${image}i) for positive imaginary parts" do - Complex(1).inspect.should == "(1+0i)" - Complex(7).inspect.should == "(7+0i)" - Complex(-1, 4).inspect.should == "(-1+4i)" - Complex(-7, 6.7).inspect.should == "(-7+6.7i)" - end - - it "returns (${real}-${image}i) for negative imaginary parts" do - Complex(0, -1).inspect.should == "(0-1i)" - Complex(-1, -4).inspect.should == "(-1-4i)" - Complex(-7, -6.7).inspect.should == "(-7-6.7i)" - end -end diff --git a/spec/ruby/shared/complex/minus.rb b/spec/ruby/shared/complex/minus.rb deleted file mode 100644 index c28d08ad2e..0000000000 --- a/spec/ruby/shared/complex/minus.rb +++ /dev/null @@ -1,45 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :complex_minus, shared: true do - describe "with Complex" do - it "subtracts both the real and imaginary components" do - (Complex(1, 2) - Complex(10, 20)).should == Complex(1 - 10, 2 - 20) - (Complex(1.5, 2.1) - Complex(100.2, -30.3)).should == Complex(1.5 - 100.2, 2.1 - (-30.3)) - end - end - - describe "with Integer" do - it "subtracts the real number from the real component of self" do - (Complex(1, 2) - 50).should == Complex(-49, 2) - (Complex(1, 2) - 50.5).should == Complex(-49.5, 2) - end - end - - describe "with Object" do - it "tries to coerce self into other" do - value = Complex(3, 9) - - obj = mock("Object") - obj.should_receive(:coerce).with(value).and_return([2, 5]) - (value - obj).should == 2 - 5 - end - end - - describe "passed Numeric which responds to #real? with true" do - it "coerces the passed argument to the type of the real part and subtracts the resulting elements" do - n = mock_numeric('n') - n.should_receive(:real?).and_return(true) - n.should_receive(:coerce).with(1).and_return([1, 4]) - (Complex(1, 2) - n).should == Complex(-3, 2) - end - end - - describe "passed Numeric which responds to #real? with false" do - it "coerces the passed argument to Complex and subtracts the resulting elements" do - n = mock_numeric('n') - n.should_receive(:real?).and_return(false) - n.should_receive(:coerce).with(Complex(1, 2)).and_return([Complex(1, 2), Complex(3, 4)]) - (Complex(1, 2) - n).should == Complex(-2, -2) - end - end -end diff --git a/spec/ruby/shared/complex/multiply.rb b/spec/ruby/shared/complex/multiply.rb deleted file mode 100644 index 4d94ef2ce3..0000000000 --- a/spec/ruby/shared/complex/multiply.rb +++ /dev/null @@ -1,49 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :complex_multiply, shared: true do - describe "with Complex" do - it "multiplies according to the usual rule for complex numbers: (a + bi) * (c + di) = ac - bd + (ad + bc)i" do - (Complex(1, 2) * Complex(10, 20)).should == Complex((1 * 10) - (2 * 20), (1 * 20) + (2 * 10)) - (Complex(1.5, 2.1) * Complex(100.2, -30.3)).should == Complex((1.5 * 100.2) - (2.1 * -30.3), (1.5 * -30.3) + (2.1 * 100.2)) - end - end - - describe "with Integer" do - it "multiplies both parts of self by the given Integer" do - (Complex(3, 2) * 50).should == Complex(150, 100) - (Complex(-3, 2) * 50.5).should == Complex(-151.5, 101) - end - end - - describe "with Object" do - it "tries to coerce self into other" do - value = Complex(3, 9) - - obj = mock("Object") - obj.should_receive(:coerce).with(value).and_return([2, 5]) - (value * obj).should == 2 * 5 - end - end - - describe "with a Numeric which responds to #real? with true" do - it "multiples both parts of self by other" do - other = mock_numeric('other') - real = mock_numeric('real') - imag = mock_numeric('imag') - other.should_receive(:real?).and_return(true) - real.should_receive(:*).with(other).and_return(1) - imag.should_receive(:*).with(other).and_return(2) - (Complex(real, imag) * other).should == Complex(1, 2) - end - - describe "with a Numeric which responds to #real? with false" do - it "coerces the passed argument to Complex and multiplies the resulting elements" do - complex = Complex(3, 0) - other = mock_numeric('other') - other.should_receive(:real?).any_number_of_times.and_return(false) - other.should_receive(:coerce).with(complex).and_return([5, 2]) - (complex * other).should == 10 - end - end - end -end diff --git a/spec/ruby/shared/complex/numerator.rb b/spec/ruby/shared/complex/numerator.rb deleted file mode 100644 index b8384e4a93..0000000000 --- a/spec/ruby/shared/complex/numerator.rb +++ /dev/null @@ -1,19 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :complex_numerator, shared: true do - it "returns self's numerator" do - Complex(2).numerator.should == Complex(2) - Complex(3, 4).numerator.should == Complex(3, 4) - - Complex(Rational(3, 4), Rational(3, 4)).numerator.should == Complex(3, 3) - Complex(Rational(7, 4), Rational(8, 4)).numerator.should == Complex(7, 8) - - Complex(Rational(7, 8), Rational(8, 4)).numerator.should == Complex(7, 16) - Complex(Rational(7, 4), Rational(8, 8)).numerator.should == Complex(7, 4) - - # NOTE: - # Bug? - Fails with a MethodMissingError - # (undefined method `denominator' for 3.5:Float) - # Complex(3.5, 3.7).numerator - end -end diff --git a/spec/ruby/shared/complex/numeric/arg.rb b/spec/ruby/shared/complex/numeric/arg.rb deleted file mode 100644 index b7eb1f2e2d..0000000000 --- a/spec/ruby/shared/complex/numeric/arg.rb +++ /dev/null @@ -1,38 +0,0 @@ -require File.expand_path('../../../../spec_helper', __FILE__) - -describe :numeric_arg, shared: true do - before :each do - @numbers = [ - 20, - Rational(3, 4), - bignum_value, - infinity_value - ] - end - - it "returns 0 if positive" do - @numbers.each do |number| - number.send(@method).should == 0 - end - end - - it "returns Pi if negative" do - @numbers.each do |number| - (0-number).send(@method).should == Math::PI - end - end - - describe "with a Numeric subclass" do - it "returns 0 if self#<(0) returns false" do - numeric = mock_numeric('positive') - numeric.should_receive(:<).with(0).and_return(false) - numeric.send(@method).should == 0 - end - - it "returns Pi if self#<(0) returns true" do - numeric = mock_numeric('positive') - numeric.should_receive(:<).with(0).and_return(true) - numeric.send(@method).should == Math::PI - end - end -end diff --git a/spec/ruby/shared/complex/numeric/conj.rb b/spec/ruby/shared/complex/numeric/conj.rb deleted file mode 100644 index 50cb060442..0000000000 --- a/spec/ruby/shared/complex/numeric/conj.rb +++ /dev/null @@ -1,20 +0,0 @@ -require File.expand_path('../../../../spec_helper', __FILE__) - -describe :numeric_conj, shared: true do - before :each do - @numbers = [ - 20, # Integer - 398.72, # Float - Rational(3, 4), # Rational - bignum_value, - infinity_value, - nan_value - ] - end - - it "returns self" do - @numbers.each do |number| - number.send(@method).should equal(number) - end - end -end diff --git a/spec/ruby/shared/complex/numeric/imag.rb b/spec/ruby/shared/complex/numeric/imag.rb deleted file mode 100644 index caf54e2cf9..0000000000 --- a/spec/ruby/shared/complex/numeric/imag.rb +++ /dev/null @@ -1,26 +0,0 @@ -require File.expand_path('../../../../spec_helper', __FILE__) - -describe :numeric_imag, shared: true do - before :each do - @numbers = [ - 20, # Integer - 398.72, # Float - Rational(3, 4), # Rational - bignum_value, # Bignum - infinity_value, - nan_value - ].map{|n| [n,-n]}.flatten - end - - it "returns 0" do - @numbers.each do |number| - number.send(@method).should == 0 - end - end - - it "raises an ArgumentError if given any arguments" do - @numbers.each do |number| - lambda { number.send(@method, number) }.should raise_error(ArgumentError) - end - end -end diff --git a/spec/ruby/shared/complex/numeric/polar.rb b/spec/ruby/shared/complex/numeric/polar.rb deleted file mode 100644 index 952b65c1b6..0000000000 --- a/spec/ruby/shared/complex/numeric/polar.rb +++ /dev/null @@ -1,50 +0,0 @@ -require File.expand_path('../../../../spec_helper', __FILE__) - -describe :numeric_polar, shared: true do - before :each do - @pos_numbers = [ - 1, - 3898172610**9, - 987.18273, - Float::MAX, - Rational(13,7), - infinity_value, - ] - @neg_numbers = @pos_numbers.map {|n| -n} - @numbers = @pos_numbers + @neg_numbers - @numbers.push(0, 0.0) - end - - it "returns a two-element Array" do - @numbers.each do |number| - number.polar.should be_an_instance_of(Array) - number.polar.size.should == 2 - end - end - - it "sets the first value to the absolute value of self" do - @numbers.each do |number| - number.polar.first.should == number.abs - end - end - - it "sets the last value to 0 if self is positive" do - (@numbers - @neg_numbers).each do |number| - number.should >= 0 - number.polar.last.should == 0 - end - end - - it "sets the last value to Pi if self is negative" do - @neg_numbers.each do |number| - number.should < 0 - number.polar.last.should == Math::PI - end - end - - it "returns [NaN, NaN] if self is NaN" do - nan_value.polar.size.should == 2 - nan_value.polar.first.nan?.should be_true - nan_value.polar.last.nan?.should be_true - end -end diff --git a/spec/ruby/shared/complex/numeric/real.rb b/spec/ruby/shared/complex/numeric/real.rb deleted file mode 100644 index 0dcf2e8381..0000000000 --- a/spec/ruby/shared/complex/numeric/real.rb +++ /dev/null @@ -1,30 +0,0 @@ -require File.expand_path('../../../../spec_helper', __FILE__) - -describe :numeric_real, shared: true do - before :each do - @numbers = [ - 20, # Integer - 398.72, # Float - Rational(3, 4), # Rational - bignum_value, # Bignum - infinity_value, - nan_value - ].map{|n| [n,-n]}.flatten - end - - it "returns self" do - @numbers.each do |number| - if number.to_f.nan? - number.real.nan?.should be_true - else - number.real.should == number - end - end - end - - it "raises an ArgumentError if given any arguments" do - @numbers.each do |number| - lambda { number.real(number) }.should raise_error(ArgumentError) - end - end -end diff --git a/spec/ruby/shared/complex/plus.rb b/spec/ruby/shared/complex/plus.rb deleted file mode 100644 index 47e362d886..0000000000 --- a/spec/ruby/shared/complex/plus.rb +++ /dev/null @@ -1,45 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :complex_plus, shared: true do - describe "with Complex" do - it "adds both the real and imaginary components" do - (Complex(1, 2) + Complex(10, 20)).should == Complex(1 + 10, 2 + 20) - (Complex(1.5, 2.1) + Complex(100.2, -30.3)).should == Complex(1.5 + 100.2, 2.1 + (-30.3)) - end - end - - describe "with Integer" do - it "adds the real number to the real component of self" do - (Complex(1, 2) + 50).should == Complex(51, 2) - (Complex(1, 2) + 50.5).should == Complex(51.5, 2) - end - end - - describe "with Object" do - it "tries to coerce self into other" do - value = Complex(3, 9) - - obj = mock("Object") - obj.should_receive(:coerce).with(value).and_return([2, 5]) - (value + obj).should == 2 + 5 - end - end - - describe "passed Numeric which responds to #real? with true" do - it "coerces the passed argument to the type of the real part and adds the resulting elements" do - n = mock_numeric('n') - n.should_receive(:real?).and_return(true) - n.should_receive(:coerce).with(1).and_return([1, 4]) - (Complex(1, 2) + n).should == Complex(5, 2) - end - end - - describe "passed Numeric which responds to #real? with false" do - it "coerces the passed argument to Complex and adds the resulting elements" do - n = mock_numeric('n') - n.should_receive(:real?).and_return(false) - n.should_receive(:coerce).with(Complex(1, 2)).and_return([Complex(1, 2), Complex(3, 4)]) - (Complex(1, 2) + n).should == Complex(4, 6) - end - end -end diff --git a/spec/ruby/shared/complex/polar.rb b/spec/ruby/shared/complex/polar.rb deleted file mode 100644 index acc063d89f..0000000000 --- a/spec/ruby/shared/complex/polar.rb +++ /dev/null @@ -1,22 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :complex_polar_class, shared: true do - it "returns a complex number in terms of radius and angle" do - Complex.polar(50, 60).should be_close(Complex(-47.6206490207578, -15.2405310551108), TOLERANCE) - Complex.polar(-10, -20).should be_close(Complex(-4.08082061813392, 9.12945250727628), TOLERANCE) - end -end - -describe :complex_polar, shared: true do - it "returns the absolute value and the argument" do - a = Complex(3, 4) - a.polar.size.should == 2 - a.polar.first.should == 5.0 - a.polar.last.should be_close(0.927295218001612, TOLERANCE) - - b = Complex(-3.5, 4.7) - b.polar.size.should == 2 - b.polar.first.should be_close(5.86003412959345, TOLERANCE) - b.polar.last.should be_close(2.21088447955664, TOLERANCE) - end -end diff --git a/spec/ruby/shared/complex/real.rb b/spec/ruby/shared/complex/real.rb deleted file mode 100644 index ab8ed07a4d..0000000000 --- a/spec/ruby/shared/complex/real.rb +++ /dev/null @@ -1,8 +0,0 @@ -describe :complex_real, shared: true do - it "returns the real part of self" do - Complex(1, 0).real.should == 1 - Complex(2, 1).real.should == 2 - Complex(6.7, 8.9).real.should == 6.7 - Complex(bignum_value, 3).real.should == bignum_value - end -end diff --git a/spec/ruby/shared/complex/rect.rb b/spec/ruby/shared/complex/rect.rb deleted file mode 100644 index 8a59d873eb..0000000000 --- a/spec/ruby/shared/complex/rect.rb +++ /dev/null @@ -1,96 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :complex_rect, shared: true do - before :each do - @numbers = [ - Complex(1), - Complex(0, 20), - Complex(0, 0), - Complex(0.0), - Complex(9999999**99), - Complex(-20), - Complex.polar(76, 10) - ] - end - - it "returns an Array" do - @numbers.each do |number| - number.send(@method).should be_an_instance_of(Array) - end - end - - it "returns a two-element Array" do - @numbers.each do |number| - number.send(@method).size.should == 2 - end - 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 - 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 - end - - it "raises an ArgumentError if given any arguments" do - @numbers.each do |number| - lambda { number.send(@method, number) }.should raise_error(ArgumentError) - end - end -end - -describe :complex_rect_class, shared: true do - describe "passed a Numeric n which responds to #real? with true" do - it "returns a Complex with real part n and imaginary part 0" do - n = mock_numeric('n') - n.should_receive(:real?).any_number_of_times.and_return(true) - result = Complex.send(@method, n) - result.real.should == n - result.imag.should == 0 - end - end - - describe "passed a Numeric which responds to #real? with false" do - it "raises TypeError" do - n = mock_numeric('n') - n.should_receive(:real?).any_number_of_times.and_return(false) - lambda { Complex.send(@method, n) }.should raise_error(TypeError) - end - end - - describe "passed Numerics n1 and n2 and at least one responds to #real? with false" do - [[false, false], [false, true], [true, false]].each do |r1, r2| - it "raises TypeError" do - n1 = mock_numeric('n1') - n2 = mock_numeric('n2') - n1.should_receive(:real?).any_number_of_times.and_return(r1) - n2.should_receive(:real?).any_number_of_times.and_return(r2) - lambda { Complex.send(@method, n1, n2) }.should raise_error(TypeError) - end - end - end - - describe "passed Numerics n1 and n2 and both respond to #real? with true" do - it "returns a Complex with real part n1 and imaginary part n2" do - n1 = mock_numeric('n1') - n2 = mock_numeric('n2') - n1.should_receive(:real?).any_number_of_times.and_return(true) - n2.should_receive(:real?).any_number_of_times.and_return(true) - result = Complex.send(@method, n1, n2) - result.real.should == n1 - result.imag.should == n2 - end - end - - describe "passed a non-Numeric" do - it "raises TypeError" do - lambda { Complex.send(@method, :sym) }.should raise_error(TypeError) - lambda { Complex.send(@method, 0, :sym) }.should raise_error(TypeError) - end - end -end diff --git a/spec/ruby/shared/complex/to_s.rb b/spec/ruby/shared/complex/to_s.rb deleted file mode 100644 index 03f4f98b84..0000000000 --- a/spec/ruby/shared/complex/to_s.rb +++ /dev/null @@ -1,44 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :complex_to_s, shared: true do - describe "when self's real component is 0" do - it "returns both the real and imaginary component even when the real is 0" do - Complex(0, 5).to_s.should == "0+5i" - Complex(0, -3.2).to_s.should == "0-3.2i" - end - end - - it "returns self as String" do - Complex(1, 5).to_s.should == "1+5i" - Complex(-2.5, 1.5).to_s.should == "-2.5+1.5i" - - Complex(1, -5).to_s.should == "1-5i" - Complex(-2.5, -1.5).to_s.should == "-2.5-1.5i" - - # Guard against the Mathn library - conflicts_with :Prime do - Complex(1, 0).to_s.should == "1+0i" - Complex(1, -0).to_s.should == "1+0i" - end - end - - it "returns 1+0.0i for Complex(1, 0.0)" do - Complex(1, 0.0).to_s.should == "1+0.0i" - end - - it "returns 1-0.0i for Complex(1, -0.0)" do - Complex(1, -0.0).to_s.should == "1-0.0i" - end - - it "returns 1+Infinity*i for Complex(1, Infinity)" do - Complex(1, infinity_value).to_s.should == "1+Infinity*i" - end - - it "returns 1-Infinity*i for Complex(1, -Infinity)" do - Complex(1, -infinity_value).to_s.should == "1-Infinity*i" - end - - it "returns 1+NaN*i for Complex(1, NaN)" do - Complex(1, nan_value).to_s.should == "1+NaN*i" - end -end diff --git a/spec/ruby/shared/enumerable/minmax.rb b/spec/ruby/shared/enumerable/minmax.rb new file mode 100644 index 0000000000..8af2626d2a --- /dev/null +++ b/spec/ruby/shared/enumerable/minmax.rb @@ -0,0 +1,24 @@ +describe :enumerable_minmax, shared: true do + it "min should return the minimum element" do + @enum.minmax.should == [4, 10] + @strs.minmax.should == ["1010", "60"] + end + + it "returns the minimum when using a block rule" do + @enum.minmax {|a,b| b <=> a }.should == [10, 4] + @strs.minmax {|a,b| a.length <=> b.length }.should == ["2", "55555"] + end + + it "returns [nil, nil] for an empty Enumerable" do + @empty_enum.minmax.should == [nil, nil] + end + + it "raises a NoMethodError for elements without #<=>" do + -> { @incomparable_enum.minmax }.should raise_error(NoMethodError) + end + + it "raises an ArgumentError when elements are incompatible" do + -> { @incompatible_enum.minmax }.should raise_error(ArgumentError) + -> { @enum.minmax{ |a, b| nil } }.should raise_error(ArgumentError) + end +end diff --git a/spec/ruby/shared/enumerator/each.rb b/spec/ruby/shared/enumerator/each.rb deleted file mode 100644 index bbab86fed7..0000000000 --- a/spec/ruby/shared/enumerator/each.rb +++ /dev/null @@ -1,89 +0,0 @@ -# -*- encoding: us-ascii -*- - -describe :enum_each, shared: true do - before :each do - object_each_with_arguments = Object.new - def object_each_with_arguments.each_with_arguments(arg, *args) - yield arg, *args - :method_returned - end - - @enum_with_arguments = object_each_with_arguments.to_enum(:each_with_arguments, :arg0, :arg1, :arg2) - - @enum_with_yielder = Enumerator.new {|y| y.yield :ok} - end - - it "yields each element of self to the given block" do - acc = [] - [1,2,3].to_enum.each {|e| acc << e } - acc.should == [1,2,3] - end - - it "calls #each on the object given in the constructor by default" do - each = mock('each') - each.should_receive(:each) - each.to_enum.each {|e| e } - end - - it "calls #each on the underlying object until it's exhausted" do - each = mock('each') - each.should_receive(:each).and_yield(1).and_yield(2).and_yield(3) - acc = [] - each.to_enum.each {|e| acc << e } - acc.should == [1,2,3] - end - - it "calls the method given in the constructor instead of #each" do - each = mock('peach') - each.should_receive(:peach) - each.to_enum(:peach).each {|e| e } - end - - it "calls the method given in the constructor until it's exhausted" do - each = mock('each') - each.should_receive(:each).and_yield(1).and_yield(2).and_yield(3) - acc = [] - each.to_enum.each {|e| acc << e } - acc.should == [1,2,3] - end - - it "raises a NoMethodError if the object doesn't respond to #each" do - enum = Object.new.to_enum - lambda do - enum.each { |e| e } - end.should raise_error(NoMethodError) - end - - it "returns self if not given arguments and not given a block" do - @enum_with_arguments.each.should equal(@enum_with_arguments) - - @enum_with_yielder.each.should equal(@enum_with_yielder) - end - - it "returns the same value from receiver.each if block is given" do - @enum_with_arguments.each {}.should equal(:method_returned) - end - - it "passes given arguments at initialized to receiver.each" do - @enum_with_arguments.each.to_a.should == [[:arg0, :arg1, :arg2]] - end - - it "requires multiple arguments" do - Enumerator.instance_method(:each).arity.should < 0 - end - - it "appends given arguments to receiver.each" do - @enum_with_arguments.each(:each0, :each1).to_a.should == [[:arg0, :arg1, :arg2, :each0, :each1]] - @enum_with_arguments.each(:each2, :each3).to_a.should == [[:arg0, :arg1, :arg2, :each2, :each3]] - end - - it "returns the same value from receiver.each if block and arguments are given" do - @enum_with_arguments.each(:each1, :each2) {}.should equal(:method_returned) - end - - it "returns new Enumerator if given arguments but not given a block" do - ret = @enum_with_arguments.each 1 - ret.should be_an_instance_of(Enumerator) - ret.should_not equal(@enum_with_arguments) - end -end diff --git a/spec/ruby/shared/enumerator/enum_cons.rb b/spec/ruby/shared/enumerator/enum_cons.rb deleted file mode 100644 index 59eed949d8..0000000000 --- a/spec/ruby/shared/enumerator/enum_cons.rb +++ /dev/null @@ -1,12 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) -require File.expand_path('../../../fixtures/enumerator/classes', __FILE__) - -describe :enum_cons, shared: true do - it "returns an enumerator of the receiver with iteration of each_cons for each array of n concecutive elements" do - a = [] - enum = EnumSpecs::Numerous.new.enum_cons(3) - enum.each {|x| a << x} - enum.should be_an_instance_of(Enumerator) - a.should == [[2, 5, 3], [5, 3, 6], [3, 6, 1], [6, 1, 4]] - end -end diff --git a/spec/ruby/shared/enumerator/enum_for.rb b/spec/ruby/shared/enumerator/enum_for.rb deleted file mode 100644 index 9030ffbd7d..0000000000 --- a/spec/ruby/shared/enumerator/enum_for.rb +++ /dev/null @@ -1,50 +0,0 @@ -describe :enum_for, shared: true do - it "is defined in Kernel" do - Kernel.method_defined?(@method).should be_true - end - - it "returns a new enumerator" do - "abc".send(@method).should be_an_instance_of(Enumerator) - end - - it "defaults the first argument to :each" do - enum = [1,2].send(@method) - enum.map { |v| v }.should == [1,2].each { |v| v } - end - - it "exposes multi-arg yields as an array" do - o = Object.new - def o.each - yield :a - yield :b1, :b2 - yield [:c] - yield :d1, :d2 - yield :e1, :e2, :e3 - end - - enum = o.send(@method) - enum.next.should == :a - enum.next.should == [:b1, :b2] - enum.next.should == [:c] - enum.next.should == [:d1, :d2] - enum.next.should == [:e1, :e2, :e3] - end - - it "uses the passed block's value to calculate the size of the enumerator" do - Object.new.enum_for { 100 }.size.should == 100 - end - - it "defers the evaluation of the passed block until #size is called" do - ScratchPad.record [] - - enum = Object.new.enum_for do - ScratchPad << :called - 100 - end - - ScratchPad.recorded.should be_empty - - enum.size - ScratchPad.recorded.should == [:called] - end -end diff --git a/spec/ruby/shared/enumerator/new.rb b/spec/ruby/shared/enumerator/new.rb deleted file mode 100644 index 23ace99816..0000000000 --- a/spec/ruby/shared/enumerator/new.rb +++ /dev/null @@ -1,42 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :enum_new, shared: true do - it "creates a new custom enumerator with the given object, iterator and arguments" do - enum = Enumerator.new(1, :upto, 3) - enum.should be_an_instance_of(Enumerator) - end - - it "creates a new custom enumerator that responds to #each" do - enum = Enumerator.new(1, :upto, 3) - enum.respond_to?(:each).should == true - end - - it "creates a new custom enumerator that runs correctly" do - Enumerator.new(1, :upto, 3).map{|x|x}.should == [1,2,3] - end - - it "aliases the second argument to :each" do - Enumerator.new(1..2).to_a.should == Enumerator.new(1..2, :each).to_a - end - - it "doesn't check for the presence of the iterator method" do - Enumerator.new(nil).should be_an_instance_of(Enumerator) - end - - it "uses the latest define iterator method" do - class StrangeEach - def each - yield :foo - end - end - enum = Enumerator.new(StrangeEach.new) - enum.to_a.should == [:foo] - class StrangeEach - def each - yield :bar - end - end - enum.to_a.should == [:bar] - end - -end diff --git a/spec/ruby/shared/enumerator/next.rb b/spec/ruby/shared/enumerator/next.rb deleted file mode 100644 index d8ae6d9673..0000000000 --- a/spec/ruby/shared/enumerator/next.rb +++ /dev/null @@ -1,28 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :enum_next, shared: true do - - before :each do - @enum = 1.upto(3) - end - - it "returns the next element of the enumeration" do - @enum.next.should == 1 - @enum.next.should == 2 - @enum.next.should == 3 - end - - it "raises a StopIteration exception at the end of the stream" do - 3.times { @enum.next } - lambda { @enum.next }.should raise_error(StopIteration) - end - - it "cannot be called again until the enumerator is rewound" do - 3.times { @enum.next } - lambda { @enum.next }.should raise_error(StopIteration) - lambda { @enum.next }.should raise_error(StopIteration) - lambda { @enum.next }.should raise_error(StopIteration) - @enum.rewind - @enum.next.should == 1 - end -end diff --git a/spec/ruby/shared/enumerator/rewind.rb b/spec/ruby/shared/enumerator/rewind.rb deleted file mode 100644 index 4d4139204c..0000000000 --- a/spec/ruby/shared/enumerator/rewind.rb +++ /dev/null @@ -1,39 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :enum_rewind, shared: true do - - before :each do - @enum = 1.upto(3) - end - - it "resets the enumerator to its initial state" do - @enum.next.should == 1 - @enum.next.should == 2 - @enum.rewind - @enum.next.should == 1 - end - - it "returns self" do - @enum.rewind.should == @enum - end - - it "has no effect on a new enumerator" do - @enum.rewind - @enum.next.should == 1 - end - - it "has no effect if called multiple, consecutive times" do - @enum.next.should == 1 - @enum.rewind - @enum.rewind - @enum.next.should == 1 - end - - it "works with peek to reset the position" do - @enum.next - @enum.next - @enum.rewind - @enum.next - @enum.peek.should == 2 - end -end diff --git a/spec/ruby/shared/enumerator/with_index.rb b/spec/ruby/shared/enumerator/with_index.rb deleted file mode 100644 index 37048a7b52..0000000000 --- a/spec/ruby/shared/enumerator/with_index.rb +++ /dev/null @@ -1,32 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :enum_with_index, shared: true do - - require File.expand_path('../../../fixtures/enumerator/classes', __FILE__) - - before :each do - @enum = [1, 2, 3, 4].to_enum - end - - it "passes each element and its index to block" do - @a = [] - @enum.send(@method) { |o, i| @a << [o, i] } - @a.should == [[1, 0], [2, 1], [3, 2], [4, 3]] - end - - it "returns the object being enumerated when given a block" do - [1, 2, 3, 4].should == @enum.send(@method) { |o, i| :glark } - end - - it "binds splat arguments properly" do - acc = [] - @enum.send(@method) { |*b| c,d = b; acc << c; acc << d } - [1, 0, 2, 1, 3, 2, 4, 3].should == acc - end - - it "returns an enumerator if no block is supplied" do - ewi = @enum.send(@method) - ewi.should be_an_instance_of(Enumerator) - ewi.to_a.should == [[1, 0], [2, 1], [3, 2], [4, 3]] - end -end diff --git a/spec/ruby/shared/enumerator/with_object.rb b/spec/ruby/shared/enumerator/with_object.rb deleted file mode 100644 index 1830736713..0000000000 --- a/spec/ruby/shared/enumerator/with_object.rb +++ /dev/null @@ -1,42 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :enum_with_object, shared: true do - before :each do - @enum = [:a, :b].to_enum - @memo = '' - @block_params = @enum.send(@method, @memo).to_a - end - - it "receives an argument" do - @enum.method(@method).arity.should == 1 - end - - context "with block" do - it "returns the given object" do - ret = @enum.send(@method, @memo) do |elm, memo| - # nothing - end - ret.should equal(@memo) - end - - context "the block parameter" do - it "passes each element to first parameter" do - @block_params[0][0].should equal(:a) - @block_params[1][0].should equal(:b) - end - - it "passes the given object to last parameter" do - @block_params[0][1].should equal(@memo) - @block_params[1][1].should equal(@memo) - end - end - end - - context "without block" do - it "returns new Enumerator" do - ret = @enum.send(@method, @memo) - ret.should be_an_instance_of(Enumerator) - ret.should_not equal(@enum) - end - end -end diff --git a/spec/ruby/shared/fiber/resume.rb b/spec/ruby/shared/fiber/resume.rb deleted file mode 100644 index 058ef4e15a..0000000000 --- a/spec/ruby/shared/fiber/resume.rb +++ /dev/null @@ -1,82 +0,0 @@ -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 the Fiber tries to resume itself" do - fiber = Fiber.new { fiber.resume } - -> { fiber.resume }.should raise_error(FiberError, /double resume/) - end - - it "raises a FiberError if invoked from a different Thread" do - fiber = Fiber.new { 42 } - Thread.new do - -> { - fiber.resume - }.should raise_error(FiberError) - end.join - fiber.resume.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 "runs until Fiber.yield" do - obj = mock('obj') - obj.should_not_receive(:do) - fiber = Fiber.new { 1 + 2; Fiber.yield; obj.do } - fiber.send(@method) - end - - it "resumes from the last call to Fiber.yield on subsequent invocations" do - fiber = Fiber.new { Fiber.yield :first; :second } - fiber.send(@method).should == :first - fiber.send(@method).should == :second - end - - it "accepts any number of arguments" do - fiber = Fiber.new { |a| } - lambda { fiber.send(@method, *(1..10).to_a) }.should_not raise_error - end - - it "sets the block parameters to its arguments on the first invocation" do - first = mock('first') - first.should_receive(:arg).with(:first).twice - fiber = Fiber.new { |arg| first.arg arg; Fiber.yield; first.arg arg; } - fiber.send(@method, :first) - fiber.send(@method, :second) - end - - it "raises a FiberError if the Fiber is dead" do - fiber = Fiber.new { true } - fiber.send(@method) - lambda { fiber.send(@method) }.should raise_error(FiberError) - end - - it "raises a LocalJumpError if the block includes a return statement" do - fiber = Fiber.new { return; } - lambda { fiber.send(@method) }.should raise_error(LocalJumpError) - end - - it "raises a LocalJumpError if the block includes a break statement" do - fiber = Fiber.new { break; } - lambda { fiber.send(@method) }.should raise_error(LocalJumpError) - end -end diff --git a/spec/ruby/shared/file/directory.rb b/spec/ruby/shared/file/directory.rb index 67e939bf16..8ba933a601 100644 --- a/spec/ruby/shared/file/directory.rb +++ b/spec/ruby/shared/file/directory.rb @@ -24,12 +24,12 @@ describe :file_directory, shared: true do end it "raises a TypeError when passed an Integer" do - lambda { @object.send(@method, 1) }.should raise_error(TypeError) - lambda { @object.send(@method, bignum_value) }.should raise_error(TypeError) + -> { @object.send(@method, 1) }.should raise_error(TypeError) + -> { @object.send(@method, bignum_value) }.should raise_error(TypeError) end it "raises a TypeError when passed nil" do - lambda { @object.send(@method, nil) }.should raise_error(TypeError) + -> { @object.send(@method, nil) }.should raise_error(TypeError) end end diff --git a/spec/ruby/shared/file/executable.rb b/spec/ruby/shared/file/executable.rb index 5b21fb0d97..baa156de98 100644 --- a/spec/ruby/shared/file/executable.rb +++ b/spec/ruby/shared/file/executable.rb @@ -13,7 +13,7 @@ describe :file_executable, shared: true do rm_r @file1, @file2 end - platform_is_not :windows do + platform_is_not :windows, :android do it "returns true if named file is executable by the effective user id of the process, otherwise false" do @object.send(@method, '/etc/passwd').should == false @object.send(@method, @file1).should == true @@ -31,13 +31,48 @@ describe :file_executable, shared: true do end it "raises an ArgumentError if not passed one argument" do - lambda { @object.send(@method) }.should raise_error(ArgumentError) + -> { @object.send(@method) }.should raise_error(ArgumentError) end it "raises a TypeError if not passed a String type" do - lambda { @object.send(@method, 1) }.should raise_error(TypeError) - lambda { @object.send(@method, nil) }.should raise_error(TypeError) - lambda { @object.send(@method, false) }.should raise_error(TypeError) + -> { @object.send(@method, 1) }.should raise_error(TypeError) + -> { @object.send(@method, nil) }.should raise_error(TypeError) + -> { @object.send(@method, false) }.should raise_error(TypeError) + end + + platform_is_not :windows do + as_superuser do + context "when run by a superuser" do + before :each do + @file = tmp('temp3.txt') + touch @file + end + + after :each do + rm_r @file + end + + it "returns true if file owner has permission to execute" do + File.chmod(0766, @file) + @object.send(@method, @file).should == true + end + + it "returns true if group has permission to execute" do + File.chmod(0676, @file) + @object.send(@method, @file).should == true + end + + it "returns true if other have permission to execute" do + File.chmod(0667, @file) + @object.send(@method, @file).should == true + end + + it "return false if nobody has permission to execute" do + File.chmod(0666, @file) + @object.send(@method, @file).should == false + end + end + end end end diff --git a/spec/ruby/shared/file/executable_real.rb b/spec/ruby/shared/file/executable_real.rb index 2b1bf8f585..bf2734ea07 100644 --- a/spec/ruby/shared/file/executable_real.rb +++ b/spec/ruby/shared/file/executable_real.rb @@ -29,13 +29,48 @@ describe :file_executable_real, shared: true do end it "raises an ArgumentError if not passed one argument" do - lambda { @object.send(@method) }.should raise_error(ArgumentError) + -> { @object.send(@method) }.should raise_error(ArgumentError) end it "raises a TypeError if not passed a String type" do - lambda { @object.send(@method, 1) }.should raise_error(TypeError) - lambda { @object.send(@method, nil) }.should raise_error(TypeError) - lambda { @object.send(@method, false) }.should raise_error(TypeError) + -> { @object.send(@method, 1) }.should raise_error(TypeError) + -> { @object.send(@method, nil) }.should raise_error(TypeError) + -> { @object.send(@method, false) }.should raise_error(TypeError) + end + + platform_is_not :windows do + as_real_superuser do + context "when run by a real superuser" do + before :each do + @file = tmp('temp3.txt') + touch @file + end + + after :each do + rm_r @file + end + + it "returns true if file owner has permission to execute" do + File.chmod(0766, @file) + @object.send(@method, @file).should == true + end + + it "returns true if group has permission to execute" do + File.chmod(0676, @file) + @object.send(@method, @file).should == true + end + + it "returns true if other have permission to execute" do + File.chmod(0667, @file) + @object.send(@method, @file).should == true + end + + it "return false if nobody has permission to execute" do + File.chmod(0666, @file) + @object.send(@method, @file).should == false + end + end + end end end diff --git a/spec/ruby/shared/file/exist.rb b/spec/ruby/shared/file/exist.rb index 1557f01a82..67424146c5 100644 --- a/spec/ruby/shared/file/exist.rb +++ b/spec/ruby/shared/file/exist.rb @@ -4,18 +4,13 @@ describe :file_exist, shared: true do @object.send(@method, 'a_fake_file').should == false end - it "returns true if the file exist using the alias exists?" do - @object.send(@method, __FILE__).should == true - @object.send(@method, 'a_fake_file').should == false - end - it "raises an ArgumentError if not passed one argument" do - lambda { @object.send(@method) }.should raise_error(ArgumentError) - lambda { @object.send(@method, __FILE__, __FILE__) }.should raise_error(ArgumentError) + -> { @object.send(@method) }.should raise_error(ArgumentError) + -> { @object.send(@method, __FILE__, __FILE__) }.should raise_error(ArgumentError) end it "raises a TypeError if not passed a String type" do - lambda { @object.send(@method, nil) }.should raise_error(TypeError) + -> { @object.send(@method, nil) }.should raise_error(TypeError) end it "accepts an object that has a #to_path method" do diff --git a/spec/ruby/shared/file/file.rb b/spec/ruby/shared/file/file.rb index 095bd63fff..c1748a88b3 100644 --- a/spec/ruby/shared/file/file.rb +++ b/spec/ruby/shared/file/file.rb @@ -34,12 +34,12 @@ describe :file_file, shared: true do end it "raises an ArgumentError if not passed one argument" do - lambda { @object.send(@method) }.should raise_error(ArgumentError) - lambda { @object.send(@method, @null, @file) }.should raise_error(ArgumentError) + -> { @object.send(@method) }.should raise_error(ArgumentError) + -> { @object.send(@method, @null, @file) }.should raise_error(ArgumentError) end it "raises a TypeError if not passed a String type" do - lambda { @object.send(@method, nil) }.should raise_error(TypeError) - lambda { @object.send(@method, 1) }.should raise_error(TypeError) + -> { @object.send(@method, nil) }.should raise_error(TypeError) + -> { @object.send(@method, 1) }.should raise_error(TypeError) end end diff --git a/spec/ruby/shared/file/grpowned.rb b/spec/ruby/shared/file/grpowned.rb index 91a6483030..24e84c28e3 100644 --- a/spec/ruby/shared/file/grpowned.rb +++ b/spec/ruby/shared/file/grpowned.rb @@ -26,8 +26,7 @@ describe :file_grpowned, shared: true do @object.send(@method, @file).should == true else - # No supplementary groups - 1.should == 1 + skip "No supplementary groups" end end end diff --git a/spec/ruby/shared/file/identical.rb b/spec/ruby/shared/file/identical.rb index e89cd309ea..b7a2904839 100644 --- a/spec/ruby/shared/file/identical.rb +++ b/spec/ruby/shared/file/identical.rb @@ -9,7 +9,11 @@ describe :file_identical, shared: true do touch(@file2) { |f| f.puts "file2" } rm_r @link - File.link(@file1, @link) + begin + File.link(@file1, @link) + rescue Errno::EACCES + File.symlink(@file1, @link) + end end after :each do @@ -31,12 +35,12 @@ describe :file_identical, shared: true do end it "raises an ArgumentError if not passed two arguments" do - lambda { @object.send(@method, @file1, @file2, @link) }.should raise_error(ArgumentError) - lambda { @object.send(@method, @file1) }.should raise_error(ArgumentError) + -> { @object.send(@method, @file1, @file2, @link) }.should raise_error(ArgumentError) + -> { @object.send(@method, @file1) }.should raise_error(ArgumentError) end it "raises a TypeError if not passed String types" do - lambda { @object.send(@method, 1,1) }.should raise_error(TypeError) + -> { @object.send(@method, 1,1) }.should raise_error(TypeError) end it "returns true if both named files are identical" do diff --git a/spec/ruby/shared/file/readable.rb b/spec/ruby/shared/file/readable.rb index 74f58caaff..7b45e23e36 100644 --- a/spec/ruby/shared/file/readable.rb +++ b/spec/ruby/shared/file/readable.rb @@ -4,9 +4,12 @@ describe :file_readable, shared: true do platform_is :windows do @file2 = File.join(ENV["WINDIR"], "system32/drivers/etc/services").tr(File::SEPARATOR, File::ALT_SEPARATOR) end - platform_is_not :windows do + platform_is_not :windows, :android do @file2 = "/etc/passwd" end + platform_is :android do + @file2 = "/system/bin/sh" + end end after :each do @@ -21,6 +24,22 @@ describe :file_readable, shared: true do it "accepts an object that has a #to_path method" do @object.send(@method, mock_to_path(@file2)).should == true end + + platform_is_not :windows do + as_superuser do + context "when run by a superuser" do + it "returns true unconditionally" do + file = tmp('temp.txt') + touch file + + File.chmod(0333, file) + @object.send(@method, file).should == true + + rm_r file + end + end + end + end end describe :file_readable_missing, shared: true do diff --git a/spec/ruby/shared/file/readable_real.rb b/spec/ruby/shared/file/readable_real.rb index b6e53ac76d..32d38bc7a2 100644 --- a/spec/ruby/shared/file/readable_real.rb +++ b/spec/ruby/shared/file/readable_real.rb @@ -14,6 +14,22 @@ describe :file_readable_real, shared: true do it "accepts an object that has a #to_path method" do File.open(@file,'w') { @object.send(@method, mock_to_path(@file)).should == true } end + + platform_is_not :windows do + as_real_superuser do + context "when run by a real superuser" do + it "returns true unconditionally" do + file = tmp('temp.txt') + touch file + + File.chmod(0333, file) + @object.send(@method, file).should == true + + rm_r file + end + end + end + end end describe :file_readable_real_missing, shared: true do diff --git a/spec/ruby/shared/file/size.rb b/spec/ruby/shared/file/size.rb index bb95190fc0..cba99fe6a5 100644 --- a/spec/ruby/shared/file/size.rb +++ b/spec/ruby/shared/file/size.rb @@ -56,7 +56,7 @@ describe :file_size_raise_when_missing, shared: true do end it "raises an error if file_name doesn't exist" do - lambda {@object.send(@method, @missing)}.should raise_error(Errno::ENOENT) + -> {@object.send(@method, @missing)}.should raise_error(Errno::ENOENT) end end @@ -72,7 +72,7 @@ describe :file_size_nil_when_missing, shared: true do end it "returns nil if file_name doesn't exist or has 0 size" do - @object.send(@method, @missing).should == nil + @object.send(@method, @missing).should == nil end end diff --git a/spec/ruby/shared/file/socket.rb b/spec/ruby/shared/file/socket.rb index 55a1cfd284..ef6c482d1c 100644 --- a/spec/ruby/shared/file/socket.rb +++ b/spec/ruby/shared/file/socket.rb @@ -1,3 +1,33 @@ describe :file_socket, shared: true do - it "accepts an object that has a #to_path method" + it "returns false if the file is not a socket" do + filename = tmp("i_exist") + touch(filename) + + @object.send(@method, filename).should == false + + rm_r filename + end + + it "returns true if the file is a socket" do + require 'socket' + + # We need a really short name here. + # On Linux the path length is limited to 107, see unix(7). + name = tmp("s") + server = UNIXServer.new(name) + + @object.send(@method, name).should == true + + server.close + rm_r name + end + + it "accepts an object that has a #to_path method" do + obj = Object.new + def obj.to_path + __FILE__ + end + + @object.send(@method, obj).should == false + end end diff --git a/spec/ruby/shared/file/sticky.rb b/spec/ruby/shared/file/sticky.rb index 38bb6ed26b..e07fa22fd7 100644 --- a/spec/ruby/shared/file/sticky.rb +++ b/spec/ruby/shared/file/sticky.rb @@ -8,7 +8,7 @@ describe :file_sticky, shared: true do Dir.rmdir(@dir) if File.exist?(@dir) end - platform_is_not :windows, :darwin, :freebsd, :netbsd, :openbsd, :solaris, :aix do + platform_is_not :windows, :darwin, :freebsd, :netbsd, :openbsd, :aix do it "returns true if the named file has the sticky bit, otherwise false" do Dir.mkdir @dir, 01755 diff --git a/spec/ruby/shared/file/world_readable.rb b/spec/ruby/shared/file/world_readable.rb index 0fddf98b73..1dce7a580f 100644 --- a/spec/ruby/shared/file/world_readable.rb +++ b/spec/ruby/shared/file/world_readable.rb @@ -1,4 +1,4 @@ -require File.expand_path('../../../spec_helper', __FILE__) +require_relative '../../spec_helper' describe :file_world_readable, shared: true do @@ -28,18 +28,18 @@ describe :file_world_readable, shared: true do end end - # We don't specify what the Fixnum is because it's system dependent - it "returns a Fixnum if the file is chmod 644" do + # We don't specify what the Integer is because it's system dependent + it "returns an Integer if the file is chmod 644" do File.chmod(0644, @file) - @object.world_readable?(@file).should be_an_instance_of(Fixnum) + @object.world_readable?(@file).should be_an_instance_of(Integer) end - it "returns a Fixnum if the file is a directory and chmod 644" do - dir = rand().to_s + '-ww' + it "returns an Integer if the file is a directory and chmod 644" do + dir = tmp(rand().to_s + '-ww') Dir.mkdir(dir) - Dir.exist?(dir).should be_true + Dir.should.exist?(dir) File.chmod(0644, dir) - @object.world_readable?(dir).should be_an_instance_of(Fixnum) + @object.world_readable?(dir).should be_an_instance_of(Integer) Dir.rmdir(dir) end diff --git a/spec/ruby/shared/file/world_writable.rb b/spec/ruby/shared/file/world_writable.rb index 43ac23a997..7ed252dcf3 100644 --- a/spec/ruby/shared/file/world_writable.rb +++ b/spec/ruby/shared/file/world_writable.rb @@ -1,4 +1,4 @@ -require File.expand_path('../../../spec_helper', __FILE__) +require_relative '../../spec_helper' describe :file_world_writable, shared: true do @@ -27,18 +27,18 @@ describe :file_world_writable, shared: true do @object.world_writable?(@file).should be_nil end - # We don't specify what the Fixnum is because it's system dependent - it "returns a Fixnum if the file is chmod 777" do + # We don't specify what the Integer is because it's system dependent + it "returns an Integer if the file is chmod 777" do File.chmod(0777, @file) - @object.world_writable?(@file).should be_an_instance_of(Fixnum) + @object.world_writable?(@file).should be_an_instance_of(Integer) end - it "returns a Fixnum if the file is a directory and chmod 777" do - dir = rand().to_s + '-ww' + it "returns an Integer if the file is a directory and chmod 777" do + dir = tmp(rand().to_s + '-ww') Dir.mkdir(dir) - Dir.exist?(dir).should be_true + Dir.should.exist?(dir) File.chmod(0777, dir) - @object.world_writable?(dir).should be_an_instance_of(Fixnum) + @object.world_writable?(dir).should be_an_instance_of(Integer) Dir.rmdir(dir) end end diff --git a/spec/ruby/shared/file/writable.rb b/spec/ruby/shared/file/writable.rb index e8296928f3..65ea2c1781 100644 --- a/spec/ruby/shared/file/writable.rb +++ b/spec/ruby/shared/file/writable.rb @@ -8,8 +8,10 @@ describe :file_writable, shared: true do end it "returns true if named file is writable by the effective user id of the process, otherwise false" do - platform_is_not :windows do - @object.send(@method, "/etc/passwd").should == false + platform_is_not :windows, :android do + as_user do + @object.send(@method, "/etc/passwd").should == false + end end File.open(@file,'w') { @object.send(@method, @file).should == true } end @@ -17,6 +19,22 @@ describe :file_writable, shared: true do it "accepts an object that has a #to_path method" do File.open(@file,'w') { @object.send(@method, mock_to_path(@file)).should == true } end + + platform_is_not :windows do + as_superuser do + context "when run by a superuser" do + it "returns true unconditionally" do + file = tmp('temp.txt') + touch file + + File.chmod(0555, file) + @object.send(@method, file).should == true + + rm_r file + end + end + end + end end describe :file_writable_missing, shared: true do diff --git a/spec/ruby/shared/file/writable_real.rb b/spec/ruby/shared/file/writable_real.rb index 3730befb7a..b4a0a58c6e 100644 --- a/spec/ruby/shared/file/writable_real.rb +++ b/spec/ruby/shared/file/writable_real.rb @@ -16,13 +16,29 @@ describe :file_writable_real, shared: true do end it "raises an ArgumentError if not passed one argument" do - lambda { File.writable_real? }.should raise_error(ArgumentError) + -> { File.writable_real? }.should raise_error(ArgumentError) end it "raises a TypeError if not passed a String type" do - lambda { @object.send(@method, 1) }.should raise_error(TypeError) - lambda { @object.send(@method, nil) }.should raise_error(TypeError) - lambda { @object.send(@method, false) }.should raise_error(TypeError) + -> { @object.send(@method, 1) }.should raise_error(TypeError) + -> { @object.send(@method, nil) }.should raise_error(TypeError) + -> { @object.send(@method, false) }.should raise_error(TypeError) + end + + platform_is_not :windows do + as_real_superuser do + context "when run by a real superuser" do + it "returns true unconditionally" do + file = tmp('temp.txt') + touch file + + File.chmod(0555, file) + @object.send(@method, file).should == true + + rm_r file + end + end + end end end diff --git a/spec/ruby/shared/file/zero.rb b/spec/ruby/shared/file/zero.rb index cf014d4722..6a9399a021 100644 --- a/spec/ruby/shared/file/zero.rb +++ b/spec/ruby/shared/file/zero.rb @@ -40,13 +40,13 @@ describe :file_zero, shared: true do end it "raises an ArgumentError if not passed one argument" do - lambda { File.zero? }.should raise_error(ArgumentError) + -> { File.zero? }.should raise_error(ArgumentError) end it "raises a TypeError if not passed a String type" do - lambda { @object.send(@method, nil) }.should raise_error(TypeError) - lambda { @object.send(@method, true) }.should raise_error(TypeError) - lambda { @object.send(@method, false) }.should raise_error(TypeError) + -> { @object.send(@method, nil) }.should raise_error(TypeError) + -> { @object.send(@method, true) }.should raise_error(TypeError) + -> { @object.send(@method, false) }.should raise_error(TypeError) end it "returns true inside a block opening a file if it is empty" do diff --git a/spec/ruby/shared/hash/key_error.rb b/spec/ruby/shared/hash/key_error.rb new file mode 100644 index 0000000000..54dcb89e91 --- /dev/null +++ b/spec/ruby/shared/hash/key_error.rb @@ -0,0 +1,23 @@ +describe :key_error, shared: true do + it "raises a KeyError" do + -> { + @method.call(@object, 'foo') + }.should raise_error(KeyError) + end + + it "sets the Hash as the receiver of KeyError" do + -> { + @method.call(@object, 'foo') + }.should raise_error(KeyError) { |err| + err.receiver.should equal(@object) + } + end + + it "sets the unmatched key as the key of KeyError" do + -> { + @method.call(@object, 'foo') + }.should raise_error(KeyError) { |err| + err.key.to_s.should == 'foo' + } + end +end diff --git a/spec/ruby/shared/io/putc.rb b/spec/ruby/shared/io/putc.rb index 5f620f183f..cdf18ac9fd 100644 --- a/spec/ruby/shared/io/putc.rb +++ b/spec/ruby/shared/io/putc.rb @@ -1,4 +1,4 @@ -# -*- encoding: ascii-8bit -*- +# encoding: binary describe :io_putc, shared: true do after :each do @io.close if @io && !@io.closed? @@ -6,7 +6,7 @@ describe :io_putc, shared: true do rm_r @name end - describe "with a Fixnum argument" do + describe "with an Integer argument" do it "writes one character as a String" do @io.should_receive(:write).with("A") @io_object.send(@method, 65).should == 65 @@ -40,18 +40,18 @@ describe :io_putc, shared: true do it "raises IOError on a closed stream" do @io.close - lambda { @io_object.send(@method, "a") }.should raise_error(IOError) + -> { @io_object.send(@method, "a") }.should raise_error(IOError) end it "raises a TypeError when passed nil" do - lambda { @io_object.send(@method, nil) }.should raise_error(TypeError) + -> { @io_object.send(@method, nil) }.should raise_error(TypeError) end it "raises a TypeError when passed false" do - lambda { @io_object.send(@method, false) }.should raise_error(TypeError) + -> { @io_object.send(@method, false) }.should raise_error(TypeError) end it "raises a TypeError when passed true" do - lambda { @io_object.send(@method, true) }.should raise_error(TypeError) + -> { @io_object.send(@method, true) }.should raise_error(TypeError) end end diff --git a/spec/ruby/shared/kernel/at_exit.rb b/spec/ruby/shared/kernel/at_exit.rb new file mode 100644 index 0000000000..29db79bb39 --- /dev/null +++ b/spec/ruby/shared/kernel/at_exit.rb @@ -0,0 +1,76 @@ +describe :kernel_at_exit, shared: true do + it "runs after all other code" do + ruby_exe("#{@method} { print 5 }; print 6").should == "65" + end + + it "runs in reverse order of registration" do + code = "#{@method} { print 4 }; #{@method} { print 5 }; print 6; #{@method} { print 7 }" + ruby_exe(code).should == "6754" + end + + it "allows calling exit inside a handler" do + code = "#{@method} { print 3 }; #{@method} { print 4; exit; print 5 }; #{@method} { print 6 }" + ruby_exe(code).should == "643" + end + + it "gives access to the last raised exception - global variables $! and $@" do + code = <<-EOC + #{@method} { + puts "The exception matches: \#{$! == $exception && $@ == $exception.backtrace} (message=\#{$!.message})" + } + + begin + raise "foo" + rescue => $exception + raise + end + EOC + + result = ruby_exe(code, args: "2>&1", exit_status: 1) + result.lines.should.include?("The exception matches: true (message=foo)\n") + end + + it "gives access to an exception raised in a previous handler" do + code = "#{@method} { print '$!.message = ' + $!.message }; #{@method} { raise 'foo' }" + result = ruby_exe(code, args: "2>&1", exit_status: 1) + result.lines.should.include?("$!.message = foo") + end + + it "both exceptions in a handler and in the main script are printed" do + code = "#{@method} { raise 'at_exit_error' }; raise 'main_script_error'" + result = ruby_exe(code, args: "2>&1", exit_status: 1) + result.should.include?('at_exit_error (RuntimeError)') + result.should.include?('main_script_error (RuntimeError)') + end + + it "decides the exit status if both at_exit and the main script raise SystemExit" do + ruby_exe("#{@method} { exit 43 }; exit 42", args: "2>&1", exit_status: 43) + $?.exitstatus.should == 43 + end + + it "runs all handlers even if some raise exceptions" do + code = "#{@method} { STDERR.puts 'last' }; #{@method} { exit 43 }; #{@method} { STDERR.puts 'first' }; exit 42" + result = ruby_exe(code, args: "2>&1", exit_status: 43) + result.should == "first\nlast\n" + $?.exitstatus.should == 43 + end + + it "runs handlers even if the main script fails to parse" do + script = fixture(__FILE__, "#{@method}.rb") + result = ruby_exe('{', options: "-r#{script}", args: "2>&1", exit_status: 1) + $?.should_not.success? + result.should.include?("handler ran\n") + + # it's tempting not to rely on error message and rely only on exception class name, + # but CRuby before 3.2 doesn't print class name for syntax error + result.should include_any_of("syntax error", "SyntaxError") + end + + it "calls the nested handler right after the outer one if a handler is nested into another handler" do + ruby_exe(<<~ruby).should == "last\nbefore\nafter\nnested\nfirst\n" + #{@method} { puts :first } + #{@method} { puts :before; #{@method} { puts :nested }; puts :after }; + #{@method} { puts :last } + ruby + end +end diff --git a/spec/ruby/shared/kernel/complex.rb b/spec/ruby/shared/kernel/complex.rb new file mode 100644 index 0000000000..98ee0b2b3f --- /dev/null +++ b/spec/ruby/shared/kernel/complex.rb @@ -0,0 +1,133 @@ +# Specs shared by Kernel#Complex() and String#to_c() +describe :kernel_complex, shared: true do + + it "returns a Complex object" do + @object.send(@method, '9').should be_an_instance_of(Complex) + end + + it "understands integers" do + @object.send(@method, '20').should == Complex(20) + end + + it "understands negative integers" do + @object.send(@method, '-3').should == Complex(-3) + end + + it "understands fractions (numerator/denominator) for the real part" do + @object.send(@method, '2/3').should == Complex(Rational(2, 3)) + end + + it "understands fractions (numerator/denominator) for the imaginary part" do + @object.send(@method, '4+2/3i').should == Complex(4, Rational(2, 3)) + end + + it "understands negative fractions (-numerator/denominator) for the real part" do + @object.send(@method, '-2/3').should == Complex(Rational(-2, 3)) + end + + it "understands negative fractions (-numerator/denominator) for the imaginary part" do + @object.send(@method, '7-2/3i').should == Complex(7, Rational(-2, 3)) + end + + it "understands floats (a.b) for the real part" do + @object.send(@method, '2.3').should == Complex(2.3) + end + + it "understands floats (a.b) for the imaginary part" do + @object.send(@method, '4+2.3i').should == Complex(4, 2.3) + end + + it "understands negative floats (-a.b) for the real part" do + @object.send(@method, '-2.33').should == Complex(-2.33) + end + + it "understands negative floats (-a.b) for the imaginary part" do + @object.send(@method, '7-28.771i').should == Complex(7, -28.771) + end + + it "understands an integer followed by 'i' to mean that integer is the imaginary part" do + @object.send(@method, '35i').should == Complex(0,35) + end + + it "understands a negative integer followed by 'i' to mean that negative integer is the imaginary part" do + @object.send(@method, '-29i').should == Complex(0,-29) + end + + it "understands an 'i' by itself as denoting a complex number with an imaginary part of 1" do + @object.send(@method, 'i').should == Complex(0,1) + end + + it "understands a '-i' by itself as denoting a complex number with an imaginary part of -1" do + @object.send(@method, '-i').should == Complex(0,-1) + end + + it "understands 'a+bi' to mean a complex number with 'a' as the real part, 'b' as the imaginary" do + @object.send(@method, '79+4i').should == Complex(79,4) + end + + it "understands 'a-bi' to mean a complex number with 'a' as the real part, '-b' as the imaginary" do + @object.send(@method, '79-4i').should == Complex(79,-4) + end + + it "understands 'a+i' to mean a complex number with 'a' as the real part, 1i as the imaginary" do + @object.send(@method, '79+i').should == Complex(79, 1) + end + + it "understands 'a-i' to mean a complex number with 'a' as the real part, -1i as the imaginary" do + @object.send(@method, '79-i').should == Complex(79, -1) + end + + it "understands i, I, j, and J imaginary units" do + @object.send(@method, '79+4i').should == Complex(79, 4) + @object.send(@method, '79+4I').should == Complex(79, 4) + @object.send(@method, '79+4j').should == Complex(79, 4) + @object.send(@method, '79+4J').should == Complex(79, 4) + end + + it "understands scientific notation for the real part" do + @object.send(@method, '2e3+4i').should == Complex(2e3,4) + end + + it "understands negative scientific notation for the real part" do + @object.send(@method, '-2e3+4i').should == Complex(-2e3,4) + end + + it "understands scientific notation for the imaginary part" do + @object.send(@method, '4+2e3i').should == Complex(4, 2e3) + end + + it "understands negative scientific notation for the imaginary part" do + @object.send(@method, '4-2e3i').should == Complex(4, -2e3) + end + + it "understands scientific notation for the real and imaginary part in the same String" do + @object.send(@method, '2e3+2e4i').should == Complex(2e3,2e4) + end + + it "understands negative scientific notation for the real and imaginary part in the same String" do + @object.send(@method, '-2e3-2e4i').should == Complex(-2e3,-2e4) + end + + it "understands scientific notation with e and E" do + @object.send(@method, '2e3+2e4i').should == Complex(2e3, 2e4) + @object.send(@method, '2E3+2E4i').should == Complex(2e3, 2e4) + end + + it "understands 'm@a' to mean a complex number in polar form with 'm' as the modulus, 'a' as the argument" do + @object.send(@method, '79@4').should == Complex.polar(79, 4) + @object.send(@method, '-79@4').should == Complex.polar(-79, 4) + @object.send(@method, '79@-4').should == Complex.polar(79, -4) + end + + it "ignores leading whitespaces" do + @object.send(@method, ' 79+4i').should == Complex(79, 4) + end + + it "ignores trailing whitespaces" do + @object.send(@method, '79+4i ').should == Complex(79, 4) + end + + it "understands _" do + @object.send(@method, '7_9+4_0i').should == Complex(79, 40) + end +end diff --git a/spec/ruby/shared/kernel/fixtures/END.rb b/spec/ruby/shared/kernel/fixtures/END.rb new file mode 100644 index 0000000000..cc8ac17c36 --- /dev/null +++ b/spec/ruby/shared/kernel/fixtures/END.rb @@ -0,0 +1,3 @@ +END { + STDERR.puts "handler ran" +} diff --git a/spec/ruby/shared/kernel/fixtures/at_exit.rb b/spec/ruby/shared/kernel/fixtures/at_exit.rb new file mode 100644 index 0000000000..e7bc8baf52 --- /dev/null +++ b/spec/ruby/shared/kernel/fixtures/at_exit.rb @@ -0,0 +1,3 @@ +at_exit do + STDERR.puts "handler ran" +end diff --git a/spec/ruby/shared/kernel/object_id.rb b/spec/ruby/shared/kernel/object_id.rb index 7acdb27554..099df8ff94 100644 --- a/spec/ruby/shared/kernel/object_id.rb +++ b/spec/ruby/shared/kernel/object_id.rb @@ -52,10 +52,30 @@ describe :object_id, shared: true do o1.send(@method).should_not == o2.send(@method) end - it "returns a different value for two String literals" do - o1 = "hello" - o2 = "hello" - o1.send(@method).should_not == o2.send(@method) + guard -> { "test".frozen? && "test".equal?("test") } do # --enable-frozen-string-literal in $RUBYOPT + it "returns the same value for two identical String literals" do + o1 = "hello" + o2 = "hello" + o1.send(@method).should == o2.send(@method) + end + end + + guard -> { "test".frozen? && !"test".equal?("test") } do # chilled string literals + it "returns a different frozen value for two String literals" do + o1 = "hello" + o2 = "hello" + o1.send(@method).should_not == o2.send(@method) + o1.frozen?.should == true + o2.frozen?.should == true + end + end + + guard -> { !"test".frozen? } do + it "returns a different value for two String literals" do + o1 = "hello" + o2 = "hello" + o1.send(@method).should_not == o2.send(@method) + end end it "returns a different value for an object and its dup" do diff --git a/spec/ruby/shared/kernel/raise.rb b/spec/ruby/shared/kernel/raise.rb index 70d638fff9..2be06ea797 100644 --- a/spec/ruby/shared/kernel/raise.rb +++ b/spec/ruby/shared/kernel/raise.rb @@ -4,7 +4,7 @@ describe :kernel_raise, shared: true do end it "aborts execution" do - lambda do + -> do @object.raise Exception, "abort" ScratchPad.record :no_abort end.should raise_error(Exception, "abort") @@ -12,57 +12,387 @@ describe :kernel_raise, shared: true do ScratchPad.recorded.should be_nil end + it "accepts an exception that implements to_hash" do + custom_error = Class.new(StandardError) do + def to_hash + {} + end + end + error = custom_error.new + -> { @object.raise(error) }.should raise_error(custom_error) + end + + it "allows the message parameter to be a hash" do + data_error = Class.new(StandardError) do + attr_reader :data + def initialize(data) + @data = data + end + end + + -> { @object.raise(data_error, {data: 42}) }.should raise_error(data_error) do |ex| + ex.data.should == {data: 42} + end + end + + # https://bugs.ruby-lang.org/issues/8257#note-36 + it "allows extra keyword arguments for compatibility" do + data_error = Class.new(StandardError) do + attr_reader :data + def initialize(data) + @data = data + end + end + + -> { @object.raise(data_error, data: 42) }.should raise_error(data_error) do |ex| + ex.data.should == {data: 42} + end + end + it "raises RuntimeError if no exception class is given" do - lambda { @object.raise }.should raise_error(RuntimeError) + -> { @object.raise }.should raise_error(RuntimeError, "") end it "raises a given Exception instance" do error = RuntimeError.new - lambda { @object.raise(error) }.should raise_error(error) + -> { @object.raise(error) }.should raise_error(error) end it "raises a RuntimeError if string given" do - lambda { @object.raise("a bad thing") }.should raise_error(RuntimeError) + -> { @object.raise("a bad thing") }.should raise_error(RuntimeError, "a bad thing") + end + + it "passes no arguments to the constructor when given only an exception class" do + klass = Class.new(Exception) do + def initialize + end + end + -> { @object.raise(klass) }.should raise_error(klass) { |e| e.message.should == klass.to_s } end it "raises a TypeError when passed a non-Exception object" do - lambda { @object.raise(Object.new) }.should raise_error(TypeError) + -> { @object.raise(Object.new) }.should raise_error(TypeError, "exception class/object expected") + -> { @object.raise(Object.new, "message") }.should raise_error(TypeError, "exception class/object expected") + -> { @object.raise(Object.new, "message", []) }.should raise_error(TypeError, "exception class/object expected") end it "raises a TypeError when passed true" do - lambda { @object.raise(true) }.should raise_error(TypeError) + -> { @object.raise(true) }.should raise_error(TypeError, "exception class/object expected") end it "raises a TypeError when passed false" do - lambda { @object.raise(false) }.should raise_error(TypeError) + -> { @object.raise(false) }.should raise_error(TypeError, "exception class/object expected") end it "raises a TypeError when passed nil" do - lambda { @object.raise(nil) }.should raise_error(TypeError) + -> { @object.raise(nil) }.should raise_error(TypeError, "exception class/object expected") end - it "re-raises the rescued exception" do - lambda do - begin - raise Exception, "outer" - ScratchPad.record :no_abort - rescue - begin - raise StandardError, "inner" - rescue - end + it "raises a TypeError when passed a message and an extra argument" do + -> { @object.raise("message", {cause: RuntimeError.new()}) }.should raise_error(TypeError, "exception class/object expected") + end - @object.raise - ScratchPad.record :no_reraise - end - end.should raise_error(Exception, "outer") + it "raises TypeError when passed a non-Exception object but it responds to #exception method that doesn't return an instance of Exception class" do + e = Object.new + def e.exception + Array + end - ScratchPad.recorded.should be_nil + -> { + @object.raise e + }.should raise_error(TypeError, "exception object expected") + end + + it "re-raises a previously rescued exception without overwriting the backtrace" do + exception = nil + + begin + raise "raised" + rescue => exception + # Ignore. + end + + backtrace = exception.backtrace + + begin + raised_exception = @object.raise(exception) + rescue => raised_exception + # Ignore. + end + + raised_exception.backtrace.should == backtrace + raised_exception.should == exception end it "allows Exception, message, and backtrace parameters" do - lambda do + -> do @object.raise(ArgumentError, "message", caller) end.should raise_error(ArgumentError, "message") end + + ruby_version_is "3.4" do + locations = caller_locations(1, 2) + it "allows Exception, message, and backtrace_locations parameters" do + -> do + @object.raise(ArgumentError, "message", locations) + end.should raise_error(ArgumentError, "message") { |error| + error.backtrace_locations.map(&:to_s).should == locations.map(&:to_s) + } + end + end + + ruby_version_is "4.0" do + it "allows cause keyword argument" do + cause = StandardError.new("original error") + result = nil + + -> do + @object.raise("new error", cause: cause) + end.should raise_error(RuntimeError, "new error") do |error| + error.cause.should == cause + end + end + + it "raises an ArgumentError when only cause is given" do + cause = StandardError.new("cause") + -> do + @object.raise(cause: cause) + end.should raise_error(ArgumentError, "only cause is given with no arguments") + end + + it "raises an ArgumentError when only cause is given and is nil" do + -> do + @object.raise(cause: nil) + end.should raise_error(ArgumentError, "only cause is given with no arguments") + end + + it "raises a TypeError when given cause is not an instance of Exception" do + cause = Object.new + -> do + @object.raise("message", cause: cause) + end.should raise_error(TypeError, "exception object expected") + end + + it "doesn't set given cause when it equals the raised exception" do + cause = StandardError.new("cause") + result = nil + + -> do + @object.raise(cause, cause: cause) + end.should raise_error(StandardError, "cause") do |error| + error.should == cause + error.cause.should == nil + end + end + + it "accepts cause equal an exception" do + error = RuntimeError.new("message") + result = nil + + -> do + @object.raise(error, cause: error) + end.should raise_error(RuntimeError, "message") do |e| + e.cause.should == nil + end + end + + it "rejects circular causes" do + -> { + begin + raise "Error 1" + rescue => error1 + begin + raise "Error 2" + rescue => error2 + begin + raise "Error 3" + rescue => error3 + @object.raise(error1, cause: error3) + end + end + end + }.should raise_error(ArgumentError, "circular causes") + end + + it "supports exception class with message and cause" do + cause = StandardError.new("cause message") + result = nil + + -> do + @object.raise(ArgumentError, "argument error message", cause: cause) + end.should raise_error(ArgumentError, "argument error message") do |error| + error.should be_kind_of(ArgumentError) + error.message.should == "argument error message" + error.cause.should == cause + end + end + + it "supports exception class with message, backtrace and cause" do + cause = StandardError.new("cause message") + backtrace = ["line1", "line2"] + result = nil + + -> do + @object.raise(ArgumentError, "argument error message", backtrace, cause: cause) + end.should raise_error(ArgumentError, "argument error message") do |error| + error.should be_kind_of(ArgumentError) + error.message.should == "argument error message" + error.cause.should == cause + error.backtrace.should == backtrace + end + end + + it "supports automatic cause chaining" do + -> do + begin + raise "first error" + rescue + # No explicit cause - should chain automatically: + @object.raise("second error") + end + end.should raise_error(RuntimeError, "second error") do |error| + error.cause.should be_kind_of(RuntimeError) + error.cause.message.should == "first error" + end + end + + it "supports cause: nil to prevent automatic cause chaining" do + -> do + begin + raise "first error" + rescue + # Explicit nil prevents chaining: + @object.raise("second error", cause: nil) + end + end.should raise_error(RuntimeError, "second error") do |error| + error.cause.should == nil + end + end + end +end + +describe :kernel_raise_across_contexts, shared: true do + ruby_version_is "4.0" do + describe "with cause keyword argument" do + it "uses the cause from the calling context" do + original_cause = nil + result = nil + + # We have no cause ($!) and we don't specify one explicitly either: + @object.raise("second error") do |&block| + begin + begin + raise "first error" + rescue => original_cause + # We have a cause here ($!) but we should ignore it: + block.call + end + rescue => result + # Ignore. + end + end + + result.should be_kind_of(RuntimeError) + result.message.should == "second error" + result.cause.should == nil + end + + it "accepts a cause keyword argument that overrides the last exception" do + original_cause = nil + override_cause = StandardError.new("override cause") + result = nil + + begin + raise "outer error" + rescue + # We have an existing cause, but we want to override it: + @object.raise("second error", cause: override_cause) do |&block| + begin + begin + raise "first error" + rescue => original_cause + # We also have an existing cause here: + block.call + end + rescue => result + # Ignore. + end + end + end + + result.should be_kind_of(RuntimeError) + result.message.should == "second error" + result.cause.should == override_cause + end + + it "supports automatic cause chaining from calling context" do + result = nil + + @object.raise("new error") do |&block| + begin + begin + raise "original error" + rescue + block.call # Let the context yield/sleep + end + rescue => result + # Ignore. + end + end + + result.should be_kind_of(RuntimeError) + result.message.should == "new error" + # Calling context has no current exception: + result.cause.should == nil + end + + it "supports explicit cause: nil to prevent cause chaining" do + result = nil + + begin + raise "calling context error" + rescue + @object.raise("new error", cause: nil) do |&block| + begin + begin + raise "target context error" + rescue + block.call # Let the context yield/sleep + end + rescue => result + # Ignore. + end + end + + result.should be_kind_of(RuntimeError) + result.message.should == "new error" + result.cause.should == nil + end + end + + it "raises TypeError when cause is not an Exception" do + -> { + @object.raise("error", cause: "not an exception") do |&block| + begin + block.call # Let the context yield/sleep + rescue + # Ignore - we expect the TypeError to be raised in the calling context + end + end + }.should raise_error(TypeError, "exception object expected") + end + + it "raises ArgumentError when only cause is given with no arguments" do + -> { + @object.raise(cause: StandardError.new("cause")) do |&block| + begin + block.call # Let the context yield/sleep + rescue + # Ignore - we expect the ArgumentError to be raised in the calling context + end + end + }.should raise_error(ArgumentError, "only cause is given with no arguments") + end + end + end end diff --git a/spec/ruby/shared/math/atanh.rb b/spec/ruby/shared/math/atanh.rb deleted file mode 100644 index 1d1a6ebd74..0000000000 --- a/spec/ruby/shared/math/atanh.rb +++ /dev/null @@ -1,44 +0,0 @@ -describe :math_atanh_base, shared: true do - it "returns a float" do - @object.send(@method, 0.5).should be_an_instance_of(Float) - end - - it "returns the inverse hyperbolic tangent of the argument" do - @object.send(@method, 0.0).should == 0.0 - @object.send(@method, -0.0).should == -0.0 - @object.send(@method, 0.5).should be_close(0.549306144334055, TOLERANCE) - @object.send(@method, -0.2).should be_close(-0.202732554054082, TOLERANCE) - end - - it "raises a TypeError if the argument is nil" do - lambda { @object.send(@method, nil) }.should raise_error(TypeError) - end - - it "raises a TypeError if the argument is not a Numeric" do - lambda { @object.send(@method, "test") }.should raise_error(TypeError) - end - - it "returns Infinity if x == 1.0" do - @object.send(@method, 1.0).should == Float::INFINITY - end - - it "return -Infinity if x == -1.0" do - @object.send(@method, -1.0).should == -Float::INFINITY - end -end - -describe :math_atanh_private, shared: true do - it "is a private instance method" do - Math.should have_private_instance_method(@method) - end -end - -describe :math_atanh_no_complex, shared: true do - it "raises a Math::DomainError for arguments greater than 1.0" do - lambda { @object.send(@method, 1.0 + Float::EPSILON) }.should raise_error(Math::DomainError) - end - - it "raises a Math::DomainError for arguments less than -1.0" do - lambda { @object.send(@method, -1.0 - Float::EPSILON) }.should raise_error(Math::DomainError) - end -end diff --git a/spec/ruby/shared/process/abort.rb b/spec/ruby/shared/process/abort.rb index 1a25aeffc2..935637e1c2 100644 --- a/spec/ruby/shared/process/abort.rb +++ b/spec/ruby/shared/process/abort.rb @@ -8,29 +8,29 @@ describe :process_abort, shared: true do end it "raises a SystemExit exception" do - lambda { @object.abort }.should raise_error(SystemExit) + -> { @object.abort }.should raise_error(SystemExit) end it "sets the exception message to the given message" do - lambda { @object.abort "message" }.should raise_error { |e| e.message.should == "message" } + -> { @object.abort "message" }.should raise_error { |e| e.message.should == "message" } end it "sets the exception status code of 1" do - lambda { @object.abort }.should raise_error { |e| e.status.should == 1 } + -> { @object.abort }.should raise_error { |e| e.status.should == 1 } end it "prints the specified message to STDERR" do - lambda { @object.abort "a message" }.should raise_error(SystemExit) + -> { @object.abort "a message" }.should raise_error(SystemExit) $stderr.should =~ /a message/ end it "coerces the argument with #to_str" do str = mock('to_str') str.should_receive(:to_str).any_number_of_times.and_return("message") - lambda { @object.abort str }.should raise_error(SystemExit, "message") + -> { @object.abort str }.should raise_error(SystemExit, "message") end it "raises TypeError when given a non-String object" do - lambda { @object.abort 123 }.should raise_error(TypeError) + -> { @object.abort 123 }.should raise_error(TypeError) end end diff --git a/spec/ruby/shared/process/exit.rb b/spec/ruby/shared/process/exit.rb index 7d567c8195..1e073614a3 100644 --- a/spec/ruby/shared/process/exit.rb +++ b/spec/ruby/shared/process/exit.rb @@ -1,13 +1,13 @@ describe :process_exit, shared: true do it "raises a SystemExit with status 0" do - lambda { @object.exit }.should raise_error(SystemExit) { |e| + -> { @object.exit }.should raise_error(SystemExit) { |e| e.status.should == 0 } end it "raises a SystemExit with the specified status" do [-2**16, -2**8, -8, -1, 0, 1 , 8, 2**8, 2**16].each do |value| - lambda { @object.exit(value) }.should raise_error(SystemExit) { |e| + -> { @object.exit(value) }.should raise_error(SystemExit) { |e| e.status.should == value } end @@ -15,33 +15,39 @@ describe :process_exit, shared: true do it "raises a SystemExit with the specified boolean status" do { true => 0, false => 1 }.each do |value, status| - lambda { @object.exit(value) }.should raise_error(SystemExit) { |e| + -> { @object.exit(value) }.should raise_error(SystemExit) { |e| e.status.should == status } end end + it "raises a SystemExit with message 'exit'" do + -> { @object.exit }.should raise_error(SystemExit) { |e| + e.message.should == "exit" + } + end + it "tries to convert the passed argument to an Integer using #to_int" do obj = mock('5') obj.should_receive(:to_int).and_return(5) - lambda { @object.exit(obj) }.should raise_error(SystemExit) { |e| + -> { @object.exit(obj) }.should raise_error(SystemExit) { |e| e.status.should == 5 } end it "converts the passed Float argument to an Integer" do { -2.2 => -2, -0.1 => 0, 5.5 => 5, 827.999 => 827 }.each do |value, status| - lambda { @object.exit(value) }.should raise_error(SystemExit) { |e| + -> { @object.exit(value) }.should raise_error(SystemExit) { |e| e.status.should == status } end end it "raises TypeError if can't convert the argument to an Integer" do - lambda { @object.exit(Object.new) }.should raise_error(TypeError) - lambda { @object.exit('0') }.should raise_error(TypeError) - lambda { @object.exit([0]) }.should raise_error(TypeError) - lambda { @object.exit(nil) }.should raise_error(TypeError) + -> { @object.exit(Object.new) }.should raise_error(TypeError) + -> { @object.exit('0') }.should raise_error(TypeError) + -> { @object.exit([0]) }.should raise_error(TypeError) + -> { @object.exit(nil) }.should raise_error(TypeError) end it "raises the SystemExit in the main thread if it reaches the top-level handler of another thread" do @@ -69,26 +75,52 @@ describe :process_exit, shared: true do ScratchPad.recorded.should == [:in_thread, :in_main] # the thread also keeps the exception as its value - lambda { t.value }.should raise_error(SystemExit) + -> { t.value }.should raise_error(SystemExit) end end describe :process_exit!, shared: true do it "exits with the given status" do - out = ruby_exe("#{@object}.send(:exit!, 21)", args: '2>&1') + out = ruby_exe("#{@object}.send(:exit!, 21)", args: '2>&1', exit_status: 21) out.should == "" $?.exitstatus.should == 21 end it "exits when called from a thread" do - out = ruby_exe("Thread.new { #{@object}.send(:exit!, 21) }.join; sleep", args: '2>&1') + out = ruby_exe("Thread.new { #{@object}.send(:exit!, 21) }.join; sleep", args: '2>&1', exit_status: 21) out.should == "" $?.exitstatus.should == 21 end it "exits when called from a fiber" do - out = ruby_exe("Fiber.new { #{@object}.send(:exit!, 21) }.resume", args: '2>&1') + out = ruby_exe("Fiber.new { #{@object}.send(:exit!, 21) }.resume", args: '2>&1', exit_status: 21) + out.should == "" + $?.exitstatus.should == 21 + end + + it "skips at_exit handlers" do + out = ruby_exe("at_exit { STDERR.puts 'at_exit' }; #{@object}.send(:exit!, 21)", args: '2>&1', exit_status: 21) out.should == "" $?.exitstatus.should == 21 end + + it "skips ensure clauses" do + out = ruby_exe("begin; STDERR.puts 'before'; #{@object}.send(:exit!, 21); ensure; STDERR.puts 'ensure'; end", args: '2>&1', exit_status: 21) + out.should == "before\n" + $?.exitstatus.should == 21 + end + + it "overrides the original exception and exit status when called from #at_exit" do + code = <<-RUBY + at_exit do + STDERR.puts 'in at_exit' + STDERR.puts "$! is \#{$!.class}:\#{$!.message}" + #{@object}.send(:exit!, 21) + end + raise 'original error' + RUBY + out = ruby_exe(code, args: '2>&1', exit_status: 21) + out.should == "in at_exit\n$! is RuntimeError:original error\n" + $?.exitstatus.should == 21 + end end diff --git a/spec/ruby/shared/process/fork.rb b/spec/ruby/shared/process/fork.rb index c2c2aee9bf..8dbb3d0da4 100644 --- a/spec/ruby/shared/process/fork.rb +++ b/spec/ruby/shared/process/fork.rb @@ -8,7 +8,7 @@ describe :process_fork, shared: true do end it "raises a NotImplementedError when called" do - lambda { @object.fork }.should raise_error(NotImplementedError) + -> { @object.fork }.should raise_error(NotImplementedError) end end @@ -23,31 +23,31 @@ describe :process_fork, shared: true do end it "returns status zero" do - pid = Process.fork { exit! 0 } + pid = @object.fork { exit! 0 } _, result = Process.wait2(pid) result.exitstatus.should == 0 end it "returns status zero" do - pid = Process.fork { exit 0 } + pid = @object.fork { exit 0 } _, result = Process.wait2(pid) result.exitstatus.should == 0 end it "returns status zero" do - pid = Process.fork {} + pid = @object.fork {} _, result = Process.wait2(pid) result.exitstatus.should == 0 end it "returns status non-zero" do - pid = Process.fork { exit! 42 } + pid = @object.fork { exit! 42 } _, result = Process.wait2(pid) result.exitstatus.should == 42 end it "returns status non-zero" do - pid = Process.fork { exit 42 } + pid = @object.fork { exit 42 } _, result = Process.wait2(pid) result.exitstatus.should == 42 end @@ -60,7 +60,7 @@ describe :process_fork, shared: true do else Process.waitpid(child_id) end - File.exist?(@file).should == true + File.should.exist?(@file) end it "runs a block in a child process" do @@ -69,7 +69,7 @@ describe :process_fork, shared: true do Process.exit! } Process.waitpid(pid) - File.exist?(@file).should == true + File.should.exist?(@file) end it "marks threads from the parent as killed" do diff --git a/spec/ruby/shared/queue/clear.rb b/spec/ruby/shared/queue/clear.rb new file mode 100644 index 0000000000..5db5a5b497 --- /dev/null +++ b/spec/ruby/shared/queue/clear.rb @@ -0,0 +1,12 @@ +describe :queue_clear, shared: true do + it "removes all objects from the queue" do + queue = @object.call + queue << Object.new + queue << 1 + queue.empty?.should be_false + queue.clear + queue.empty?.should be_true + end + + # TODO: test for atomicity of Queue#clear +end diff --git a/spec/ruby/shared/queue/close.rb b/spec/ruby/shared/queue/close.rb new file mode 100644 index 0000000000..0e7c69acba --- /dev/null +++ b/spec/ruby/shared/queue/close.rb @@ -0,0 +1,14 @@ +describe :queue_close, shared: true do + it "may be called multiple times" do + q = @object.call + q.close + q.closed?.should be_true + q.close # no effect + q.closed?.should be_true + end + + it "returns self" do + q = @object.call + q.close.should == q + end +end diff --git a/spec/ruby/shared/queue/closed.rb b/spec/ruby/shared/queue/closed.rb new file mode 100644 index 0000000000..b3cea0c524 --- /dev/null +++ b/spec/ruby/shared/queue/closed.rb @@ -0,0 +1,12 @@ +describe :queue_closed?, shared: true do + it "returns false initially" do + queue = @object.call + queue.closed?.should be_false + end + + it "returns true when the queue is closed" do + queue = @object.call + queue.close + queue.closed?.should be_true + end +end diff --git a/spec/ruby/shared/queue/deque.rb b/spec/ruby/shared/queue/deque.rb new file mode 100644 index 0000000000..a154da6274 --- /dev/null +++ b/spec/ruby/shared/queue/deque.rb @@ -0,0 +1,164 @@ +describe :queue_deq, shared: true do + it "removes an item from the queue" do + q = @object.call + q << Object.new + q.size.should == 1 + q.send @method + q.size.should == 0 + end + + it "returns items in the order they were added" do + q = @object.call + q << 1 + q << 2 + q.send(@method).should == 1 + q.send(@method).should == 2 + end + + it "blocks the thread until there are items in the queue" do + q = @object.call + v = 0 + + th = Thread.new do + q.send(@method) + v = 1 + end + + v.should == 0 + q << Object.new + th.join + v.should == 1 + end + + it "removes an item from a closed queue" do + q = @object.call + q << 1 + q.close + q.send(@method).should == 1 + end + + it "converts false-ish for non_blocking to boolean" do + q = @object.call + q << 1 + q << 2 + + q.send(@method, false).should == 1 + q.send(@method, nil).should == 2 + end + + it "returns nil for a closed empty queue" do + q = @object.call + q.close + q.send(@method).should == nil + end + + it "returns nil for an empty queue that becomes closed" do + q = @object.call + + t = Thread.new { + q.send(@method).should == nil + } + + Thread.pass until t.status == "sleep" && q.num_waiting == 1 + q.close + t.join + end + + describe "with a timeout" do + it "returns an item if one is available in time" do + q = @object.call + + t = Thread.new { + q.send(@method, timeout: TIME_TOLERANCE).should == 1 + } + Thread.pass until t.status == "sleep" && q.num_waiting == 1 + q << 1 + t.join + end + + it "returns nil if no item is available in time" do + q = @object.call + + Thread.new { + q.send(@method, timeout: 0.001).should == nil + }.join + end + + it "does nothing if the timeout is nil" do + q = @object.call + t = Thread.new { + q.send(@method, timeout: nil).should == 1 + } + Thread.pass until t.status == "sleep" && q.num_waiting == 1 + q << 1 + t.join + end + + it "immediately returns nil if no item is available and the timeout is 0" do + q = @object.call + q << 1 + q.send(@method, timeout: 0).should == 1 + q.send(@method, timeout: 0).should == nil + end + + it "raise TypeError if timeout is not a valid numeric" do + q = @object.call + -> { + q.send(@method, timeout: "1") + }.should raise_error(TypeError, "no implicit conversion to float from string") + + -> { + q.send(@method, timeout: false) + }.should raise_error(TypeError, "no implicit conversion to float from false") + end + + it "raise ArgumentError if non_block = true is passed too" do + q = @object.call + -> { + q.send(@method, true, timeout: 1) + }.should raise_error(ArgumentError, "can't set a timeout if non_block is enabled") + end + + it "returns nil for a closed empty queue" do + q = @object.call + q.close + q.send(@method, timeout: 0).should == nil + end + end + + describe "in non-blocking mode" do + it "removes an item from the queue" do + q = @object.call + q << Object.new + q.size.should == 1 + q.send(@method, true) + q.size.should == 0 + end + + it "raises a ThreadError if the queue is empty" do + q = @object.call + -> { q.send(@method, true) }.should raise_error(ThreadError) + end + + it "removes an item from a closed queue" do + q = @object.call + q << 1 + q.close + q.send(@method, true).should == 1 + end + + it "raises a ThreadError for a closed empty queue" do + q = @object.call + q.close + -> { q.send(@method, true) }.should raise_error(ThreadError) + end + + it "converts true-ish non_blocking argument to true" do + q = @object.call + + -> { q.send(@method, true) }.should raise_error(ThreadError) + -> { q.send(@method, 1) }.should raise_error(ThreadError) + -> { q.send(@method, "") }.should raise_error(ThreadError) + end + end +end diff --git a/spec/ruby/shared/queue/empty.rb b/spec/ruby/shared/queue/empty.rb new file mode 100644 index 0000000000..4acd831d48 --- /dev/null +++ b/spec/ruby/shared/queue/empty.rb @@ -0,0 +1,12 @@ +describe :queue_empty?, shared: true do + it "returns true on an empty Queue" do + queue = @object.call + queue.empty?.should be_true + end + + it "returns false when Queue is not empty" do + queue = @object.call + queue << Object.new + queue.empty?.should be_false + end +end diff --git a/spec/ruby/shared/queue/enque.rb b/spec/ruby/shared/queue/enque.rb new file mode 100644 index 0000000000..8aba02e544 --- /dev/null +++ b/spec/ruby/shared/queue/enque.rb @@ -0,0 +1,18 @@ +describe :queue_enq, shared: true do + it "adds an element to the Queue" do + q = @object.call + q.size.should == 0 + q.send @method, Object.new + q.size.should == 1 + q.send @method, Object.new + q.size.should == 2 + end + + it "is an error for a closed queue" do + q = @object.call + q.close + -> { + q.send @method, Object.new + }.should raise_error(ClosedQueueError) + end +end diff --git a/spec/ruby/shared/queue/freeze.rb b/spec/ruby/shared/queue/freeze.rb new file mode 100644 index 0000000000..4c506a4235 --- /dev/null +++ b/spec/ruby/shared/queue/freeze.rb @@ -0,0 +1,18 @@ +describe :queue_freeze, shared: true do + ruby_version_is ""..."3.3" do + it "can be frozen" do + queue = @object.call + queue.freeze + queue.should.frozen? + end + end + + ruby_version_is "3.3" do + it "raises an exception when freezing" do + queue = @object.call + -> { + queue.freeze + }.should raise_error(TypeError, "cannot freeze #{queue}") + end + end +end diff --git a/spec/ruby/shared/queue/length.rb b/spec/ruby/shared/queue/length.rb new file mode 100644 index 0000000000..a0143a4e19 --- /dev/null +++ b/spec/ruby/shared/queue/length.rb @@ -0,0 +1,9 @@ +describe :queue_length, shared: true do + it "returns the number of elements" do + q = @object.call + q.send(@method).should == 0 + q << Object.new + q << Object.new + q.send(@method).should == 2 + end +end diff --git a/spec/ruby/shared/queue/num_waiting.rb b/spec/ruby/shared/queue/num_waiting.rb new file mode 100644 index 0000000000..b054951e45 --- /dev/null +++ b/spec/ruby/shared/queue/num_waiting.rb @@ -0,0 +1,16 @@ +describe :queue_num_waiting, shared: true do + it "reports the number of threads waiting on the queue" do + q = @object.call + threads = [] + + 5.times do |i| + q.num_waiting.should == i + t = Thread.new { q.deq } + Thread.pass until q.num_waiting == i+1 + threads << t + end + + threads.each { q.enq Object.new } + threads.each {|t| t.join } + end +end diff --git a/spec/ruby/shared/rational/Rational.rb b/spec/ruby/shared/rational/Rational.rb deleted file mode 100644 index 0165fa769a..0000000000 --- a/spec/ruby/shared/rational/Rational.rb +++ /dev/null @@ -1,103 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) -require File.expand_path('../../../fixtures/rational', __FILE__) - -describe :kernel_Rational, shared: true do - describe "passed Integer" do - # Guard against the Mathn library - conflicts_with :Prime do - it "returns a new Rational number with 1 as the denominator" do - Rational(1).should eql(Rational(1, 1)) - Rational(-3).should eql(Rational(-3, 1)) - Rational(bignum_value).should eql(Rational(bignum_value, 1)) - end - end - end - - describe "passed two integers" do - it "returns a new Rational number" do - rat = Rational(1, 2) - rat.numerator.should == 1 - rat.denominator.should == 2 - rat.should be_an_instance_of(Rational) - - rat = Rational(-3, -5) - rat.numerator.should == 3 - rat.denominator.should == 5 - rat.should be_an_instance_of(Rational) - - rat = Rational(bignum_value, 3) - rat.numerator.should == bignum_value - rat.denominator.should == 3 - rat.should be_an_instance_of(Rational) - end - - it "reduces the Rational" do - rat = Rational(2, 4) - rat.numerator.should == 1 - rat.denominator.should == 2 - - rat = Rational(3, 9) - rat.numerator.should == 1 - rat.denominator.should == 3 - end - end - - describe "when passed a String" do - it "converts the String to a Rational using the same method as String#to_r" do - r = Rational(13, 25) - s_r = ".52".to_r - r_s = Rational(".52") - - r_s.should == r - r_s.should == s_r - end - - it "scales the Rational value of the first argument by the Rational value of the second" do - Rational(".52", ".6").should == Rational(13, 15) - Rational(".52", "1.6").should == Rational(13, 40) - end - - it "does not use the same method as Float#to_r" do - r = Rational(3, 5) - f_r = 0.6.to_r - r_s = Rational("0.6") - - r_s.should == r - r_s.should_not == f_r - end - - describe "when passed a Numeric" do - it "calls #to_r to convert the first argument to a Rational" do - num = RationalSpecs::SubNumeric.new(2) - - Rational(num).should == Rational(2) - end - end - - describe "when passed a Complex" do - it "returns a Rational from the real part if the imaginary part is 0" do - Rational(Complex(1, 0)).should == Rational(1) - end - - it "raises a RangeError if the imaginary part is not 0" do - lambda { Rational(Complex(1, 2)) }.should raise_error(RangeError) - end - end - - it "raises a TypeError if the first argument is nil" do - lambda { Rational(nil) }.should raise_error(TypeError) - end - - it "raises a TypeError if the second argument is nil" do - lambda { Rational(1, nil) }.should raise_error(TypeError) - end - - it "raises a TypeError if the first argument is a Symbol" do - lambda { Rational(:sym) }.should raise_error(TypeError) - end - - it "raises a TypeError if the second argument is a Symbol" do - lambda { Rational(1, :sym) }.should raise_error(TypeError) - end - end -end diff --git a/spec/ruby/shared/rational/abs.rb b/spec/ruby/shared/rational/abs.rb deleted file mode 100644 index aa1bdc4363..0000000000 --- a/spec/ruby/shared/rational/abs.rb +++ /dev/null @@ -1,11 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :rational_abs, shared: true do - it "returns self's absolute value" do - Rational(3, 4).send(@method).should == Rational(3, 4) - Rational(-3, 4).send(@method).should == Rational(3, 4) - Rational(3, -4).send(@method).should == Rational(3, 4) - - Rational(bignum_value, -bignum_value).send(@method).should == Rational(bignum_value, bignum_value) - end -end diff --git a/spec/ruby/shared/rational/ceil.rb b/spec/ruby/shared/rational/ceil.rb deleted file mode 100644 index cbb4ed0d08..0000000000 --- a/spec/ruby/shared/rational/ceil.rb +++ /dev/null @@ -1,45 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :rational_ceil, shared: true do - before do - @rational = Rational(2200, 7) - end - - describe "with no arguments (precision = 0)" do - it "returns an Integer" do - @rational.ceil.should be_kind_of(Integer) - end - - it "returns the truncated value toward positive infinity" do - @rational.ceil.should == 315 - Rational(1, 2).ceil.should == 1 - Rational(-1, 2).ceil.should == 0 - end - end - - describe "with a precision < 0" do - it "returns an Integer" do - @rational.ceil(-2).should be_kind_of(Integer) - @rational.ceil(-1).should be_kind_of(Integer) - end - - it "moves the truncation point n decimal places left" do - @rational.ceil(-3).should == 1000 - @rational.ceil(-2).should == 400 - @rational.ceil(-1).should == 320 - end - end - - describe "with precision > 0" do - it "returns a Rational" do - @rational.ceil(1).should be_kind_of(Rational) - @rational.ceil(2).should be_kind_of(Rational) - end - - it "moves the truncation point n decimal places right" do - @rational.ceil(1).should == Rational(3143, 10) - @rational.ceil(2).should == Rational(31429, 100) - @rational.ceil(3).should == Rational(157143, 500) - end - end -end diff --git a/spec/ruby/shared/rational/coerce.rb b/spec/ruby/shared/rational/coerce.rb deleted file mode 100644 index 8bdd19aa2a..0000000000 --- a/spec/ruby/shared/rational/coerce.rb +++ /dev/null @@ -1,21 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :rational_coerce, shared: true do - it "returns the passed argument, self as Float, when given a Float" do - result = Rational(3, 4).coerce(1.0) - result.should == [1.0, 0.75] - result.first.is_a?(Float).should be_true - result.last.is_a?(Float).should be_true - end - - it "returns the passed argument, self as Rational, when given an Integer" do - result = Rational(3, 4).coerce(10) - result.should == [Rational(10, 1), Rational(3, 4)] - result.first.is_a?(Rational).should be_true - result.last.is_a?(Rational).should be_true - end - - it "returns [argument, self] when given a Rational" do - Rational(3, 7).coerce(Rational(9, 2)).should == [Rational(9, 2), Rational(3, 7)] - end -end diff --git a/spec/ruby/shared/rational/comparison.rb b/spec/ruby/shared/rational/comparison.rb deleted file mode 100644 index c52363781f..0000000000 --- a/spec/ruby/shared/rational/comparison.rb +++ /dev/null @@ -1,85 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :rational_cmp_rat, shared: true do - it "returns 1 when self is greater than the passed argument" do - (Rational(4, 4) <=> Rational(3, 4)).should equal(1) - (Rational(-3, 4) <=> Rational(-4, 4)).should equal(1) - end - - it "returns 0 when self is equal to the passed argument" do - (Rational(4, 4) <=> Rational(4, 4)).should equal(0) - (Rational(-3, 4) <=> Rational(-3, 4)).should equal(0) - end - - it "returns -1 when self is less than the passed argument" do - (Rational(3, 4) <=> Rational(4, 4)).should equal(-1) - (Rational(-4, 4) <=> Rational(-3, 4)).should equal(-1) - end -end - -describe :rational_cmp_int, shared: true do - it "returns 1 when self is greater than the passed argument" do - (Rational(4, 4) <=> 0).should equal(1) - (Rational(4, 4) <=> -10).should equal(1) - (Rational(-3, 4) <=> -1).should equal(1) - end - - it "returns 0 when self is equal to the passed argument" do - (Rational(4, 4) <=> 1).should equal(0) - (Rational(-8, 4) <=> -2).should equal(0) - end - - it "returns -1 when self is less than the passed argument" do - (Rational(3, 4) <=> 1).should equal(-1) - (Rational(-4, 4) <=> 0).should equal(-1) - end -end - -describe :rational_cmp_float, shared: true do - it "returns 1 when self is greater than the passed argument" do - (Rational(4, 4) <=> 0.5).should equal(1) - (Rational(4, 4) <=> -1.5).should equal(1) - (Rational(-3, 4) <=> -0.8).should equal(1) - end - - it "returns 0 when self is equal to the passed argument" do - (Rational(4, 4) <=> 1.0).should equal(0) - (Rational(-6, 4) <=> -1.5).should equal(0) - end - - it "returns -1 when self is less than the passed argument" do - (Rational(3, 4) <=> 1.2).should equal(-1) - (Rational(-4, 4) <=> 0.5).should equal(-1) - end -end - -describe :rational_cmp_coerce, shared: true do - it "calls #coerce on the passed argument with self" do - rational = Rational(3, 4) - - obj = mock("Object") - obj.should_receive(:coerce).with(rational).and_return([1, 2]) - - rational <=> obj - end - - it "calls #<=> on the coerced Rational with the coerced Object" do - rational = Rational(3, 4) - - coerced_rational = mock("Coerced Rational") - coerced_rational.should_receive(:<=>).and_return(:result) - - coerced_obj = mock("Coerced Object") - - obj = mock("Object") - obj.should_receive(:coerce).and_return([coerced_rational, coerced_obj]) - - (rational <=> obj).should == :result - end -end - -describe :rational_cmp_other, shared: true do - it "returns nil" do - (Rational <=> mock("Object")).should be_nil - end -end diff --git a/spec/ruby/shared/rational/denominator.rb b/spec/ruby/shared/rational/denominator.rb deleted file mode 100644 index 74e464465d..0000000000 --- a/spec/ruby/shared/rational/denominator.rb +++ /dev/null @@ -1,14 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :rational_denominator, shared: true do - it "returns the denominator" do - Rational(3, 4).denominator.should equal(4) - Rational(3, -4).denominator.should equal(4) - - Rational(1, bignum_value).denominator.should == bignum_value - end - - it "returns 1 if no denominator was given" do - Rational(80).denominator.should == 1 - end -end diff --git a/spec/ruby/shared/rational/div.rb b/spec/ruby/shared/rational/div.rb deleted file mode 100644 index 23c11f5d12..0000000000 --- a/spec/ruby/shared/rational/div.rb +++ /dev/null @@ -1,54 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :rational_div_rat, shared: true do - it "performs integer division and returns the result" do - Rational(2, 3).div(Rational(2, 3)).should == 1 - Rational(-2, 9).div(Rational(-9, 2)).should == 0 - end - - it "raises a ZeroDivisionError when the argument has a numerator of 0" do - lambda { Rational(3, 4).div(Rational(0, 3)) }.should raise_error(ZeroDivisionError) - end - - it "raises a ZeroDivisionError when the argument has a numerator of 0.0" do - lambda { Rational(3, 4).div(Rational(0.0, 3)) }.should raise_error(ZeroDivisionError) - end -end - -describe :rational_div_float, shared: true do - it "performs integer division and returns the result" do - Rational(2, 3).div(30.333).should == 0 - Rational(2, 9).div(Rational(-8.6)).should == -1 - Rational(3.12).div(0.5).should == 6 - end - - it "raises a ZeroDivisionError when the argument is 0.0" do - lambda { Rational(3, 4).div(0.0) }.should raise_error(ZeroDivisionError) - end -end - -describe :rational_div_int, shared: true do - it "performs integer division and returns the result" do - Rational(2, 1).div(1).should == 2 - Rational(25, 5).div(-50).should == -1 - end - - it "raises a ZeroDivisionError when the argument is 0" do - lambda { Rational(3, 4).div(0) }.should raise_error(ZeroDivisionError) - end -end - -describe :rational_div, shared: true do - it "returns an Integer" do - Rational(229, 21).div(82).should be_kind_of(Integer) - end - - it "raises an ArgumentError if passed more than one argument" do - lambda { Rational(3, 4).div(2,3) }.should raise_error(ArgumentError) - end - - # See http://redmine.ruby-lang.org/issues/show/1648 - it "raises a TypeError if passed a non-numeric argument" do - lambda { Rational(3, 4).div([]) }.should raise_error(TypeError) - end -end diff --git a/spec/ruby/shared/rational/divide.rb b/spec/ruby/shared/rational/divide.rb deleted file mode 100644 index 8c5bf666e6..0000000000 --- a/spec/ruby/shared/rational/divide.rb +++ /dev/null @@ -1,71 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :rational_divide_rat, shared: true do - it "returns self divided by other as a Rational" do - Rational(3, 4).send(@method, Rational(3, 4)).should eql(Rational(1, 1)) - Rational(2, 4).send(@method, Rational(1, 4)).should eql(Rational(2, 1)) - - Rational(2, 4).send(@method, 2).should == Rational(1, 4) - Rational(6, 7).send(@method, -2).should == Rational(-3, 7) - end - - it "raises a ZeroDivisionError when passed a Rational with a numerator of 0" do - lambda { Rational(3, 4).send(@method, Rational(0, 1)) }.should raise_error(ZeroDivisionError) - end -end - -describe :rational_divide_int, shared: true do - it "returns self divided by other as a Rational" do - Rational(3, 4).send(@method, 2).should eql(Rational(3, 8)) - Rational(2, 4).send(@method, 2).should eql(Rational(1, 4)) - Rational(6, 7).send(@method, -2).should eql(Rational(-3, 7)) - end - - it "raises a ZeroDivisionError when passed 0" do - lambda { Rational(3, 4).send(@method, 0) }.should raise_error(ZeroDivisionError) - end -end - -describe :rational_divide_float, shared: true do - it "returns self divided by other as a Float" do - Rational(3, 4).send(@method, 0.75).should eql(1.0) - Rational(3, 4).send(@method, 0.25).should eql(3.0) - Rational(3, 4).send(@method, 0.3).should eql(2.5) - - Rational(-3, 4).send(@method, 0.3).should eql(-2.5) - Rational(3, -4).send(@method, 0.3).should eql(-2.5) - Rational(3, 4).send(@method, -0.3).should eql(-2.5) - end - - it "returns infinity when passed 0" do - Rational(3, 4).send(@method, 0.0).infinite?.should eql(1) - Rational(-3, -4).send(@method, 0.0).infinite?.should eql(1) - - Rational(-3, 4).send(@method, 0.0).infinite?.should eql(-1) - Rational(3, -4).send(@method, 0.0).infinite?.should eql(-1) - end -end - -describe :rational_divide, shared: true do - it "calls #coerce on the passed argument with self" do - rational = Rational(3, 4) - obj = mock("Object") - obj.should_receive(:coerce).with(rational).and_return([1, 2]) - - rational.send(@method, obj) - end - - it "calls #/ on the coerced Rational with the coerced Object" do - rational = Rational(3, 4) - - coerced_rational = mock("Coerced Rational") - coerced_rational.should_receive(:/).and_return(:result) - - coerced_obj = mock("Coerced Object") - - obj = mock("Object") - obj.should_receive(:coerce).and_return([coerced_rational, coerced_obj]) - - rational.send(@method, obj).should == :result - end -end diff --git a/spec/ruby/shared/rational/divmod.rb b/spec/ruby/shared/rational/divmod.rb deleted file mode 100644 index 607ae9d693..0000000000 --- a/spec/ruby/shared/rational/divmod.rb +++ /dev/null @@ -1,42 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :rational_divmod_rat, shared: true do - it "returns the quotient as Integer and the remainder as Rational" do - Rational(7, 4).divmod(Rational(1, 2)).should eql([3, Rational(1, 4)]) - Rational(7, 4).divmod(Rational(-1, 2)).should eql([-4, Rational(-1, 4)]) - Rational(0, 4).divmod(Rational(4, 3)).should eql([0, Rational(0, 1)]) - - Rational(bignum_value, 4).divmod(Rational(4, 3)).should eql([1729382256910270464, Rational(0, 1)]) - end - - it "raises a ZeroDivisonError when passed a Rational with a numerator of 0" do - lambda { Rational(7, 4).divmod(Rational(0, 3)) }.should raise_error(ZeroDivisionError) - end -end - -describe :rational_divmod_int, shared: true do - it "returns the quotient as Integer and the remainder as Rational" do - Rational(7, 4).divmod(2).should eql([0, Rational(7, 4)]) - Rational(7, 4).divmod(-2).should eql([-1, Rational(-1, 4)]) - - Rational(bignum_value, 4).divmod(3).should == [768614336404564650, Rational(2, 1)] - end - - it "raises a ZeroDivisionError when passed 0" do - lambda { Rational(7, 4).divmod(0) }.should raise_error(ZeroDivisionError) - end -end - -describe :rational_divmod_float, shared: true do - it "returns the quotient as Integer and the remainder as Float" do - Rational(7, 4).divmod(0.5).should eql([3, 0.25]) - end - - it "returns the quotient as Integer and the remainder as Float" do - Rational(7, 4).divmod(-0.5).should eql([-4, -0.25]) - end - - it "raises a ZeroDivisionError when passed 0" do - lambda { Rational(7, 4).divmod(0.0) }.should raise_error(ZeroDivisionError) - end -end diff --git a/spec/ruby/shared/rational/equal_value.rb b/spec/ruby/shared/rational/equal_value.rb deleted file mode 100644 index be4d5af598..0000000000 --- a/spec/ruby/shared/rational/equal_value.rb +++ /dev/null @@ -1,39 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :rational_equal_value_rat, shared: true do - it "returns true if self has the same numerator and denominator as the passed argument" do - (Rational(3, 4) == Rational(3, 4)).should be_true - (Rational(-3, -4) == Rational(3, 4)).should be_true - (Rational(-4, 5) == Rational(4, -5)).should be_true - - (Rational(bignum_value, 3) == Rational(bignum_value, 3)).should be_true - (Rational(-bignum_value, 3) == Rational(bignum_value, -3)).should be_true - end -end - -describe :rational_equal_value_int, shared: true do - it "returns true if self has the passed argument as numerator and a denominator of 1" do - # Rational(x, y) reduces x and y automatically - (Rational(4, 2) == 2).should be_true - (Rational(-4, 2) == -2).should be_true - (Rational(4, -2) == -2).should be_true - end -end - -describe :rational_equal_value_float, shared: true do - it "converts self to a Float and compares it with the passed argument" do - (Rational(3, 4) == 0.75).should be_true - (Rational(4, 2) == 2.0).should be_true - (Rational(-4, 2) == -2.0).should be_true - (Rational(4, -2) == -2.0).should be_true - end -end - -describe :rational_equal_value, shared: true do - it "returns the result of calling #== with self on the passed argument" do - obj = mock("Object") - obj.should_receive(:==).and_return(:result) - - (Rational(3, 4) == obj).should_not be_false - end -end diff --git a/spec/ruby/shared/rational/exponent.rb b/spec/ruby/shared/rational/exponent.rb deleted file mode 100644 index 7e7c5be7c1..0000000000 --- a/spec/ruby/shared/rational/exponent.rb +++ /dev/null @@ -1,176 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :rational_exponent, shared: true do - describe "when passed Rational" do - conflicts_with :Prime do - it "returns Rational(1) if the exponent is Rational(0)" do - (Rational(0) ** Rational(0)).should eql(Rational(1)) - (Rational(1) ** Rational(0)).should eql(Rational(1)) - (Rational(3, 4) ** Rational(0)).should eql(Rational(1)) - (Rational(-1) ** Rational(0)).should eql(Rational(1)) - (Rational(-3, 4) ** Rational(0)).should eql(Rational(1)) - (Rational(bignum_value) ** Rational(0)).should eql(Rational(1)) - (Rational(-bignum_value) ** Rational(0)).should eql(Rational(1)) - end - - it "returns self raised to the argument as a Rational if the exponent's denominator is 1" do - (Rational(3, 4) ** Rational(1, 1)).should eql(Rational(3, 4)) - (Rational(3, 4) ** Rational(2, 1)).should eql(Rational(9, 16)) - (Rational(3, 4) ** Rational(-1, 1)).should eql(Rational(4, 3)) - (Rational(3, 4) ** Rational(-2, 1)).should eql(Rational(16, 9)) - end - - it "returns self raised to the argument as a Float if the exponent's denominator is not 1" do - (Rational(3, 4) ** Rational(4, 3)).should be_close(0.681420222312052, TOLERANCE) - (Rational(3, 4) ** Rational(-4, 3)).should be_close(1.46752322173095, TOLERANCE) - (Rational(3, 4) ** Rational(4, -3)).should be_close(1.46752322173095, TOLERANCE) - end - - it "returns a complex number when self is negative and the passed argument is not 0" do - (Rational(-3, 4) ** Rational(-4, 3)).should be_close(Complex(-0.7337616108654732, 1.2709123906625817), TOLERANCE) - end - end - end - - describe "when passed Integer" do - it "returns the Rational value of self raised to the passed argument" do - (Rational(3, 4) ** 4).should == Rational(81, 256) - (Rational(3, 4) ** -4).should == Rational(256, 81) - (Rational(-3, 4) ** -4).should == Rational(256, 81) - (Rational(3, -4) ** -4).should == Rational(256, 81) - - (Rational(bignum_value, 4) ** 4).should == Rational(28269553036454149273332760011886696253239742350009903329945699220681916416, 1) - (Rational(3, bignum_value) ** -4).should == Rational(7237005577332262213973186563042994240829374041602535252466099000494570602496, 81) - (Rational(-bignum_value, 4) ** -4).should == Rational(1, 28269553036454149273332760011886696253239742350009903329945699220681916416) - (Rational(3, -bignum_value) ** -4).should == Rational(7237005577332262213973186563042994240829374041602535252466099000494570602496, 81) - end - - conflicts_with :Prime do - it "returns Rational(1, 1) when the passed argument is 0" do - (Rational(3, 4) ** 0).should eql(Rational(1, 1)) - (Rational(-3, 4) ** 0).should eql(Rational(1, 1)) - (Rational(3, -4) ** 0).should eql(Rational(1, 1)) - - (Rational(bignum_value, 4) ** 0).should eql(Rational(1, 1)) - (Rational(3, -bignum_value) ** 0).should eql(Rational(1, 1)) - end - end - end - - describe "when passed Bignum" do - # #5713 - it "returns Rational(0) when self is Rational(0) and the exponent is positive" do - (Rational(0) ** bignum_value).should eql(Rational(0)) - end - - it "raises ZeroDivisionError when self is Rational(0) and the exponent is negative" do - lambda { Rational(0) ** -bignum_value }.should raise_error(ZeroDivisionError) - end - - it "returns Rational(1) when self is Rational(1)" do - (Rational(1) ** bignum_value).should eql(Rational(1)) - (Rational(1) ** -bignum_value).should eql(Rational(1)) - end - - it "returns Rational(1) when self is Rational(-1) and the exponent is positive and even" do - (Rational(-1) ** bignum_value(0)).should eql(Rational(1)) - (Rational(-1) ** bignum_value(2)).should eql(Rational(1)) - end - - it "returns Rational(-1) when self is Rational(-1) and the exponent is positive and odd" do - (Rational(-1) ** bignum_value(1)).should eql(Rational(-1)) - (Rational(-1) ** bignum_value(3)).should eql(Rational(-1)) - end - - it "returns positive Infinity when self is > 1" do - (Rational(2) ** bignum_value).infinite?.should == 1 - (Rational(fixnum_max) ** bignum_value).infinite?.should == 1 - end - - it "returns 0.0 when self is > 1 and the exponent is negative" do - (Rational(2) ** -bignum_value).should eql(0.0) - (Rational(fixnum_max) ** -bignum_value).should eql(0.0) - end - - # Fails on linux due to pow() bugs in glibc: http://sources.redhat.com/bugzilla/show_bug.cgi?id=3866 - platform_is_not :linux do - it "returns positive Infinity when self < -1" do - (Rational(-2) ** bignum_value).infinite?.should == 1 - (Rational(-2) ** (bignum_value + 1)).infinite?.should == 1 - (Rational(fixnum_min) ** bignum_value).infinite?.should == 1 - end - - it "returns 0.0 when self is < -1 and the exponent is negative" do - (Rational(-2) ** -bignum_value).should eql(0.0) - (Rational(fixnum_min) ** -bignum_value).should eql(0.0) - end - end - end - - describe "when passed Float" do - it "returns self converted to Float and raised to the passed argument" do - (Rational(3, 1) ** 3.0).should eql(27.0) - (Rational(3, 1) ** 1.5).should be_close(5.19615242270663, TOLERANCE) - (Rational(3, 1) ** -1.5).should be_close(0.192450089729875, TOLERANCE) - end - - it "returns a complex number if self is negative and the passed argument is not 0" do - (Rational(-3, 2) ** 1.5).should be_close(Complex(-3.374618290464398e-16, -1.8371173070873836), TOLERANCE) - (Rational(3, -2) ** 1.5).should be_close(Complex(-3.374618290464398e-16, -1.8371173070873836), TOLERANCE) - (Rational(3, -2) ** -1.5).should be_close(Complex(-9.998869008783402e-17, 0.5443310539518174), TOLERANCE) - end - - it "returns Complex(1.0) when the passed argument is 0.0" do - (Rational(3, 4) ** 0.0).should == Complex(1.0) - (Rational(-3, 4) ** 0.0).should == Complex(1.0) - (Rational(-3, 4) ** 0.0).should == Complex(1.0) - end - end - - it "calls #coerce on the passed argument with self" do - rational = Rational(3, 4) - obj = mock("Object") - obj.should_receive(:coerce).with(rational).and_return([1, 2]) - - rational ** obj - end - - it "calls #** on the coerced Rational with the coerced Object" do - rational = Rational(3, 4) - - coerced_rational = mock("Coerced Rational") - coerced_rational.should_receive(:**).and_return(:result) - - coerced_obj = mock("Coerced Object") - - obj = mock("Object") - obj.should_receive(:coerce).and_return([coerced_rational, coerced_obj]) - - (rational ** obj).should == :result - end - - it "raises ZeroDivisionError for Rational(0, 1) passed a negative Integer" do - [-1, -4, -9999].each do |exponent| - lambda { Rational(0, 1) ** exponent }.should raise_error(ZeroDivisionError, "divided by 0") - end - end - - it "raises ZeroDivisionError for Rational(0, 1) passed a negative Rational with denominator 1" do - [Rational(-1, 1), Rational(-3, 1)].each do |exponent| - lambda { Rational(0, 1) ** exponent }.should raise_error(ZeroDivisionError, "divided by 0") - end - end - - # #7513 - it "raises ZeroDivisionError for Rational(0, 1) passed a negative Rational" do - lambda { Rational(0, 1) ** Rational(-3, 2) }.should raise_error(ZeroDivisionError, "divided by 0") - end - - platform_is_not :solaris do # See https://github.com/ruby/spec/issues/134 - it "returns Infinity for Rational(0, 1) passed a negative Float" do - [-1.0, -3.0, -3.14].each do |exponent| - (Rational(0, 1) ** exponent).infinite?.should == 1 - end - end - end -end diff --git a/spec/ruby/shared/rational/fdiv.rb b/spec/ruby/shared/rational/fdiv.rb deleted file mode 100644 index 22ca4b4ddc..0000000000 --- a/spec/ruby/shared/rational/fdiv.rb +++ /dev/null @@ -1,5 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :rational_fdiv, shared: true do - it "needs to be reviewed for spec completeness" -end diff --git a/spec/ruby/shared/rational/floor.rb b/spec/ruby/shared/rational/floor.rb deleted file mode 100644 index 5106e0b4d9..0000000000 --- a/spec/ruby/shared/rational/floor.rb +++ /dev/null @@ -1,45 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :rational_floor, shared: true do - before do - @rational = Rational(2200, 7) - end - - describe "with no arguments (precision = 0)" do - it "returns an integer" do - @rational.floor.should be_kind_of(Integer) - end - - it "returns the truncated value toward negative infinity" do - @rational.floor.should == 314 - Rational(1, 2).floor.should == 0 - Rational(-1, 2).floor.should == -1 - end - end - - describe "with a precision < 0" do - it "returns an integer" do - @rational.floor(-2).should be_kind_of(Integer) - @rational.floor(-1).should be_kind_of(Integer) - end - - it "moves the truncation point n decimal places left" do - @rational.floor(-3).should == 0 - @rational.floor(-2).should == 300 - @rational.floor(-1).should == 310 - end - end - - describe "with a precision > 0" do - it "returns a Rational" do - @rational.floor(1).should be_kind_of(Rational) - @rational.floor(2).should be_kind_of(Rational) - end - - it "moves the truncation point n decimal places right" do - @rational.floor(1).should == Rational(1571, 5) - @rational.floor(2).should == Rational(7857, 25) - @rational.floor(3).should == Rational(62857, 200) - end - end -end diff --git a/spec/ruby/shared/rational/hash.rb b/spec/ruby/shared/rational/hash.rb deleted file mode 100644 index a83ce49afb..0000000000 --- a/spec/ruby/shared/rational/hash.rb +++ /dev/null @@ -1,9 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :rational_hash, shared: true do - # BUG: Rational(2, 3).hash == Rational(3, 2).hash - it "is static" do - Rational(2, 3).hash.should == Rational(2, 3).hash - Rational(2, 4).hash.should_not == Rational(2, 3).hash - end -end diff --git a/spec/ruby/shared/rational/inspect.rb b/spec/ruby/shared/rational/inspect.rb deleted file mode 100644 index a641db8eb8..0000000000 --- a/spec/ruby/shared/rational/inspect.rb +++ /dev/null @@ -1,12 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :rational_inspect, shared: true do - conflicts_with :Prime do - it "returns a string representation of self" do - Rational(3, 4).inspect.should == "(3/4)" - Rational(-5, 8).inspect.should == "(-5/8)" - Rational(-1, -2).inspect.should == "(1/2)" - Rational(bignum_value, 1).inspect.should == "(#{bignum_value}/1)" - end - end -end diff --git a/spec/ruby/shared/rational/marshal_dump.rb b/spec/ruby/shared/rational/marshal_dump.rb deleted file mode 100644 index 673c6c8327..0000000000 --- a/spec/ruby/shared/rational/marshal_dump.rb +++ /dev/null @@ -1,5 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :rational_marshal_dump, shared: true do - it "needs to be reviewed for spec completeness" -end diff --git a/spec/ruby/shared/rational/marshal_load.rb b/spec/ruby/shared/rational/marshal_load.rb deleted file mode 100644 index 7cf32ad1db..0000000000 --- a/spec/ruby/shared/rational/marshal_load.rb +++ /dev/null @@ -1,5 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :rational_marshal_load, shared: true do - it "needs to be reviewed for spec completeness" -end diff --git a/spec/ruby/shared/rational/minus.rb b/spec/ruby/shared/rational/minus.rb deleted file mode 100644 index e23430111e..0000000000 --- a/spec/ruby/shared/rational/minus.rb +++ /dev/null @@ -1,48 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :rational_minus_rat, shared: true do - it "returns the result of subtracting other from self as a Rational" do - (Rational(3, 4) - Rational(0, 1)).should eql(Rational(3, 4)) - (Rational(3, 4) - Rational(1, 4)).should eql(Rational(1, 2)) - - (Rational(3, 4) - Rational(2, 1)).should eql(Rational(-5, 4)) - end -end - -describe :rational_minus_int, shared: true do - it "returns the result of subtracting other from self as a Rational" do - (Rational(3, 4) - 1).should eql(Rational(-1, 4)) - (Rational(3, 4) - 2).should eql(Rational(-5, 4)) - end -end - -describe :rational_minus_float, shared: true do - it "returns the result of subtracting other from self as a Float" do - (Rational(3, 4) - 0.2).should eql(0.55) - (Rational(3, 4) - 2.5).should eql(-1.75) - end -end - -describe :rational_minus, shared: true do - it "calls #coerce on the passed argument with self" do - rational = Rational(3, 4) - obj = mock("Object") - obj.should_receive(:coerce).with(rational).and_return([1, 2]) - - rational - obj - end - - it "calls #- on the coerced Rational with the coerced Object" do - rational = Rational(3, 4) - - coerced_rational = mock("Coerced Rational") - coerced_rational.should_receive(:-).and_return(:result) - - coerced_obj = mock("Coerced Object") - - obj = mock("Object") - obj.should_receive(:coerce).and_return([coerced_rational, coerced_obj]) - - (rational - obj).should == :result - end -end diff --git a/spec/ruby/shared/rational/modulo.rb b/spec/ruby/shared/rational/modulo.rb deleted file mode 100644 index ca69650f20..0000000000 --- a/spec/ruby/shared/rational/modulo.rb +++ /dev/null @@ -1,43 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :rational_modulo, shared: true do - it "returns the remainder when this value is divided by other" do - Rational(2, 3).send(@method, Rational(2, 3)).should == Rational(0, 1) - Rational(4, 3).send(@method, Rational(2, 3)).should == Rational(0, 1) - Rational(2, -3).send(@method, Rational(-2, 3)).should == Rational(0, 1) - Rational(0, -1).send(@method, -1).should == Rational(0, 1) - - Rational(7, 4).send(@method, Rational(1, 2)).should == Rational(1, 4) - Rational(7, 4).send(@method, 1).should == Rational(3, 4) - Rational(7, 4).send(@method, Rational(1, 7)).should == Rational(1, 28) - - Rational(3, 4).send(@method, -1).should == Rational(-1, 4) - Rational(1, -5).send(@method, -1).should == Rational(-1, 5) - end - - it "returns a Float value when the argument is Float" do - Rational(7, 4).send(@method, 1.0).should be_kind_of(Float) - Rational(7, 4).send(@method, 1.0).should == 0.75 - Rational(7, 4).send(@method, 0.26).should be_close(0.19, 0.0001) - end - - it "raises ZeroDivisionError on zero denominator" do - lambda { - Rational(3, 5).send(@method, Rational(0, 1)) - }.should raise_error(ZeroDivisionError) - - lambda { - Rational(0, 1).send(@method, Rational(0, 1)) - }.should raise_error(ZeroDivisionError) - - lambda { - Rational(3, 5).send(@method, 0) - }.should raise_error(ZeroDivisionError) - end - - it "raises a ZeroDivisionError when the argument is 0.0" do - lambda { - Rational(3, 5).send(@method, 0.0) - }.should raise_error(ZeroDivisionError) - end -end diff --git a/spec/ruby/shared/rational/multiply.rb b/spec/ruby/shared/rational/multiply.rb deleted file mode 100644 index 05a9cfc5c8..0000000000 --- a/spec/ruby/shared/rational/multiply.rb +++ /dev/null @@ -1,62 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :rational_multiply_rat, shared: true do - it "returns self divided by other as a Rational" do - (Rational(3, 4) * Rational(3, 4)).should eql(Rational(9, 16)) - (Rational(2, 4) * Rational(1, 4)).should eql(Rational(1, 8)) - - (Rational(3, 4) * Rational(0, 1)).should eql(Rational(0, 4)) - end -end - -describe :rational_multiply_int, shared: true do - it "returns self divided by other as a Rational" do - (Rational(3, 4) * 2).should eql(Rational(3, 2)) - (Rational(2, 4) * 2).should eql(Rational(1, 1)) - (Rational(6, 7) * -2).should eql(Rational(-12, 7)) - - (Rational(3, 4) * 0).should eql(Rational(0, 4)) - end -end - -describe :rational_multiply_float, shared: true do - it "returns self divided by other as a Float" do - (Rational(3, 4) * 0.75).should eql(0.5625) - (Rational(3, 4) * 0.25).should eql(0.1875) - (Rational(3, 4) * 0.3).should be_close(0.225, TOLERANCE) - - (Rational(-3, 4) * 0.3).should be_close(-0.225, TOLERANCE) - (Rational(3, -4) * 0.3).should be_close(-0.225, TOLERANCE) - (Rational(3, 4) * -0.3).should be_close(-0.225, TOLERANCE) - - (Rational(3, 4) * 0.0).should eql(0.0) - (Rational(-3, -4) * 0.0).should eql(0.0) - - (Rational(-3, 4) * 0.0).should eql(0.0) - (Rational(3, -4) * 0.0).should eql(0.0) - end -end - -describe :rational_multiply, shared: true do - it "calls #coerce on the passed argument with self" do - rational = Rational(3, 4) - obj = mock("Object") - obj.should_receive(:coerce).with(rational).and_return([1, 2]) - - rational * obj - end - - it "calls #* on the coerced Rational with the coerced Object" do - rational = Rational(3, 4) - - coerced_rational = mock("Coerced Rational") - coerced_rational.should_receive(:*).and_return(:result) - - coerced_obj = mock("Coerced Object") - - obj = mock("Object") - obj.should_receive(:coerce).and_return([coerced_rational, coerced_obj]) - - (rational * obj).should == :result - end -end diff --git a/spec/ruby/shared/rational/numerator.rb b/spec/ruby/shared/rational/numerator.rb deleted file mode 100644 index e4868ef43c..0000000000 --- a/spec/ruby/shared/rational/numerator.rb +++ /dev/null @@ -1,10 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :rational_numerator, shared: true do - it "returns the numerator" do - Rational(3, 4).numerator.should equal(3) - Rational(3, -4).numerator.should equal(-3) - - Rational(bignum_value, 1).numerator.should == bignum_value - end -end diff --git a/spec/ruby/shared/rational/plus.rb b/spec/ruby/shared/rational/plus.rb deleted file mode 100644 index e37c757c13..0000000000 --- a/spec/ruby/shared/rational/plus.rb +++ /dev/null @@ -1,48 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :rational_plus_rat, shared: true do - it "returns the result of subtracting other from self as a Rational" do - (Rational(3, 4) + Rational(0, 1)).should eql(Rational(3, 4)) - (Rational(3, 4) + Rational(1, 4)).should eql(Rational(1, 1)) - - (Rational(3, 4) + Rational(2, 1)).should eql(Rational(11, 4)) - end -end - -describe :rational_plus_int, shared: true do - it "returns the result of subtracting other from self as a Rational" do - (Rational(3, 4) + 1).should eql(Rational(7, 4)) - (Rational(3, 4) + 2).should eql(Rational(11, 4)) - end -end - -describe :rational_plus_float, shared: true do - it "returns the result of subtracting other from self as a Float" do - (Rational(3, 4) + 0.2).should eql(0.95) - (Rational(3, 4) + 2.5).should eql(3.25) - end -end - -describe :rational_plus, shared: true do - it "calls #coerce on the passed argument with self" do - rational = Rational(3, 4) - obj = mock("Object") - obj.should_receive(:coerce).with(rational).and_return([1, 2]) - - rational + obj - end - - it "calls #+ on the coerced Rational with the coerced Object" do - rational = Rational(3, 4) - - coerced_rational = mock("Coerced Rational") - coerced_rational.should_receive(:+).and_return(:result) - - coerced_obj = mock("Coerced Object") - - obj = mock("Object") - obj.should_receive(:coerce).and_return([coerced_rational, coerced_obj]) - - (rational + obj).should == :result - end -end diff --git a/spec/ruby/shared/rational/quo.rb b/spec/ruby/shared/rational/quo.rb deleted file mode 100644 index 61bd3fad9d..0000000000 --- a/spec/ruby/shared/rational/quo.rb +++ /dev/null @@ -1,5 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :rational_quo, shared: true do - it "needs to be reviewed for spec completeness" -end diff --git a/spec/ruby/shared/rational/remainder.rb b/spec/ruby/shared/rational/remainder.rb deleted file mode 100644 index 64aeb55e6c..0000000000 --- a/spec/ruby/shared/rational/remainder.rb +++ /dev/null @@ -1,5 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :rational_remainder, shared: true do - it "needs to be reviewed for spec completeness" -end diff --git a/spec/ruby/shared/rational/round.rb b/spec/ruby/shared/rational/round.rb deleted file mode 100644 index c7a4cc6d07..0000000000 --- a/spec/ruby/shared/rational/round.rb +++ /dev/null @@ -1,96 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :rational_round, shared: true do - before do - @rational = Rational(2200, 7) - end - - describe "with no arguments (precision = 0)" do - it "returns an integer" do - @rational.round.should be_kind_of(Integer) - Rational(0, 1).round(0).should be_kind_of(Integer) - Rational(124, 1).round(0).should be_kind_of(Integer) - end - - it "returns the truncated value toward the nearest integer" do - @rational.round.should == 314 - Rational(0, 1).round(0).should == 0 - Rational(2, 1).round(0).should == 2 - end - - it "returns the rounded value toward the nearest integer" do - Rational(1, 2).round.should == 1 - Rational(-1, 2).round.should == -1 - Rational(3, 2).round.should == 2 - Rational(-3, 2).round.should == -2 - Rational(5, 2).round.should == 3 - Rational(-5, 2).round.should == -3 - end - end - - describe "with a precision < 0" do - it "returns an integer" do - @rational.round(-2).should be_kind_of(Integer) - @rational.round(-1).should be_kind_of(Integer) - Rational(0, 1).round(-1).should be_kind_of(Integer) - Rational(2, 1).round(-1).should be_kind_of(Integer) - end - - it "moves the truncation point n decimal places left" do - @rational.round(-3).should == 0 - @rational.round(-2).should == 300 - @rational.round(-1).should == 310 - end - end - - describe "with a precision > 0" do - it "returns a Rational" do - @rational.round(1).should be_kind_of(Rational) - @rational.round(2).should be_kind_of(Rational) - Rational(0, 1).round(1).should be_kind_of(Rational) - Rational(2, 1).round(1).should be_kind_of(Rational) - end - - it "moves the truncation point n decimal places right" do - @rational.round(1).should == Rational(3143, 10) - @rational.round(2).should == Rational(31429, 100) - @rational.round(3).should == Rational(157143, 500) - Rational(0, 1).round(1).should == Rational(0, 1) - Rational(2, 1).round(1).should == Rational(2, 1) - end - - it "doesn't alter the value if the precision is too great" do - Rational(3, 2).round(10).should == Rational(3, 2).round(20) - end - - # #6605 - it "doesn't fail when rounding to an absurdly large positive precision" do - Rational(3, 2).round(2_097_171).should == Rational(3, 2) - end - end - - ruby_version_is "2.4" do - describe "with half option" do - it "returns an Integer when precision is not passed" do - Rational(10, 4).round(half: :up).should == 3 - Rational(10, 4).round(half: :down).should == 2 - Rational(10, 4).round(half: :even).should == 2 - Rational(-10, 4).round(half: :up).should == -3 - Rational(-10, 4).round(half: :down).should == -2 - Rational(-10, 4).round(half: :even).should == -2 - end - - it "returns a Rational when the precision is greater than 0" do - Rational(25, 100).round(1, half: :up).should == Rational(3, 10) - Rational(25, 100).round(1, half: :down).should == Rational(1, 5) - Rational(25, 100).round(1, half: :even).should == Rational(1, 5) - Rational(35, 100).round(1, half: :up).should == Rational(2, 5) - Rational(35, 100).round(1, half: :down).should == Rational(3, 10) - Rational(35, 100).round(1, half: :even).should == Rational(2, 5) - Rational(-25, 100).round(1, half: :up).should == Rational(-3, 10) - Rational(-25, 100).round(1, half: :down).should == Rational(-1, 5) - Rational(-25, 100).round(1, half: :even).should == Rational(-1, 5) - end - end - end -end diff --git a/spec/ruby/shared/rational/to_f.rb b/spec/ruby/shared/rational/to_f.rb deleted file mode 100644 index 2c9afdddda..0000000000 --- a/spec/ruby/shared/rational/to_f.rb +++ /dev/null @@ -1,10 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :rational_to_f, shared: true do - it "returns self converted to a Float" do - Rational(3, 4).to_f.should eql(0.75) - Rational(3, -4).to_f.should eql(-0.75) - Rational(-1, 4).to_f.should eql(-0.25) - Rational(-1, -4).to_f.should eql(0.25) - end -end diff --git a/spec/ruby/shared/rational/to_i.rb b/spec/ruby/shared/rational/to_i.rb deleted file mode 100644 index b0db78b3a8..0000000000 --- a/spec/ruby/shared/rational/to_i.rb +++ /dev/null @@ -1,12 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :rational_to_i, shared: true do - it "converts self to an Integer by truncation" do - Rational(7, 4).to_i.should eql(1) - Rational(11, 4).to_i.should eql(2) - end - - it "converts self to an Integer by truncation" do - Rational(-7, 4).to_i.should eql(-1) - end -end diff --git a/spec/ruby/shared/rational/to_r.rb b/spec/ruby/shared/rational/to_r.rb deleted file mode 100644 index 646167614a..0000000000 --- a/spec/ruby/shared/rational/to_r.rb +++ /dev/null @@ -1,13 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :rational_to_r, shared: true do - conflicts_with :Prime do - it "returns self" do - a = Rational(3, 4) - a.to_r.should equal(a) - - a = Rational(bignum_value, 4) - a.to_r.should equal(a) - end - end -end diff --git a/spec/ruby/shared/rational/to_s.rb b/spec/ruby/shared/rational/to_s.rb deleted file mode 100644 index 429a021908..0000000000 --- a/spec/ruby/shared/rational/to_s.rb +++ /dev/null @@ -1,11 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :rational_to_s, shared: true do - it "returns a string representation of self" do - Rational(1, 1).to_s.should == "1/1" - Rational(2, 1).to_s.should == "2/1" - Rational(1, 2).to_s.should == "1/2" - Rational(-1, 3).to_s.should == "-1/3" - Rational(1, -3).to_s.should == "-1/3" - end -end diff --git a/spec/ruby/shared/rational/truncate.rb b/spec/ruby/shared/rational/truncate.rb deleted file mode 100644 index 993c654c45..0000000000 --- a/spec/ruby/shared/rational/truncate.rb +++ /dev/null @@ -1,45 +0,0 @@ -require File.expand_path('../../../spec_helper', __FILE__) - -describe :rational_truncate, shared: true do - before do - @rational = Rational(2200, 7) - end - - describe "with no arguments (precision = 0)" do - it "returns an integer" do - @rational.truncate.should be_kind_of(Integer) - end - - it "returns the truncated value toward 0" do - @rational.truncate.should == 314 - Rational(1, 2).truncate.should == 0 - Rational(-1, 2).truncate.should == 0 - end - end - - describe "with a precision < 0" do - it "returns an integer" do - @rational.truncate(-2).should be_kind_of(Integer) - @rational.truncate(-1).should be_kind_of(Integer) - end - - it "moves the truncation point n decimal places left" do - @rational.truncate(-3).should == 0 - @rational.truncate(-2).should == 300 - @rational.truncate(-1).should == 310 - end - end - - describe "with a precision > 0" do - it "returns a Rational" do - @rational.truncate(1).should be_kind_of(Rational) - @rational.truncate(2).should be_kind_of(Rational) - end - - it "moves the truncation point n decimal places right" do - @rational.truncate(1).should == Rational(1571, 5) - @rational.truncate(2).should == Rational(7857, 25) - @rational.truncate(3).should == Rational(62857, 200) - end - end -end diff --git a/spec/ruby/shared/sizedqueue/enque.rb b/spec/ruby/shared/sizedqueue/enque.rb new file mode 100644 index 0000000000..6804af3fb3 --- /dev/null +++ b/spec/ruby/shared/sizedqueue/enque.rb @@ -0,0 +1,129 @@ +describe :sizedqueue_enq, shared: true do + it "blocks if queued elements exceed size" do + q = @object.call(1) + + q.size.should == 0 + q.send(@method, :first_element) + q.size.should == 1 + + blocked_thread = Thread.new { q.send(@method, :second_element) } + sleep 0.01 until blocked_thread.stop? + + q.size.should == 1 + q.pop.should == :first_element + + blocked_thread.join + q.size.should == 1 + q.pop.should == :second_element + q.size.should == 0 + end + + it "raises a ThreadError if queued elements exceed size when not blocking" do + q = @object.call(2) + + non_blocking = true + add_to_queue = -> { q.send(@method, Object.new, non_blocking) } + + q.size.should == 0 + add_to_queue.call + q.size.should == 1 + add_to_queue.call + q.size.should == 2 + add_to_queue.should raise_error(ThreadError) + end + + it "interrupts enqueuing threads with ClosedQueueError when the queue is closed" do + q = @object.call(1) + q << 1 + + t = Thread.new { + -> { q.send(@method, 2) }.should raise_error(ClosedQueueError, "queue closed") + } + + Thread.pass until q.num_waiting == 1 + + q.close + + t.join + q.pop.should == 1 + end + + describe "with a timeout" do + it "returns self if the item was pushed in time" do + q = @object.call(1) + q << 1 + + t = Thread.new { + q.send(@method, 2, timeout: TIME_TOLERANCE).should == q + } + Thread.pass until t.status == "sleep" && q.num_waiting == 1 + q.pop + t.join + end + + it "does nothing if the timeout is nil" do + q = @object.call(1) + q << 1 + t = Thread.new { + q.send(@method, 2, timeout: nil).should == q + } + t.join(0.2).should == nil + q.pop + t.join + end + + it "returns nil if no space is available and timeout is 0" do + q = @object.call(1) + q.send(@method, 1, timeout: 0).should == q + q.send(@method, 2, timeout: 0).should == nil + end + + it "returns nil if no space is available in time" do + q = @object.call(1) + q << 1 + Thread.new { + q.send(@method, 2, timeout: 0.001).should == nil + }.join + end + + it "raise TypeError if timeout is not a valid numeric" do + q = @object.call(1) + -> { + q.send(@method, 2, timeout: "1") + }.should raise_error(TypeError, "no implicit conversion to float from string") + + -> { + q.send(@method, 2, timeout: false) + }.should raise_error(TypeError, "no implicit conversion to float from false") + end + + it "raise ArgumentError if non_block = true is passed too" do + q = @object.call(1) + -> { + q.send(@method, 2, true, timeout: 1) + }.should raise_error(ArgumentError, "can't set a timeout if non_block is enabled") + end + + it "raise ClosedQueueError when closed before enqueued" do + q = @object.call(1) + q.close + -> { q.send(@method, 2, timeout: 1) }.should raise_error(ClosedQueueError, "queue closed") + end + + it "interrupts enqueuing threads with ClosedQueueError when the queue is closed" do + q = @object.call(1) + q << 1 + + t = Thread.new { + -> { q.send(@method, 1, timeout: TIME_TOLERANCE) }.should raise_error(ClosedQueueError, "queue closed") + } + + Thread.pass until q.num_waiting == 1 + + q.close + + t.join + q.pop.should == 1 + end + end +end diff --git a/spec/ruby/shared/sizedqueue/max.rb b/spec/ruby/shared/sizedqueue/max.rb new file mode 100644 index 0000000000..ea10d24be0 --- /dev/null +++ b/spec/ruby/shared/sizedqueue/max.rb @@ -0,0 +1,47 @@ +describe :sizedqueue_max, shared: true do + it "returns the size of the queue" do + q = @object.call(5) + q.max.should == 5 + end +end + +describe :sizedqueue_max=, shared: true do + it "sets the size of the queue" do + q = @object.call(5) + q.max.should == 5 + q.max = 10 + q.max.should == 10 + end + + it "does not remove items already in the queue beyond the maximum" do + q = @object.call(5) + q.enq 1 + q.enq 2 + q.enq 3 + q.max = 2 + (q.size > q.max).should be_true + q.deq.should == 1 + q.deq.should == 2 + q.deq.should == 3 + end + + it "raises a TypeError when given a non-numeric value" do + q = @object.call(5) + -> { q.max = "foo" }.should raise_error(TypeError) + -> { q.max = Object.new }.should raise_error(TypeError) + end + + it "raises an argument error when set to zero" do + q = @object.call(5) + q.max.should == 5 + -> { q.max = 0 }.should raise_error(ArgumentError) + q.max.should == 5 + end + + it "raises an argument error when set to a negative number" do + q = @object.call(5) + q.max.should == 5 + -> { q.max = -1 }.should raise_error(ArgumentError) + q.max.should == 5 + end +end diff --git a/spec/ruby/shared/sizedqueue/new.rb b/spec/ruby/shared/sizedqueue/new.rb new file mode 100644 index 0000000000..2573194efb --- /dev/null +++ b/spec/ruby/shared/sizedqueue/new.rb @@ -0,0 +1,23 @@ +describe :sizedqueue_new, shared: true do + it "raises a TypeError when the given argument doesn't respond to #to_int" do + -> { @object.call("12") }.should raise_error(TypeError) + -> { @object.call(Object.new) }.should raise_error(TypeError) + + @object.call(12.9).max.should == 12 + object = Object.new + object.define_singleton_method(:to_int) { 42 } + @object.call(object).max.should == 42 + end + + it "raises an argument error when no argument is given" do + -> { @object.call }.should raise_error(ArgumentError) + end + + it "raises an argument error when the given argument is zero" do + -> { @object.call(0) }.should raise_error(ArgumentError) + end + + it "raises an argument error when the given argument is negative" do + -> { @object.call(-1) }.should raise_error(ArgumentError) + end +end diff --git a/spec/ruby/shared/sizedqueue/num_waiting.rb b/spec/ruby/shared/sizedqueue/num_waiting.rb new file mode 100644 index 0000000000..8c31e48ca5 --- /dev/null +++ b/spec/ruby/shared/sizedqueue/num_waiting.rb @@ -0,0 +1,12 @@ +describe :sizedqueue_num_waiting, shared: true do + it "reports the number of threads waiting to push" do + q = @object.call(1) + q.push(1) + t = Thread.new { q.push(2) } + sleep 0.05 until t.stop? + q.num_waiting.should == 1 + + q.pop + t.join + end +end diff --git a/spec/ruby/shared/string/end_with.rb b/spec/ruby/shared/string/end_with.rb new file mode 100644 index 0000000000..08f43c1bce --- /dev/null +++ b/spec/ruby/shared/string/end_with.rb @@ -0,0 +1,61 @@ +describe :end_with, shared: true do + # the @method should either be :to_s or :to_sym + + it "returns true only if ends match" do + s = "hello".send(@method) + s.should.end_with?('o') + s.should.end_with?('llo') + end + + it 'returns false if the end does not match' do + s = 'hello'.send(@method) + s.should_not.end_with?('ll') + end + + it "returns true if the search string is empty" do + "hello".send(@method).should.end_with?("") + "".send(@method).should.end_with?("") + end + + it "returns true only if any ending match" do + "hello".send(@method).should.end_with?('x', 'y', 'llo', 'z') + end + + it "converts its argument using :to_str" do + s = "hello".send(@method) + find = mock('o') + find.should_receive(:to_str).and_return("o") + s.should.end_with?(find) + end + + it "ignores arguments not convertible to string" do + "hello".send(@method).should_not.end_with?() + -> { "hello".send(@method).end_with?(1) }.should raise_error(TypeError) + -> { "hello".send(@method).end_with?(["o"]) }.should raise_error(TypeError) + -> { "hello".send(@method).end_with?(1, nil, "o") }.should raise_error(TypeError) + end + + it "uses only the needed arguments" do + find = mock('h') + find.should_not_receive(:to_str) + "hello".send(@method).should.end_with?("o", find) + end + + it "works for multibyte strings" do + "céréale".send(@method).should.end_with?("réale") + end + + it "raises an Encoding::CompatibilityError if the encodings are incompatible" do + pat = "ア".encode Encoding::EUC_JP + -> do + "あれ".send(@method).end_with?(pat) + end.should raise_error(Encoding::CompatibilityError) + end + + it "checks that we are starting to match at the head of a character" do + "\xC3\xA9".send(@method).should_not.end_with?("\xA9") + "\xe3\x81\x82".send(@method).should_not.end_with?("\x82") + "\xd8\x00\xdc\x00".dup.force_encoding("UTF-16BE").send(@method).should_not.end_with?( + "\xdc\x00".dup.force_encoding("UTF-16BE")) + end +end diff --git a/spec/ruby/shared/string/start_with.rb b/spec/ruby/shared/string/start_with.rb new file mode 100644 index 0000000000..4b947a3bbf --- /dev/null +++ b/spec/ruby/shared/string/start_with.rb @@ -0,0 +1,84 @@ +describe :start_with, shared: true do + # the @method should either be :to_s or :to_sym + + it "returns true only if beginning match" do + s = "hello".send(@method) + s.should.start_with?('h') + s.should.start_with?('hel') + s.should_not.start_with?('el') + end + + it "returns true only if any beginning match" do + "hello".send(@method).should.start_with?('x', 'y', 'he', 'z') + end + + it "returns true if the search string is empty" do + "hello".send(@method).should.start_with?("") + "".send(@method).should.start_with?("") + end + + it "converts its argument using :to_str" do + s = "hello".send(@method) + find = mock('h') + find.should_receive(:to_str).and_return("h") + s.should.start_with?(find) + end + + it "ignores arguments not convertible to string" do + "hello".send(@method).should_not.start_with?() + -> { "hello".send(@method).start_with?(1) }.should raise_error(TypeError) + -> { "hello".send(@method).start_with?(["h"]) }.should raise_error(TypeError) + -> { "hello".send(@method).start_with?(1, nil, "h") }.should raise_error(TypeError) + end + + it "uses only the needed arguments" do + find = mock('h') + find.should_not_receive(:to_str) + "hello".send(@method).should.start_with?("h",find) + end + + it "works for multibyte strings" do + "céréale".send(@method).should.start_with?("cér") + end + + it "supports regexps" do + regexp = /[h1]/ + "hello".send(@method).should.start_with?(regexp) + "1337".send(@method).should.start_with?(regexp) + "foxes are 1337".send(@method).should_not.start_with?(regexp) + "chunky\n12bacon".send(@method).should_not.start_with?(/12/) + end + + it "supports regexps with ^ and $ modifiers" do + regexp1 = /^\d{2}/ + regexp2 = /\d{2}$/ + "12test".send(@method).should.start_with?(regexp1) + "test12".send(@method).should_not.start_with?(regexp1) + "12test".send(@method).should_not.start_with?(regexp2) + "test12".send(@method).should_not.start_with?(regexp2) + end + + it "sets Regexp.last_match if it returns true" do + regexp = /test-(\d+)/ + "test-1337".send(@method).start_with?(regexp).should be_true + Regexp.last_match.should_not be_nil + Regexp.last_match[1].should == "1337" + $1.should == "1337" + + "test-asdf".send(@method).start_with?(regexp).should be_false + Regexp.last_match.should be_nil + $1.should be_nil + end + + ruby_version_is ""..."3.3" do + it "does not check that we are not matching part of a character" do + "\xC3\xA9".send(@method).should.start_with?("\xC3") + end + end + + ruby_version_is "3.3" do # #19784 + it "checks that we are not matching part of a character" do + "\xC3\xA9".send(@method).should_not.start_with?("\xC3") + end + end +end diff --git a/spec/ruby/shared/string/times.rb b/spec/ruby/shared/string/times.rb index c44a76c9b7..4814f894cf 100644 --- a/spec/ruby/shared/string/times.rb +++ b/spec/ruby/shared/string/times.rb @@ -18,47 +18,41 @@ describe :string_times, shared: true do end it "raises an ArgumentError when given integer is negative" do - lambda { @object.call("cool", -3) }.should raise_error(ArgumentError) - lambda { @object.call("cool", -3.14) }.should raise_error(ArgumentError) + -> { @object.call("cool", -3) }.should raise_error(ArgumentError) + -> { @object.call("cool", -3.14) }.should raise_error(ArgumentError) + -> { @object.call("cool", min_long) }.should raise_error(ArgumentError) end it "raises a RangeError when given integer is a Bignum" do - lambda { @object.call("cool", 999999999999999999999) }.should raise_error(RangeError) + -> { @object.call("cool", 999999999999999999999) }.should raise_error(RangeError) + -> { @object.call("", 999999999999999999999) }.should raise_error(RangeError) end - it "returns subclass instances" do - @object.call(MyString.new("cool"), 0).should be_an_instance_of(MyString) - @object.call(MyString.new("cool"), 1).should be_an_instance_of(MyString) - @object.call(MyString.new("cool"), 2).should be_an_instance_of(MyString) + it "works with huge long values when string is empty" do + @object.call("", max_long).should == "" end - it "always taints the result when self is tainted" do - ["", "OK", MyString.new(""), MyString.new("OK")].each do |str| - str.taint - - [0, 1, 2].each do |arg| - @object.call(str, arg).tainted?.should == true - end - end + it "returns String instances" do + @object.call(MyString.new("cool"), 0).should be_an_instance_of(String) + @object.call(MyString.new("cool"), 1).should be_an_instance_of(String) + @object.call(MyString.new("cool"), 2).should be_an_instance_of(String) end - with_feature :encoding do - it "returns a String in the same encoding as self" do - str = "\xE3\x81\x82".force_encoding Encoding::UTF_8 - result = @object.call(str, 2) - result.encoding.should equal(Encoding::UTF_8) - end + it "returns a String in the same encoding as self" do + str = "\xE3\x81\x82".dup.force_encoding Encoding::UTF_8 + result = @object.call(str, 2) + result.encoding.should equal(Encoding::UTF_8) end - platform_is wordsize: 32 do + platform_is c_long_size: 32 do it "raises an ArgumentError if the length of the resulting string doesn't fit into a long" do - lambda { @object.call("abc", (2 ** 31) - 1) }.should raise_error(ArgumentError) + -> { @object.call("abc", (2 ** 31) - 1) }.should raise_error(ArgumentError) end end - platform_is wordsize: 64 do + platform_is c_long_size: 64 do it "raises an ArgumentError if the length of the resulting string doesn't fit into a long" do - lambda { @object.call("abc", (2 ** 63) - 1) }.should raise_error(ArgumentError) + -> { @object.call("abc", (2 ** 63) - 1) }.should raise_error(ArgumentError) end end end diff --git a/spec/ruby/shared/time/strftime_for_date.rb b/spec/ruby/shared/time/strftime_for_date.rb index f126c5a323..dbb124adc8 100644 --- a/spec/ruby/shared/time/strftime_for_date.rb +++ b/spec/ruby/shared/time/strftime_for_date.rb @@ -264,12 +264,10 @@ describe :strftime_date, shared: true do @new_date[2001,3,22].strftime("%-m/%-d/%-y").should == "3/22/1" end - with_feature :encoding do - it "passes the format string's encoding to the result string" do - result = @new_date[2010,3,8].strftime("%d. März %Y") + it "passes the format string's encoding to the result string" do + result = @new_date[2010,3,8].strftime("%d. März %Y") - result.encoding.should == Encoding::UTF_8 - result.should == "08. März 2010" - end + result.encoding.should == Encoding::UTF_8 + result.should == "08. März 2010" end end diff --git a/spec/ruby/shared/time/strftime_for_time.rb b/spec/ruby/shared/time/strftime_for_time.rb index 49cd09051a..9f4d08d72e 100644 --- a/spec/ruby/shared/time/strftime_for_time.rb +++ b/spec/ruby/shared/time/strftime_for_time.rb @@ -170,4 +170,12 @@ describe :strftime_time, shared: true do time.strftime("%-k%p").should == "8AM" time.strftime("%-l%p").should == "8AM" end + + it "should be able to show default Logger format" do + default_logger_format = "%Y-%m-%dT%H:%M:%S.%6N " + @new_time[2001, 2, 3, 4, 5, 6].strftime(default_logger_format).should == "2001-02-03T04:05:06.000000 " + @new_time[2001, 12, 3, 4, 5, 6 + 1/10r].strftime(default_logger_format).should == "2001-12-03T04:05:06.100000 " + @new_time[2001, 2, 13, 4, 5, 6 + 1/100r].strftime(default_logger_format).should == "2001-02-13T04:05:06.010000 " + @new_time[2001, 2, 3, 14, 5, 6 + 1/1000r].strftime(default_logger_format).should == "2001-02-03T14:05:06.001000 " + end end diff --git a/spec/ruby/shared/time/yday.rb b/spec/ruby/shared/time/yday.rb new file mode 100644 index 0000000000..f81c45261c --- /dev/null +++ b/spec/ruby/shared/time/yday.rb @@ -0,0 +1,18 @@ +describe :time_yday, shared: true do + it 'returns the correct value for each day of each month' do + mdays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] + + yday = 1 + mdays.each_with_index do |days, month| + days.times do |day| + @method.call(2014, month+1, day+1).should == yday + yday += 1 + end + end + end + + it 'supports leap years' do + @method.call(2016, 2, 29).should == 31 + 29 + @method.call(2016, 3, 1).should == 31 + 29 + 1 + end +end diff --git a/spec/ruby/shared/types/rb_num2dbl_fails.rb b/spec/ruby/shared/types/rb_num2dbl_fails.rb new file mode 100644 index 0000000000..ec7cc11986 --- /dev/null +++ b/spec/ruby/shared/types/rb_num2dbl_fails.rb @@ -0,0 +1,17 @@ +# +# Shared tests for rb_num2dbl related conversion failures. +# +# Usage example: +# it_behaves_like :rb_num2dbl_fails, nil, -> v { o = A.new; o.foo(v) } +# + +describe :rb_num2dbl_fails, shared: true do + it "fails if string is provided" do + -> { @object.call("123") }.should raise_error(TypeError, "no implicit conversion to float from string") + end + + it "fails if boolean is provided" do + -> { @object.call(true) }.should raise_error(TypeError, "no implicit conversion to float from true") + -> { @object.call(false) }.should raise_error(TypeError, "no implicit conversion to float from false") + end +end |
