diff options
Diffstat (limited to 'test/ruby/test_numeric.rb')
| -rw-r--r-- | test/ruby/test_numeric.rb | 398 |
1 files changed, 300 insertions, 98 deletions
diff --git a/test/ruby/test_numeric.rb b/test/ruby/test_numeric.rb index 4668f06196..35496ac875 100644 --- a/test/ruby/test_numeric.rb +++ b/test/ruby/test_numeric.rb @@ -1,19 +1,11 @@ +# frozen_string_literal: false require 'test/unit' -require_relative 'envutil' class TestNumeric < Test::Unit::TestCase - class DummyNumeric < Numeric - end - - def assert_raise_with_message(exc, pattern, msg = nil, &blk) - e = assert_raise(exc, msg, &blk) - assert_match(pattern, e.message) - end - def test_coerce a, b = 1.coerce(2) - assert_equal(Fixnum, a.class) - assert_equal(Fixnum, b.class) + assert_kind_of(Integer, a) + assert_kind_of(Integer, b) a, b = 1.coerce(2.0) assert_equal(Float, a.class) @@ -26,13 +18,19 @@ class TestNumeric < Test::Unit::TestCase assert_raise_with_message(TypeError, /can't be coerced into /) {1|:foo} assert_raise_with_message(TypeError, /can't be coerced into /) {1^:foo} - EnvUtil.with_default_external(Encoding::UTF_8) do + EnvUtil.with_default_internal(Encoding::UTF_8) do assert_raise_with_message(TypeError, /:\u{3042}/) {1+:"\u{3042}"} assert_raise_with_message(TypeError, /:\u{3042}/) {1&:"\u{3042}"} assert_raise_with_message(TypeError, /:\u{3042}/) {1|:"\u{3042}"} assert_raise_with_message(TypeError, /:\u{3042}/) {1^:"\u{3042}"} + + assert_raise_with_message(TypeError, /:\u{3044}/) {1+"\u{3044}".to_sym} + assert_raise_with_message(TypeError, /:\u{3044}/) {1&"\u{3044}".to_sym} + assert_raise_with_message(TypeError, /:\u{3044}/) {1|"\u{3044}".to_sym} + assert_raise_with_message(TypeError, /:\u{3044}/) {1^"\u{3044}".to_sym} end - EnvUtil.with_default_external(Encoding::US_ASCII) do + + EnvUtil.with_default_internal(Encoding::US_ASCII) do assert_raise_with_message(TypeError, /:"\\u3042"/) {1+:"\u{3042}"} assert_raise_with_message(TypeError, /:"\\u3042"/) {1&:"\u{3042}"} assert_raise_with_message(TypeError, /:"\\u3042"/) {1|:"\u{3042}"} @@ -40,38 +38,41 @@ class TestNumeric < Test::Unit::TestCase end bug10711 = '[ruby-core:67405] [Bug #10711]' - exp = "1.2 can't be coerced into Fixnum" + exp = "1.2 can't be coerced into Integer" assert_raise_with_message(TypeError, exp, bug10711) { 1 & 1.2 } end def test_dummynumeric - a = DummyNumeric.new - - DummyNumeric.class_eval do + a = Class.new(Numeric) do def coerce(x); nil; end - end + end.new assert_raise(TypeError) { -a } assert_nil(1 <=> a) assert_raise(ArgumentError) { 1 <= a } - DummyNumeric.class_eval do - remove_method :coerce + a = Class.new(Numeric) do def coerce(x); 1.coerce(x); end - end + end.new assert_equal(2, 1 + a) assert_equal(0, 1 <=> a) - assert(1 <= a) + assert_operator(1, :<=, a) - DummyNumeric.class_eval do - remove_method :coerce + a = Class.new(Numeric) do def coerce(x); [x, 1]; end - end + end.new assert_equal(-1, -a) - ensure - DummyNumeric.class_eval do - remove_method :coerce - end + a = Class.new(Numeric) do + def coerce(x); raise StandardError, "my error"; end + end.new + assert_raise_with_message(StandardError, "my error") { 1 + a } + assert_raise_with_message(StandardError, "my error") { 1 < a } + + a = Class.new(Numeric) do + def coerce(x); :bad_return_value; end + end.new + assert_raise_with_message(TypeError, "coerce must return [x, y]") { 1 + a } + assert_raise_with_message(TypeError, "coerce must return [x, y]") { 1 < a } end def test_singleton_method @@ -82,94 +83,121 @@ class TestNumeric < Test::Unit::TestCase def test_dup a = Numeric.new - assert_raise(TypeError) { a.dup } + assert_same a, a.dup + end + + def test_clone + a = Numeric.new + assert_same a, a.clone + assert_raise(ArgumentError) {a.clone(freeze: false)} - c = Module.new do - break eval("class C\u{3042} < Numeric; self; end") + c = EnvUtil.labeled_class("\u{1f4a9}", Numeric) + assert_raise_with_message(ArgumentError, /\u{1f4a9}/) do + c.new.clone(freeze: false) end - assert_raise_with_message(TypeError, /C\u3042/) {c.new.dup} end def test_quo - assert_raise(ArgumentError) {DummyNumeric.new.quo(1)} + a = Numeric.new + assert_raise(TypeError) {a.quo(1)} + end + + def test_quo_ruby_core_41575 + rat = 84.quo(1) + x = Class.new(Numeric) do + define_method(:to_r) { rat } + end.new + assert_equal(2.quo(1), x.quo(42), '[ruby-core:41575]') end def test_divmod =begin - DummyNumeric.class_eval do + x = Class.new(Numeric) do def /(x); 42.0; end def %(x); :mod; end - end + end.new - assert_equal(42, DummyNumeric.new.div(1)) - assert_equal(:mod, DummyNumeric.new.modulo(1)) - assert_equal([42, :mod], DummyNumeric.new.divmod(1)) + assert_equal(42, x.div(1)) + assert_equal(:mod, x.modulo(1)) + assert_equal([42, :mod], x.divmod(1)) =end assert_kind_of(Integer, 11.divmod(3.5).first, '[ruby-dev:34006]') - -=begin - ensure - DummyNumeric.class_eval do - remove_method :/, :% - end -=end end def test_real_p - assert(Numeric.new.real?) + assert_predicate(Numeric.new, :real?) end def test_integer_p - assert(!Numeric.new.integer?) + assert_not_predicate(Numeric.new, :integer?) end def test_abs - a = DummyNumeric.new - DummyNumeric.class_eval do + a = Class.new(Numeric) do def -@; :ok; end def <(x); true; end - end + end.new assert_equal(:ok, a.abs) - DummyNumeric.class_eval do - remove_method :< + a = Class.new(Numeric) do def <(x); false; end - end + end.new assert_equal(a, a.abs) - - ensure - DummyNumeric.class_eval do - remove_method :-@, :< - end end def test_zero_p - DummyNumeric.class_eval do + a = Class.new(Numeric) do def ==(x); true; end - end + end.new - assert(DummyNumeric.new.zero?) + assert_predicate(a, :zero?) + end - ensure - DummyNumeric.class_eval do - remove_method :== - end + def test_nonzero_p + a = Class.new(Numeric) do + def zero?; true; end + end.new + assert_nil(a.nonzero?) + + a = Class.new(Numeric) do + def zero?; false; end + end.new + assert_equal(a, a.nonzero?) + end + + def test_positive_p + a = Class.new(Numeric) do + def >(x); true; end + end.new + assert_predicate(a, :positive?) + + a = Class.new(Numeric) do + def >(x); false; end + end.new + assert_not_predicate(a, :positive?) + end + + def test_negative_p + a = Class.new(Numeric) do + def <(x); true; end + end.new + assert_predicate(a, :negative?) + + a = Class.new(Numeric) do + def <(x); false; end + end.new + assert_not_predicate(a, :negative?) end def test_to_int - DummyNumeric.class_eval do + a = Class.new(Numeric) do def to_i; :ok; end - end - - assert_equal(:ok, DummyNumeric.new.to_int) + end.new - ensure - DummyNumeric.class_eval do - remove_method :to_i - end + assert_equal(:ok, a.to_int) end def test_cmp @@ -178,47 +206,55 @@ class TestNumeric < Test::Unit::TestCase assert_nil(a <=> :foo) end + def test_float_round_ndigits + bug14635 = "[ruby-core:86323]" + f = 0.5 + 31.times do |i| + assert_equal(0.5, f.round(i+1), bug14635 + " (argument: #{i+1})") + end + end + def test_floor_ceil_round_truncate - DummyNumeric.class_eval do + a = Class.new(Numeric) do def to_f; 1.5; end - end + end.new - a = DummyNumeric.new assert_equal(1, a.floor) assert_equal(2, a.ceil) assert_equal(2, a.round) assert_equal(1, a.truncate) - DummyNumeric.class_eval do - remove_method :to_f + a = Class.new(Numeric) do def to_f; 1.4; end - end + end.new - a = DummyNumeric.new assert_equal(1, a.floor) assert_equal(2, a.ceil) assert_equal(1, a.round) assert_equal(1, a.truncate) - DummyNumeric.class_eval do - remove_method :to_f + a = Class.new(Numeric) do def to_f; -1.5; end - end + end.new - a = DummyNumeric.new assert_equal(-2, a.floor) assert_equal(-1, a.ceil) assert_equal(-2, a.round) assert_equal(-1, a.truncate) + end - ensure - DummyNumeric.class_eval do - remove_method :to_f + def test_floor_ceil_ndigits + bug17183 = "[ruby-core:100090]" + f = 291.4 + 31.times do |i| + assert_equal(291.4, f.floor(i+1), bug17183) + assert_equal(291.4, f.ceil(i+1), bug17183) end end def assert_step(expected, (from, *args), inf: false) - enum = from.step(*args) + kw = args.last.is_a?(Hash) ? args.pop : {} + enum = from.step(*args, **kw) size = enum.size xsize = expected.size @@ -227,7 +263,7 @@ class TestNumeric < Test::Unit::TestCase assert_send [size, :>, 0], "step size: +infinity" a = [] - from.step(*args) { |x| a << x; break if a.size == xsize } + from.step(*args, **kw) { |x| a << x; break if a.size == xsize } assert_equal expected, a, "step" a = [] @@ -237,7 +273,7 @@ class TestNumeric < Test::Unit::TestCase assert_equal expected.size, size, "step size" a = [] - from.step(*args) { |x| a << x } + from.step(*args, **kw) { |x| a << x } assert_equal expected, a, "step" a = [] @@ -247,10 +283,56 @@ class TestNumeric < Test::Unit::TestCase end def test_step - i, bignum = 32, 1 << 30 - bignum <<= (i <<= 1) - 32 until bignum.is_a?(Bignum) + bignum = RbConfig::LIMITS['FIXNUM_MAX'] + 1 assert_raise(ArgumentError) { 1.step(10, 1, 0) { } } + assert_raise(ArgumentError) { 1.step(10, 1, 0).size } assert_raise(ArgumentError) { 1.step(10, 0) { } } + assert_raise(ArgumentError) { 1.step(10, "1") { } } + assert_raise(ArgumentError) { 1.step(10, "1").size } + assert_raise(TypeError) { 1.step(10, nil) { } } + assert_nothing_raised { 1.step(10, nil).size } + assert_nothing_raised { 1.step(by: nil) } + assert_nothing_raised { 1.step(by: nil).size } + + assert_kind_of(Enumerator::ArithmeticSequence, 1.step(10)) + assert_kind_of(Enumerator::ArithmeticSequence, 1.step(10, 2)) + assert_kind_of(Enumerator::ArithmeticSequence, 1.step(10, by: 2)) + assert_kind_of(Enumerator::ArithmeticSequence, 1.step(by: 2)) + assert_kind_of(Enumerator::ArithmeticSequence, 1.step(by: 2, to: nil)) + assert_kind_of(Enumerator::ArithmeticSequence, 1.step(by: 2, to: 10)) + assert_kind_of(Enumerator::ArithmeticSequence, 1.step(by: -1)) + + bug9811 = '[ruby-dev:48177] [Bug #9811]' + assert_raise(ArgumentError, bug9811) { 1.step(10, foo: nil) {} } + assert_raise(ArgumentError, bug9811) { 1.step(10, foo: nil).size } + assert_raise(ArgumentError, bug9811) { 1.step(10, to: 11) {} } + assert_raise(ArgumentError, bug9811) { 1.step(10, to: 11).size } + assert_raise(ArgumentError, bug9811) { 1.step(10, 1, by: 11) {} } + assert_raise(ArgumentError, bug9811) { 1.step(10, 1, by: 11).size } + + feature15573 = "[ruby-core:91324] [Feature #15573]" + assert_raise(ArgumentError, feature15573) { 1.step(10, 0) } + assert_raise(ArgumentError, feature15573) { 1.step(10, by: 0) } + assert_raise(ArgumentError, feature15573) { 1.step(10, 0) { break } } + assert_raise(ArgumentError, feature15573) { 1.step(10, by: 0) { break } } + assert_raise(ArgumentError, feature15573) { 42.step(by: 0, to: -Float::INFINITY) } + assert_raise(ArgumentError, feature15573) { 42.step(by: 0, to: 42.5) } + assert_raise(ArgumentError, feature15573) { 4.2.step(by: 0.0) } + assert_raise(ArgumentError, feature15573) { 4.2.step(by: -0.0) } + assert_raise(ArgumentError, feature15573) { 42.step(by: 0.0, to: 44) } + assert_raise(ArgumentError, feature15573) { 42.step(by: 0.0, to: 0) } + assert_raise(ArgumentError, feature15573) { 42.step(by: -0.0, to: 44) } + assert_raise(ArgumentError, feature15573) { bignum.step(by: 0) } + assert_raise(ArgumentError, feature15573) { bignum.step(by: 0.0) } + assert_raise(ArgumentError, feature15573) { bignum.step(by: 0, to: bignum+1) } + assert_raise(ArgumentError, feature15573) { bignum.step(by: 0, to: 0) } + + e = 1.step(10, {by: "1"}) + assert_raise(TypeError) {e.next} + assert_raise(TypeError) {e.size} + e = 1.step(to: "10") + assert_raise(ArgumentError) {e.next} + assert_raise(ArgumentError) {e.size} assert_equal(bignum*2+1, (-bignum).step(bignum, 1).size) assert_equal(bignum*2, (-bignum).step(bignum-1, 1).size) @@ -261,21 +343,45 @@ class TestNumeric < Test::Unit::TestCase i <<= 1 until (bigflo - i).to_i < bignum bigflo -= i >> 1 assert_equal(bigflo.to_i, (0.0).step(bigflo-1.0, 1.0).size) - assert_operator((0.0).step(bignum.to_f, 1.0).size, :>=, bignum) # may loose precision assert_step [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 10] + assert_step [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, to: 10] + assert_step [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, to: 10, by: nil] assert_step [1, 3, 5, 7, 9], [1, 10, 2] + assert_step [1, 3, 5, 7, 9], [1, to: 10, by: 2] assert_step [10, 8, 6, 4, 2], [10, 1, -2] + assert_step [10, 8, 6, 4, 2], [10, to: 1, by: -2] assert_step [1.0, 3.0, 5.0, 7.0, 9.0], [1.0, 10.0, 2.0] + assert_step [1.0, 3.0, 5.0, 7.0, 9.0], [1.0, to: 10.0, by: 2.0] assert_step [1], [1, 10, bignum] + assert_step [1], [1, to: 10, by: bignum] assert_step [], [2, 1, 3] assert_step [], [-2, -1, -3] - assert_step [10], [10, 1, -(bignum)] + assert_step [10], [10, 1, -bignum] assert_step [], [1, 0, Float::INFINITY] assert_step [], [0, 1, -Float::INFINITY] + assert_step [10], [10, to: 1, by: -bignum] + + assert_step [10, 11, 12, 13], [10], inf: true + assert_step [10, 9, 8, 7], [10, by: -1], inf: true + assert_step [10, 9, 8, 7], [10, by: -1, to: nil], inf: true + end + + def test_step_bug15537 + assert_step [10.0, 8.0, 6.0, 4.0, 2.0], [10.0, 1, -2] + assert_step [10.0, 8.0, 6.0, 4.0, 2.0], [10.0, to: 1, by: -2] + assert_step [10.0, 8.0, 6.0, 4.0, 2.0], [10.0, 1, -2] + assert_step [10.0, 8.0, 6.0, 4.0, 2.0], [10, to: 1.0, by: -2] + assert_step [10.0, 8.0, 6.0, 4.0, 2.0], [10, 1.0, -2] + + assert_step [10.0, 9.0, 8.0, 7.0], [10, by: -1.0], inf: true + assert_step [10.0, 9.0, 8.0, 7.0], [10, by: -1.0, to: nil], inf: true + assert_step [10.0, 9.0, 8.0, 7.0], [10, nil, -1.0], inf: true + assert_step [10.0, 9.0, 8.0, 7.0], [10.0, by: -1], inf: true + assert_step [10.0, 9.0, 8.0, 7.0], [10.0, nil, -1], inf: true end def test_num2long @@ -289,8 +395,104 @@ class TestNumeric < Test::Unit::TestCase end def test_eql - assert(1 == 1.0) - assert(!(1.eql?(1.0))) - assert(!(1.eql?(2))) + assert_equal(1, 1.0) + assert_not_operator(1, :eql?, 1.0) + assert_not_operator(1, :eql?, 2) + end + + def test_coerced_remainder + assert_separately([], <<-'end;') + x = Class.new do + def coerce(a) [self, a]; end + def %(a) self; end + end.new + assert_raise(ArgumentError) {1.remainder(x)} + end; end + + def test_remainder_infinity + assert_equal(4, 4.remainder(Float::INFINITY)) + assert_equal(4, 4.remainder(-Float::INFINITY)) + assert_equal(-4, -4.remainder(Float::INFINITY)) + assert_equal(-4, -4.remainder(-Float::INFINITY)) + + assert_equal(4.2, 4.2.remainder(Float::INFINITY)) + assert_equal(4.2, 4.2.remainder(-Float::INFINITY)) + assert_equal(-4.2, -4.2.remainder(Float::INFINITY)) + assert_equal(-4.2, -4.2.remainder(-Float::INFINITY)) + end + + def test_comparison_comparable + bug12864 = '[ruby-core:77713] [Bug #12864]' + + myinteger = Class.new do + include Comparable + + def initialize(i) + @i = i.to_i + end + attr_reader :i + + def <=>(other) + @i <=> (other.is_a?(self.class) ? other.i : other) + end + end + + all_assertions(bug12864) do |a| + [5, 2**62, 2**61].each do |i| + a.for("%#x"%i) do + m = myinteger.new(i) + assert_equal(i, m) + assert_equal(m, i) + end + end + end + end + + def test_pow + assert_equal(2**3, 2.pow(3)) + assert_equal(2**-1, 2.pow(-1)) + assert_equal(2**0.5, 2.pow(0.5)) + assert_equal((-1)**0.5, -1.pow(0.5)) + assert_equal(3**3 % 8, 3.pow(3, 8)) + assert_equal(3**3 % -8, 3.pow(3,-8)) + assert_equal(3**2 % -2, 3.pow(2,-2)) + assert_equal((-3)**3 % 8, -3.pow(3,8)) + assert_equal((-3)**3 % -8, -3.pow(3,-8)) + assert_equal(5**2 % -8, 5.pow(2,-8)) + assert_equal(4481650795473624846969600733813414725093, + 2120078484650058507891187874713297895455. + pow(5478118174010360425845660566650432540723, + 5263488859030795548286226023720904036518)) + + assert_equal(12, 12.pow(1, 10000000000), '[Bug #14259]') + assert_equal(12, 12.pow(1, 10000000001), '[Bug #14259]') + assert_equal(12, 12.pow(1, 10000000002), '[Bug #14259]') + assert_equal(17298641040, 12.pow(72387894339363242, 243682743764), '[Bug #14259]') + + integers = [-2, -1, 0, 1, 2, 3, 6, 1234567890123456789] + integers.each do |i| + assert_equal(0, i.pow(0, 1), '[Bug #17257]') + assert_equal(1, i.pow(0, 2)) + assert_equal(1, i.pow(0, 3)) + assert_equal(1, i.pow(0, 6)) + assert_equal(1, i.pow(0, 1234567890123456789)) + + assert_equal(0, i.pow(0, -1)) + assert_equal(-1, i.pow(0, -2)) + assert_equal(-2, i.pow(0, -3)) + assert_equal(-5, i.pow(0, -6)) + assert_equal(-1234567890123456788, i.pow(0, -1234567890123456789)) + end + + assert_equal(0, 0.pow(2, 1)) + assert_equal(0, 0.pow(3, 1)) + assert_equal(0, 2.pow(3, 1)) + assert_equal(0, -2.pow(3, 1)) + + min, max = RbConfig::LIMITS.values_at("FIXNUM_MIN", "FIXNUM_MAX") + assert_equal(0, 0.pow(2, min)) + assert_equal(0, Integer.sqrt(max+1).pow(2, min)) + end + end |
