diff options
Diffstat (limited to 'spec/ruby/core/complex')
49 files changed, 1367 insertions, 0 deletions
diff --git a/spec/ruby/core/complex/abs2_spec.rb b/spec/ruby/core/complex/abs2_spec.rb new file mode 100644 index 0000000000..3e5c5fd225 --- /dev/null +++ b/spec/ruby/core/complex/abs2_spec.rb @@ -0,0 +1,9 @@ +require_relative '../../spec_helper' + +describe "Complex#abs2" 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) + Complex(0).abs2.should == 0 + end +end diff --git a/spec/ruby/core/complex/abs_spec.rb b/spec/ruby/core/complex/abs_spec.rb new file mode 100644 index 0000000000..43912c517f --- /dev/null +++ b/spec/ruby/core/complex/abs_spec.rb @@ -0,0 +1,6 @@ +require_relative '../../spec_helper' +require_relative 'shared/abs' + +describe "Complex#abs" do + it_behaves_like :complex_abs, :abs +end diff --git a/spec/ruby/core/complex/angle_spec.rb b/spec/ruby/core/complex/angle_spec.rb new file mode 100644 index 0000000000..4aa176956f --- /dev/null +++ b/spec/ruby/core/complex/angle_spec.rb @@ -0,0 +1,6 @@ +require_relative '../../spec_helper' +require_relative 'shared/arg' + +describe "Complex#angle" do + it_behaves_like :complex_arg, :angle +end diff --git a/spec/ruby/core/complex/arg_spec.rb b/spec/ruby/core/complex/arg_spec.rb new file mode 100644 index 0000000000..009f19429f --- /dev/null +++ b/spec/ruby/core/complex/arg_spec.rb @@ -0,0 +1,6 @@ +require_relative '../../spec_helper' +require_relative 'shared/arg' + +describe "Complex#arg" do + it_behaves_like :complex_arg, :arg +end diff --git a/spec/ruby/core/complex/coerce_spec.rb b/spec/ruby/core/complex/coerce_spec.rb new file mode 100644 index 0000000000..a30a6c1d5f --- /dev/null +++ b/spec/ruby/core/complex/coerce_spec.rb @@ -0,0 +1,70 @@ +require_relative '../../spec_helper' + +describe "Complex#coerce" 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) + -> { @one.coerce(other) }.should raise_error(TypeError) + end + + it "raises a TypeError when other is a String" do + -> { @one.coerce("20") }.should raise_error(TypeError) + end + + it "raises a TypeError when other is nil" do + -> { @one.coerce(nil) }.should raise_error(TypeError) + end + + it "raises a TypeError when other is false" do + -> { @one.coerce(false) }.should raise_error(TypeError) + end +end diff --git a/spec/ruby/core/complex/comparison_spec.rb b/spec/ruby/core/complex/comparison_spec.rb new file mode 100644 index 0000000000..3a3142f234 --- /dev/null +++ b/spec/ruby/core/complex/comparison_spec.rb @@ -0,0 +1,25 @@ +require_relative '../../spec_helper' + +describe "Complex#<=>" do + it "returns nil if either self or argument has imaginary part" do + (Complex(5, 1) <=> Complex(2)).should be_nil + (Complex(1) <=> Complex(2, 1)).should be_nil + (5 <=> Complex(2, 1)).should be_nil + end + + it "returns nil if argument is not numeric" do + (Complex(5, 1) <=> "cmp").should be_nil + (Complex(1) <=> "cmp").should be_nil + (Complex(1) <=> Object.new).should be_nil + end + + it "returns 0, 1, or -1 if self and argument do not have imaginary part" do + (Complex(5) <=> Complex(2)).should == 1 + (Complex(2) <=> Complex(3)).should == -1 + (Complex(2) <=> Complex(2)).should == 0 + + (Complex(5) <=> 2).should == 1 + (Complex(2) <=> 3).should == -1 + (Complex(2) <=> 2).should == 0 + end +end diff --git a/spec/ruby/core/complex/conj_spec.rb b/spec/ruby/core/complex/conj_spec.rb new file mode 100644 index 0000000000..5e3bc1acb8 --- /dev/null +++ b/spec/ruby/core/complex/conj_spec.rb @@ -0,0 +1,6 @@ +require_relative '../../spec_helper' +require_relative 'shared/conjugate' + +describe "Complex#conj" do + it_behaves_like :complex_conjugate, :conj +end diff --git a/spec/ruby/core/complex/conjugate_spec.rb b/spec/ruby/core/complex/conjugate_spec.rb new file mode 100644 index 0000000000..f658bab4da --- /dev/null +++ b/spec/ruby/core/complex/conjugate_spec.rb @@ -0,0 +1,6 @@ +require_relative '../../spec_helper' +require_relative 'shared/conjugate' + +describe "Complex#conjugate" do + it_behaves_like :complex_conjugate, :conjugate +end diff --git a/spec/ruby/core/complex/constants_spec.rb b/spec/ruby/core/complex/constants_spec.rb new file mode 100644 index 0000000000..50303de16c --- /dev/null +++ b/spec/ruby/core/complex/constants_spec.rb @@ -0,0 +1,7 @@ +require_relative '../../spec_helper' + +describe "Complex::I" do + it "is Complex(0, 1)" do + Complex::I.should eql(Complex(0, 1)) + end +end diff --git a/spec/ruby/core/complex/denominator_spec.rb b/spec/ruby/core/complex/denominator_spec.rb new file mode 100644 index 0000000000..c1a2003820 --- /dev/null +++ b/spec/ruby/core/complex/denominator_spec.rb @@ -0,0 +1,13 @@ +require_relative '../../spec_helper' + +describe "Complex#denominator" 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/core/complex/divide_spec.rb b/spec/ruby/core/complex/divide_spec.rb new file mode 100644 index 0000000000..bebf862312 --- /dev/null +++ b/spec/ruby/core/complex/divide_spec.rb @@ -0,0 +1,6 @@ +require_relative '../../spec_helper' +require_relative 'shared/divide' + +describe "Complex#/" do + it_behaves_like :complex_divide, :/ +end diff --git a/spec/ruby/core/complex/eql_spec.rb b/spec/ruby/core/complex/eql_spec.rb new file mode 100644 index 0000000000..9194efc074 --- /dev/null +++ b/spec/ruby/core/complex/eql_spec.rb @@ -0,0 +1,31 @@ +require_relative '../../spec_helper' + +describe "Complex#eql?" do + it "returns false if other is not Complex" do + Complex(1).eql?(1).should be_false + end + + it "returns true when the respective parts are of the same classes and self == other" do + Complex(1, 2).eql?(Complex(1, 2)).should be_true + end + + it "returns false when the real parts are of different classes" do + Complex(1).eql?(Complex(1.0)).should be_false + end + + it "returns false when the imaginary parts are of different classes" do + Complex(1, 2).eql?(Complex(1, 2.0)).should be_false + end + + it "returns false when self == other is false" do + Complex(1, 2).eql?(Complex(2, 3)).should be_false + end + + it "does NOT send #eql? to real or imaginary parts" do + real = mock_numeric('real') + imag = mock_numeric('imag') + real.should_not_receive(:eql?) + imag.should_not_receive(:eql?) + Complex(real, imag).eql?(Complex(real, imag)).should be_true + end +end diff --git a/spec/ruby/core/complex/equal_value_spec.rb b/spec/ruby/core/complex/equal_value_spec.rb new file mode 100644 index 0000000000..97c486d820 --- /dev/null +++ b/spec/ruby/core/complex/equal_value_spec.rb @@ -0,0 +1,93 @@ +require_relative '../../spec_helper' + +describe "Complex#==" 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 + # Integer#== and Float#== 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 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/core/complex/exponent_spec.rb b/spec/ruby/core/complex/exponent_spec.rb new file mode 100644 index 0000000000..86f827aece --- /dev/null +++ b/spec/ruby/core/complex/exponent_spec.rb @@ -0,0 +1,61 @@ +require_relative '../../spec_helper' + +describe "Complex#**" do + describe "with Integer 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/core/complex/fdiv_spec.rb b/spec/ruby/core/complex/fdiv_spec.rb new file mode 100644 index 0000000000..68f7d1b309 --- /dev/null +++ b/spec/ruby/core/complex/fdiv_spec.rb @@ -0,0 +1,129 @@ +require_relative '../../spec_helper' + +describe "Complex#fdiv" do + it "accepts a numeric argument" do + -> { Complex(20).fdiv(2) }.should_not raise_error(TypeError) + -> { Complex(20).fdiv(2.0) }.should_not raise_error(TypeError) + -> { Complex(20).fdiv(bignum_value) }.should_not raise_error(TypeError) + end + + it "accepts a negative numeric argument" do + -> { Complex(20).fdiv(-2) }.should_not raise_error(TypeError) + -> { Complex(20).fdiv(-2.0) }.should_not raise_error(TypeError) + -> { Complex(20).fdiv(-bignum_value) }.should_not raise_error(TypeError) + end + + it "raises a TypeError if passed a non-numeric argument" do + -> { Complex(20).fdiv([]) }.should raise_error(TypeError) + -> { Complex(20).fdiv(:sym) }.should raise_error(TypeError) + -> { Complex(20).fdiv('s') }.should raise_error(TypeError) + end + + it "sets the real part to NaN if self's real part is NaN" do + Complex(nan_value).fdiv(2).real.nan?.should be_true + end + + it "sets the imaginary part to NaN if self's imaginary part is NaN" do + Complex(2, nan_value).fdiv(2).imag.nan?.should be_true + end + + it "sets the real and imaginary part to NaN if self's real and imaginary parts are NaN" do + Complex(nan_value, nan_value).fdiv(2).imag.nan?.should be_true + Complex(nan_value, nan_value).fdiv(2).real.nan?.should be_true + end + + it "sets the real and imaginary part to NaN if self's real part and the argument are both NaN" do + Complex(nan_value, 2).fdiv(nan_value).imag.nan?.should be_true + Complex(nan_value, 2).fdiv(nan_value).real.nan?.should be_true + end + + it "sets the real and imaginary part to NaN if self's real part, self's imaginary part, and the argument are NaN" do + Complex(nan_value, nan_value).fdiv(nan_value).imag.nan?.should be_true + Complex(nan_value, nan_value).fdiv(nan_value).real.nan?.should be_true + end + + it "sets the real part to Infinity if self's real part is Infinity" do + Complex(infinity_value).fdiv(2).real.infinite?.should == 1 + Complex(infinity_value,2).fdiv(2).real.infinite?.should == 1 + end + + it "sets the imaginary part to Infinity if self's imaginary part is Infinity" do + Complex(2, infinity_value).fdiv(2).imag.infinite?.should == 1 + Complex(2, infinity_value).fdiv(2).imag.infinite?.should == 1 + end + + it "sets the imaginary and real part to Infinity if self's imaginary and real parts are Infinity" do + Complex(infinity_value, infinity_value).fdiv(2).real.infinite?.should == 1 + Complex(infinity_value, infinity_value).fdiv(2).imag.infinite?.should == 1 + end + + it "sets the real part to NaN and the imaginary part to NaN if self's imaginary part, self's real part, and the argument are Infinity" do + Complex(infinity_value, infinity_value).fdiv(infinity_value).real.nan?.should be_true + Complex(infinity_value, infinity_value).fdiv(infinity_value).imag.nan?.should be_true + end +end + +describe "Complex#fdiv with no imaginary part" do + before :each do + @numbers = [1, 5.43, 10, bignum_value, 99872.2918710].map{|n| [n,-n]}.flatten + end + + it "returns a Complex number" do + @numbers.each do |real| + @numbers.each do |other| + Complex(real).fdiv(other).should be_an_instance_of(Complex) + end + end + end + + it "sets the real part to self's real part fdiv'd with the argument" do + @numbers.each do |real| + @numbers.each do |other| + Complex(real).fdiv(other).real.should == real.fdiv(other) + end + end + end + + it "sets the imaginary part to 0.0" do + @numbers.each do |real| + @numbers.each do |other| + Complex(real).fdiv(other).imaginary.should == 0.0 + end + end + end +end + +describe "Complex#fdiv with an imaginary part" do + before :each do + @numbers = [1, 5.43, 10, bignum_value, 99872.2918710].map{|n| [n,-n]}.flatten + end + + it "returns a Complex number" do + @numbers.each do |real| + @numbers.each_with_index do |other,idx| + Complex( + real,@numbers[idx == 0 ? -1 : idx-1] + ).fdiv(other).should be_an_instance_of(Complex) + end + end + end + + it "sets the real part to self's real part fdiv'd with the argument" do + @numbers.each do |real| + @numbers.each_with_index do |other,idx| + Complex( + real,@numbers[idx == 0 ? -1 : idx-1] + ).fdiv(other).real.should == real.fdiv(other) + end + end + end + + it "sets the imaginary part to the imaginary part fdiv'd with the argument" do + @numbers.each do |real| + @numbers.each_with_index do |other,idx| + im = @numbers[idx == 0 ? -1 : idx-1] + Complex(real, im).fdiv(other).imag.should == im.fdiv(other) + end + end + end +end diff --git a/spec/ruby/core/complex/finite_spec.rb b/spec/ruby/core/complex/finite_spec.rb new file mode 100644 index 0000000000..7d9f82404e --- /dev/null +++ b/spec/ruby/core/complex/finite_spec.rb @@ -0,0 +1,32 @@ +require_relative '../../spec_helper' + +describe "Complex#finite?" do + it "returns true if magnitude is finite" do + (1+1i).should.finite? + end + + it "returns false for positive infinity" do + value = Complex(Float::INFINITY, 42) + value.should_not.finite? + end + + it "returns false for positive complex with infinite imaginary" do + value = Complex(1, Float::INFINITY) + value.should_not.finite? + end + + it "returns false for negative infinity" do + value = -Complex(Float::INFINITY, 42) + value.should_not.finite? + end + + it "returns false for negative complex with infinite imaginary" do + value = -Complex(1, Float::INFINITY) + value.should_not.finite? + end + + it "returns false for NaN" do + value = Complex(Float::NAN, Float::NAN) + value.should_not.finite? + end +end diff --git a/spec/ruby/core/complex/hash_spec.rb b/spec/ruby/core/complex/hash_spec.rb new file mode 100644 index 0000000000..cad283309d --- /dev/null +++ b/spec/ruby/core/complex/hash_spec.rb @@ -0,0 +1,16 @@ +require_relative '../../spec_helper' + +describe "Complex#hash" 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/core/complex/imag_spec.rb b/spec/ruby/core/complex/imag_spec.rb new file mode 100644 index 0000000000..2bafd1ab54 --- /dev/null +++ b/spec/ruby/core/complex/imag_spec.rb @@ -0,0 +1,6 @@ +require_relative '../../spec_helper' +require_relative 'shared/image' + +describe "Complex#imag" do + it_behaves_like :complex_image, :imag +end diff --git a/spec/ruby/core/complex/imaginary_spec.rb b/spec/ruby/core/complex/imaginary_spec.rb new file mode 100644 index 0000000000..a8a1bfea90 --- /dev/null +++ b/spec/ruby/core/complex/imaginary_spec.rb @@ -0,0 +1,6 @@ +require_relative '../../spec_helper' +require_relative 'shared/image' + +describe "Complex#imaginary" do + it_behaves_like :complex_image, :imaginary +end diff --git a/spec/ruby/core/complex/infinite_spec.rb b/spec/ruby/core/complex/infinite_spec.rb new file mode 100644 index 0000000000..9e48860dee --- /dev/null +++ b/spec/ruby/core/complex/infinite_spec.rb @@ -0,0 +1,32 @@ +require_relative '../../spec_helper' + +describe "Complex#infinite?" do + it "returns nil if magnitude is finite" do + (1+1i).infinite?.should == nil + end + + it "returns 1 for positive infinity" do + value = Complex(Float::INFINITY, 42).infinite? + value.should == 1 + end + + it "returns 1 for positive complex with infinite imaginary" do + value = Complex(1, Float::INFINITY).infinite? + value.should == 1 + end + + it "returns -1 for negative infinity" do + value = -Complex(Float::INFINITY, 42).infinite? + value.should == -1 + end + + it "returns -1 for negative complex with infinite imaginary" do + value = -Complex(1, Float::INFINITY).infinite? + value.should == -1 + end + + it "returns nil for NaN" do + value = Complex(0, Float::NAN).infinite? + value.should == nil + end +end diff --git a/spec/ruby/core/complex/inspect_spec.rb b/spec/ruby/core/complex/inspect_spec.rb new file mode 100644 index 0000000000..045be94b22 --- /dev/null +++ b/spec/ruby/core/complex/inspect_spec.rb @@ -0,0 +1,37 @@ +require_relative '../../spec_helper' +require_relative '../numeric/fixtures/classes' + +describe "Complex#inspect" 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 + + it "calls #inspect on real and imaginary" do + real = NumericSpecs::Subclass.new + # + because of https://bugs.ruby-lang.org/issues/20337 + real.should_receive(:inspect).and_return(+"1") + imaginary = NumericSpecs::Subclass.new + imaginary.should_receive(:inspect).and_return("2") + imaginary.should_receive(:<).any_number_of_times.and_return(false) + Complex(real, imaginary).inspect.should == "(1+2i)" + end + + it "adds an `*' before the `i' if the last character of the imaginary part is not numeric" do + real = NumericSpecs::Subclass.new + # + because of https://bugs.ruby-lang.org/issues/20337 + real.should_receive(:inspect).and_return(+"(1)") + imaginary = NumericSpecs::Subclass.new + imaginary.should_receive(:inspect).and_return("(2)") + imaginary.should_receive(:<).any_number_of_times.and_return(false) + Complex(real, imaginary).inspect.should == "((1)+(2)*i)" + end +end diff --git a/spec/ruby/core/complex/integer_spec.rb b/spec/ruby/core/complex/integer_spec.rb new file mode 100644 index 0000000000..0957accb70 --- /dev/null +++ b/spec/ruby/core/complex/integer_spec.rb @@ -0,0 +1,11 @@ +require_relative '../../spec_helper' + +describe "Complex#integer?" do + it "returns false for a Complex with no imaginary part" do + Complex(20).integer?.should be_false + end + + it "returns false for a Complex with an imaginary part" do + Complex(20,3).integer?.should be_false + end +end diff --git a/spec/ruby/core/complex/magnitude_spec.rb b/spec/ruby/core/complex/magnitude_spec.rb new file mode 100644 index 0000000000..86f3b29868 --- /dev/null +++ b/spec/ruby/core/complex/magnitude_spec.rb @@ -0,0 +1,6 @@ +require_relative '../../spec_helper' +require_relative 'shared/abs' + +describe "Complex#magnitude" do + it_behaves_like :complex_abs, :magnitude +end diff --git a/spec/ruby/core/complex/marshal_dump_spec.rb b/spec/ruby/core/complex/marshal_dump_spec.rb new file mode 100644 index 0000000000..116899b0ad --- /dev/null +++ b/spec/ruby/core/complex/marshal_dump_spec.rb @@ -0,0 +1,11 @@ +require_relative '../../spec_helper' + +describe "Complex#marshal_dump" do + it "is a private method" do + Complex.should have_private_instance_method(:marshal_dump, false) + end + + it "dumps real and imaginary parts" do + Complex(1, 2).send(:marshal_dump).should == [1, 2] + end +end diff --git a/spec/ruby/core/complex/minus_spec.rb b/spec/ruby/core/complex/minus_spec.rb new file mode 100644 index 0000000000..7c104ce784 --- /dev/null +++ b/spec/ruby/core/complex/minus_spec.rb @@ -0,0 +1,45 @@ +require_relative '../../spec_helper' + +describe "Complex#-" 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/core/complex/multiply_spec.rb b/spec/ruby/core/complex/multiply_spec.rb new file mode 100644 index 0000000000..35bf7c8455 --- /dev/null +++ b/spec/ruby/core/complex/multiply_spec.rb @@ -0,0 +1,49 @@ +require_relative '../../spec_helper' + +describe "Complex#*" 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/core/complex/negative_spec.rb b/spec/ruby/core/complex/negative_spec.rb new file mode 100644 index 0000000000..62ab89c04a --- /dev/null +++ b/spec/ruby/core/complex/negative_spec.rb @@ -0,0 +1,13 @@ +require_relative '../../spec_helper' + +describe "Complex#negative?" do + it "is undefined" do + c = Complex(1) + + c.methods.should_not include(:negative?) + + -> { + c.negative? + }.should raise_error(NoMethodError) + end +end diff --git a/spec/ruby/core/complex/numerator_spec.rb b/spec/ruby/core/complex/numerator_spec.rb new file mode 100644 index 0000000000..7ab66e6a61 --- /dev/null +++ b/spec/ruby/core/complex/numerator_spec.rb @@ -0,0 +1,19 @@ +require_relative '../../spec_helper' + +describe "Complex#numerator" 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/core/complex/phase_spec.rb b/spec/ruby/core/complex/phase_spec.rb new file mode 100644 index 0000000000..89574bf533 --- /dev/null +++ b/spec/ruby/core/complex/phase_spec.rb @@ -0,0 +1,6 @@ +require_relative '../../spec_helper' +require_relative 'shared/arg' + +describe "Complex#phase" do + it_behaves_like :complex_arg, :phase +end diff --git a/spec/ruby/core/complex/plus_spec.rb b/spec/ruby/core/complex/plus_spec.rb new file mode 100644 index 0000000000..2056ca786c --- /dev/null +++ b/spec/ruby/core/complex/plus_spec.rb @@ -0,0 +1,45 @@ +require_relative '../../spec_helper' + +describe "Complex#+" 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/core/complex/polar_spec.rb b/spec/ruby/core/complex/polar_spec.rb new file mode 100644 index 0000000000..56335584ef --- /dev/null +++ b/spec/ruby/core/complex/polar_spec.rb @@ -0,0 +1,41 @@ +require_relative '../../spec_helper' + +describe "Complex.polar" 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 + + it "raises a TypeError when given non real arguments" do + ->{ Complex.polar(nil) }.should raise_error(TypeError) + ->{ Complex.polar(nil, nil) }.should raise_error(TypeError) + end + + it "computes the real values of the real & imaginary parts from the polar form" do + a = Complex.polar(1.0+0.0i, Math::PI/2+0.0i) + a.real.should be_close(0.0, TOLERANCE) + a.imag.should be_close(1.0, TOLERANCE) + a.real.real?.should be_true + a.imag.real?.should be_true + + b = Complex.polar(1+0.0i) + b.real.should be_close(1.0, TOLERANCE) + b.imag.should be_close(0.0, TOLERANCE) + b.real.real?.should be_true + b.imag.real?.should be_true + end +end + +describe "Complex#polar" 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/core/complex/positive_spec.rb b/spec/ruby/core/complex/positive_spec.rb new file mode 100644 index 0000000000..f1bad8608c --- /dev/null +++ b/spec/ruby/core/complex/positive_spec.rb @@ -0,0 +1,13 @@ +require_relative '../../spec_helper' + +describe "Complex#positive?" do + it "is undefined" do + c = Complex(1) + + c.methods.should_not include(:positive?) + + -> { + c.positive? + }.should raise_error(NoMethodError) + end +end diff --git a/spec/ruby/core/complex/quo_spec.rb b/spec/ruby/core/complex/quo_spec.rb new file mode 100644 index 0000000000..ee6fd65c79 --- /dev/null +++ b/spec/ruby/core/complex/quo_spec.rb @@ -0,0 +1,6 @@ +require_relative '../../spec_helper' +require_relative 'shared/divide' + +describe "Complex#quo" do + it_behaves_like :complex_divide, :quo +end diff --git a/spec/ruby/core/complex/rationalize_spec.rb b/spec/ruby/core/complex/rationalize_spec.rb new file mode 100644 index 0000000000..043b8ddf2a --- /dev/null +++ b/spec/ruby/core/complex/rationalize_spec.rb @@ -0,0 +1,31 @@ +require_relative '../../spec_helper' + +describe "Complex#rationalize" do + it "raises RangeError if self has non-zero imaginary part" do + -> { Complex(1,5).rationalize }.should raise_error(RangeError) + end + + it "raises RangeError if self has 0.0 imaginary part" do + -> { Complex(1,0.0).rationalize }.should raise_error(RangeError) + end + + it "returns a Rational if self has zero imaginary part" do + Complex(1,0).rationalize.should == Rational(1,1) + Complex(2<<63+5).rationalize.should == Rational(2<<63+5,1) + end + + it "sends #rationalize to the real part" do + real = mock_numeric('real') + real.should_receive(:rationalize).with(0.1).and_return(:result) + Complex(real, 0).rationalize(0.1).should == :result + end + + it "ignores a single argument" do + Complex(1,0).rationalize(0.1).should == Rational(1,1) + end + + it "raises ArgumentError when passed more than one argument" do + -> { Complex(1,0).rationalize(0.1, 0.1) }.should raise_error(ArgumentError) + -> { Complex(1,0).rationalize(0.1, 0.1, 2) }.should raise_error(ArgumentError) + end +end diff --git a/spec/ruby/core/complex/real_spec.rb b/spec/ruby/core/complex/real_spec.rb new file mode 100644 index 0000000000..2ea791c005 --- /dev/null +++ b/spec/ruby/core/complex/real_spec.rb @@ -0,0 +1,28 @@ +require_relative '../../spec_helper' + +describe "Complex#real" 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 + +describe "Complex#real?" do + it "returns false if there is an imaginary part" do + Complex(2,3).real?.should be_false + end + + it "returns false if there is not an imaginary part" do + Complex(2).real?.should be_false + end + + it "returns false if the real part is Infinity" do + Complex(infinity_value).real?.should be_false + end + + it "returns false if the real part is NaN" do + Complex(nan_value).real?.should be_false + end +end diff --git a/spec/ruby/core/complex/rect_spec.rb b/spec/ruby/core/complex/rect_spec.rb new file mode 100644 index 0000000000..9e95f3efc2 --- /dev/null +++ b/spec/ruby/core/complex/rect_spec.rb @@ -0,0 +1,10 @@ +require_relative '../../spec_helper' +require_relative 'shared/rect' + +describe "Complex#rect" do + it_behaves_like :complex_rect, :rect +end + +describe "Complex.rect" do + it_behaves_like :complex_rect_class, :rect +end diff --git a/spec/ruby/core/complex/rectangular_spec.rb b/spec/ruby/core/complex/rectangular_spec.rb new file mode 100644 index 0000000000..d4b8ad9782 --- /dev/null +++ b/spec/ruby/core/complex/rectangular_spec.rb @@ -0,0 +1,10 @@ +require_relative '../../spec_helper' +require_relative 'shared/rect' + +describe "Complex#rectangular" do + it_behaves_like :complex_rect, :rectangular +end + +describe "Complex.rectangular" do + it_behaves_like :complex_rect_class, :rectangular +end diff --git a/spec/ruby/core/complex/shared/abs.rb b/spec/ruby/core/complex/shared/abs.rb new file mode 100644 index 0000000000..2299479341 --- /dev/null +++ b/spec/ruby/core/complex/shared/abs.rb @@ -0,0 +1,10 @@ +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/core/complex/shared/arg.rb b/spec/ruby/core/complex/shared/arg.rb new file mode 100644 index 0000000000..c81f197433 --- /dev/null +++ b/spec/ruby/core/complex/shared/arg.rb @@ -0,0 +1,9 @@ +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/core/complex/shared/conjugate.rb b/spec/ruby/core/complex/shared/conjugate.rb new file mode 100644 index 0000000000..d1ae47bcb6 --- /dev/null +++ b/spec/ruby/core/complex/shared/conjugate.rb @@ -0,0 +1,8 @@ +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/core/complex/shared/divide.rb b/spec/ruby/core/complex/shared/divide.rb new file mode 100644 index 0000000000..a60802c74c --- /dev/null +++ b/spec/ruby/core/complex/shared/divide.rb @@ -0,0 +1,82 @@ +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 + -> { 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/core/complex/shared/image.rb b/spec/ruby/core/complex/shared/image.rb new file mode 100644 index 0000000000..f839dbcaf9 --- /dev/null +++ b/spec/ruby/core/complex/shared/image.rb @@ -0,0 +1,8 @@ +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/core/complex/shared/rect.rb b/spec/ruby/core/complex/shared/rect.rb new file mode 100644 index 0000000000..4ac294e771 --- /dev/null +++ b/spec/ruby/core/complex/shared/rect.rb @@ -0,0 +1,94 @@ +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| + -> { 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) + -> { 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) + -> { 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 + -> { Complex.send(@method, :sym) }.should raise_error(TypeError) + -> { Complex.send(@method, 0, :sym) }.should raise_error(TypeError) + end + end +end diff --git a/spec/ruby/core/complex/to_c_spec.rb b/spec/ruby/core/complex/to_c_spec.rb new file mode 100644 index 0000000000..5ce01d9d4e --- /dev/null +++ b/spec/ruby/core/complex/to_c_spec.rb @@ -0,0 +1,12 @@ +require_relative '../../spec_helper' + +describe "Complex#to_c" do + it "returns self" do + value = Complex(1, 5) + value.to_c.should equal(value) + end + + it 'returns the same value' do + Complex(1, 5).to_c.should == Complex(1, 5) + end +end diff --git a/spec/ruby/core/complex/to_f_spec.rb b/spec/ruby/core/complex/to_f_spec.rb new file mode 100644 index 0000000000..b53471c1fc --- /dev/null +++ b/spec/ruby/core/complex/to_f_spec.rb @@ -0,0 +1,41 @@ +require_relative '../../spec_helper' + +describe "Complex#to_f" do + describe "when the imaginary part is Integer 0" do + it "returns the result of sending #to_f to the real part" do + real = mock_numeric('real') + real.should_receive(:to_f).and_return(:f) + Complex(real, 0).to_f.should == :f + end + end + + describe "when the imaginary part is Rational 0" do + it "returns the result of sending #to_f to the real part" do + real = mock_numeric('real') + real.should_receive(:to_f).and_return(:f) + Complex(real, Rational(0)).to_f.should == :f + end + end + + describe "when the imaginary part responds to #== 0 with true" do + it "returns the result of sending #to_f to the real part" do + real = mock_numeric('real') + real.should_receive(:to_f).and_return(:f) + imag = mock_numeric('imag') + imag.should_receive(:==).with(0).any_number_of_times.and_return(true) + Complex(real, imag).to_f.should == :f + end + end + + describe "when the imaginary part is non-zero" do + it "raises RangeError" do + -> { Complex(0, 1).to_f }.should raise_error(RangeError) + end + end + + describe "when the imaginary part is Float 0.0" do + it "raises RangeError" do + -> { Complex(0, 0.0).to_f }.should raise_error(RangeError) + end + end +end diff --git a/spec/ruby/core/complex/to_i_spec.rb b/spec/ruby/core/complex/to_i_spec.rb new file mode 100644 index 0000000000..1e78f5ec0e --- /dev/null +++ b/spec/ruby/core/complex/to_i_spec.rb @@ -0,0 +1,41 @@ +require_relative '../../spec_helper' + +describe "Complex#to_i" do + describe "when the imaginary part is Integer 0" do + it "returns the result of sending #to_i to the real part" do + real = mock_numeric('real') + real.should_receive(:to_i).and_return(:i) + Complex(real, 0).to_i.should == :i + end + end + + describe "when the imaginary part is Rational 0" do + it "returns the result of sending #to_i to the real part" do + real = mock_numeric('real') + real.should_receive(:to_i).and_return(:i) + Complex(real, Rational(0)).to_i.should == :i + end + end + + describe "when the imaginary part responds to #== 0 with true" do + it "returns the result of sending #to_i to the real part" do + real = mock_numeric('real') + real.should_receive(:to_i).and_return(:i) + imag = mock_numeric('imag') + imag.should_receive(:==).with(0).any_number_of_times.and_return(true) + Complex(real, imag).to_i.should == :i + end + end + + describe "when the imaginary part is non-zero" do + it "raises RangeError" do + -> { Complex(0, 1).to_i }.should raise_error(RangeError) + end + end + + describe "when the imaginary part is Float 0.0" do + it "raises RangeError" do + -> { Complex(0, 0.0).to_i }.should raise_error(RangeError) + end + end +end diff --git a/spec/ruby/core/complex/to_r_spec.rb b/spec/ruby/core/complex/to_r_spec.rb new file mode 100644 index 0000000000..788027a500 --- /dev/null +++ b/spec/ruby/core/complex/to_r_spec.rb @@ -0,0 +1,49 @@ +require_relative '../../spec_helper' + +describe "Complex#to_r" do + describe "when the imaginary part is Integer 0" do + it "returns the result of sending #to_r to the real part" do + real = mock_numeric('real') + real.should_receive(:to_r).and_return(:r) + Complex(real, 0).to_r.should == :r + end + end + + describe "when the imaginary part is Rational 0" do + it "returns the result of sending #to_r to the real part" do + real = mock_numeric('real') + real.should_receive(:to_r).and_return(:r) + Complex(real, Rational(0)).to_r.should == :r + end + end + + describe "when the imaginary part responds to #== 0 with true" do + it "returns the result of sending #to_r to the real part" do + real = mock_numeric('real') + real.should_receive(:to_r).and_return(:r) + imag = mock_numeric('imag') + imag.should_receive(:==).with(0).any_number_of_times.and_return(true) + Complex(real, imag).to_r.should == :r + end + end + + describe "when the imaginary part is non-zero" do + it "raises RangeError" do + -> { Complex(0, 1).to_r }.should raise_error(RangeError) + end + end + + describe "when the imaginary part is Float 0.0" do + ruby_version_is ''...'3.4' do + it "raises RangeError" do + -> { Complex(0, 0.0).to_r }.should raise_error(RangeError) + end + end + + ruby_version_is '3.4' do + it "returns a Rational" do + Complex(0, 0.0).to_r.should == 0r + end + end + end +end diff --git a/spec/ruby/core/complex/to_s_spec.rb b/spec/ruby/core/complex/to_s_spec.rb new file mode 100644 index 0000000000..ceccffe470 --- /dev/null +++ b/spec/ruby/core/complex/to_s_spec.rb @@ -0,0 +1,55 @@ +require_relative '../../spec_helper' +require_relative '../numeric/fixtures/classes' + +describe "Complex#to_s" 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 + guard -> { !defined?(Math.rsqrt) } 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 + + it "treats real and imaginary parts as strings" do + real = NumericSpecs::Subclass.new + # + because of https://bugs.ruby-lang.org/issues/20337 + real.should_receive(:to_s).and_return(+"1") + imaginary = NumericSpecs::Subclass.new + imaginary.should_receive(:to_s).and_return("2") + imaginary.should_receive(:<).any_number_of_times.and_return(false) + Complex(real, imaginary).to_s.should == "1+2i" + end +end diff --git a/spec/ruby/core/complex/uminus_spec.rb b/spec/ruby/core/complex/uminus_spec.rb new file mode 100644 index 0000000000..c0184e11de --- /dev/null +++ b/spec/ruby/core/complex/uminus_spec.rb @@ -0,0 +1,11 @@ +require_relative '../../spec_helper' + +describe "Complex#-@" do + it "sends #-@ to the real and imaginary parts and returns a Complex with the resulting respective parts" do + real = mock_numeric('real') + imag = mock_numeric('imag') + real.should_receive(:-@).and_return(-1) + imag.should_receive(:-@).and_return(-2) + Complex(real, imag).send(:-@).should == Complex(-1, -2) + end +end |
