1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
ruby--ruby/test/ruby/test_numeric.rb
eregon a21ac07f69 * numeric.c (do_coerce): Add a warning when an exception is raised
or an invalid value is returned in #coerce called by
  numeric comparison operators and the exception
  thrown by the caller has no information on the failure.
  In the next release such exception should not be rescued or
  should be the cause of the caller exception. nil is accepted
  as the "no possible coercion" return value. See #7688.
* test/ruby/test_numeric.rb: Add corresponding test.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@46375 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2014-06-07 13:16:01 +00:00

363 lines
10 KiB
Ruby

require 'test/unit'
require_relative 'envutil'
class TestNumeric < Test::Unit::TestCase
class DummyNumeric < Numeric
end
def test_coerce
a, b = 1.coerce(2)
assert_equal(Fixnum, a.class)
assert_equal(Fixnum, b.class)
a, b = 1.coerce(2.0)
assert_equal(Float, a.class)
assert_equal(Float, b.class)
assert_raise(TypeError) { -Numeric.new }
assert_raise_with_message(TypeError, /can't be coerced into /) {1+:foo}
assert_raise_with_message(TypeError, /can't be coerced into /) {1&:foo}
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
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}"}
end
EnvUtil.with_default_external(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}"}
assert_raise_with_message(TypeError, /:"\\u3042"/) {1^:"\u{3042}"}
end
end
def test_dummynumeric
a = DummyNumeric.new
DummyNumeric.class_eval do
def coerce(x); nil; end
end
assert_raise(TypeError) { -a }
assert_nil(1 <=> a)
assert_raise(ArgumentError) { 1 <= a }
DummyNumeric.class_eval do
remove_method :coerce
def coerce(x); 1.coerce(x); end
end
assert_equal(2, 1 + a)
assert_equal(0, 1 <=> a)
assert_operator(1, :<=, a)
DummyNumeric.class_eval do
remove_method :coerce
def coerce(x); [x, 1]; end
end
assert_equal(-1, -a)
bug7688 = '[ruby-core:51389] [Bug #7688]'
DummyNumeric.class_eval do
remove_method :coerce
def coerce(x); raise StandardError; end
end
assert_raise_with_message(TypeError, /can't be coerced into /) { 1 + a }
warn = /will no more rescue exceptions of #coerce.+ in the next release/m
assert_warn(warn, bug7688) { assert_raise(ArgumentError) { 1 < a } }
DummyNumeric.class_eval do
remove_method :coerce
def coerce(x); :bad_return_value; end
end
assert_raise_with_message(TypeError, "coerce must return [x, y]") { 1 + a }
warn = /Bad return value for #coerce.+next release will raise an error/m
assert_warn(warn, bug7688) { assert_raise(ArgumentError) { 1 < a } }
ensure
DummyNumeric.class_eval do
remove_method :coerce
end
end
def test_singleton_method
a = Numeric.new
assert_raise_with_message(TypeError, /foo/) { def a.foo; end }
assert_raise_with_message(TypeError, /\u3042/) { eval("def a.\u3042; end") }
end
def test_dup
a = Numeric.new
assert_raise(TypeError) { a.dup }
c = Module.new do
break eval("class C\u{3042} < Numeric; self; end")
end
assert_raise_with_message(TypeError, /C\u3042/) {c.new.dup}
end
def test_quo
assert_raise(TypeError) {DummyNumeric.new.quo(1)}
end
def test_quo_ruby_core_41575
x = DummyNumeric.new
rat = 84.quo(1)
DummyNumeric.class_eval do
define_method(:to_r) { rat }
end
assert_equal(2.quo(1), x.quo(42), '[ruby-core:41575]')
ensure
DummyNumeric.class_eval do
remove_method :to_r
end
end
def test_divmod
=begin
DummyNumeric.class_eval do
def /(x); 42.0; end
def %(x); :mod; end
end
assert_equal(42, DummyNumeric.new.div(1))
assert_equal(:mod, DummyNumeric.new.modulo(1))
assert_equal([42, :mod], DummyNumeric.new.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_predicate(Numeric.new, :real?)
end
def test_integer_p
assert_not_predicate(Numeric.new, :integer?)
end
def test_abs
a = DummyNumeric.new
DummyNumeric.class_eval do
def -@; :ok; end
def <(x); true; end
end
assert_equal(:ok, a.abs)
DummyNumeric.class_eval do
remove_method :<
def <(x); false; end
end
assert_equal(a, a.abs)
ensure
DummyNumeric.class_eval do
remove_method :-@, :<
end
end
def test_zero_p
DummyNumeric.class_eval do
def ==(x); true; end
end
assert_predicate(DummyNumeric.new, :zero?)
ensure
DummyNumeric.class_eval do
remove_method :==
end
end
def test_to_int
DummyNumeric.class_eval do
def to_i; :ok; end
end
assert_equal(:ok, DummyNumeric.new.to_int)
ensure
DummyNumeric.class_eval do
remove_method :to_i
end
end
def test_cmp
a = Numeric.new
assert_equal(0, a <=> a)
assert_nil(a <=> :foo)
end
def test_floor_ceil_round_truncate
DummyNumeric.class_eval do
def to_f; 1.5; end
end
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
def to_f; 1.4; end
end
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
def to_f; -1.5; end
end
a = DummyNumeric.new
assert_equal(-2, a.floor)
assert_equal(-1, a.ceil)
assert_equal(-2, a.round)
assert_equal(-1, a.truncate)
ensure
DummyNumeric.class_eval do
remove_method :to_f
end
end
def assert_step(expected, (from, *args), inf: false)
enum = from.step(*args)
size = enum.size
xsize = expected.size
if inf
assert_send [size, :infinite?], "step size: +infinity"
assert_send [size, :>, 0], "step size: +infinity"
a = []
from.step(*args) { |x| a << x; break if a.size == xsize }
assert_equal expected, a, "step"
a = []
enum.each { |x| a << x; break if a.size == xsize }
assert_equal expected, a, "step enumerator"
else
assert_equal expected.size, size, "step size"
a = []
from.step(*args) { |x| a << x }
assert_equal expected, a, "step"
a = []
enum.each { |x| a << x }
assert_equal expected, a, "step enumerator"
end
end
def test_step
i, bignum = 32, 1 << 30
bignum <<= (i <<= 1) - 32 until bignum.is_a?(Bignum)
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, 0).size }
assert_raise(ArgumentError) { 1.step(10, "1") { } }
assert_raise(ArgumentError) { 1.step(10, "1").size }
assert_raise(TypeError) { 1.step(10, nil) { } }
assert_raise(TypeError) { 1.step(10, nil).size }
assert_nothing_raised { 1.step(by: 0, to: nil) }
assert_nothing_raised { 1.step(by: 0, to: nil).size }
assert_nothing_raised { 1.step(by: 0) }
assert_nothing_raised { 1.step(by: 0).size }
assert_nothing_raised { 1.step(by: nil) }
assert_nothing_raised { 1.step(by: nil).size }
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 }
assert_equal(bignum*2+1, (-bignum).step(bignum, 1).size)
assert_equal(bignum*2, (-bignum).step(bignum-1, 1).size)
assert_equal(10+1, (0.0).step(10.0, 1.0).size)
i, bigflo = 1, bignum.to_f
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 [3, 3, 3, 3], [3, by: 0], inf: true
assert_step [3, 3, 3, 3], [3, by: 0, to: 42], inf: true
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
assert_step [42, 42, 42, 42], [42, by: 0, to: -Float::INFINITY], inf: true
assert_step [42, 42, 42, 42], [42, by: 0, to: 42.5], inf: true
assert_step [4.2, 4.2, 4.2, 4.2], [4.2, by: 0.0], inf: true
assert_step [4.2, 4.2, 4.2, 4.2], [4.2, by: -0.0], inf: true
assert_step [42.0, 42.0, 42.0, 42.0], [42, by: 0.0, to: 44], inf: true
assert_step [42.0, 42.0, 42.0, 42.0], [42, by: 0.0, to: 0], inf: true
assert_step [42.0, 42.0, 42.0, 42.0], [42, by: -0.0, to: 44], inf: true
assert_step [bignum]*4, [bignum, by: 0], inf: true
assert_step [bignum]*4, [bignum, by: 0.0], inf: true
assert_step [bignum]*4, [bignum, by: 0, to: bignum+1], inf: true
assert_step [bignum]*4, [bignum, by: 0, to: 0], inf: true
end
def test_num2long
assert_raise(TypeError) { 1 & nil }
assert_raise(TypeError) { 1 & 1.0 }
assert_raise(TypeError) { 1 & 2147483648.0 }
assert_raise(TypeError) { 1 & 9223372036854777856.0 }
o = Object.new
def o.to_int; 1; end
assert_raise(TypeError) { assert_equal(1, 1 & o) }
end
def test_eql
assert_equal(1, 1.0)
assert_not_operator(1, :eql?, 1.0)
assert_not_operator(1, :eql?, 2)
end
end