diff options
Diffstat (limited to 'test/ruby/test_integer.rb')
| -rw-r--r-- | test/ruby/test_integer.rb | 309 |
1 files changed, 279 insertions, 30 deletions
diff --git a/test/ruby/test_integer.rb b/test/ruby/test_integer.rb index 1b485760e3..f9bf4fa20c 100644 --- a/test/ruby/test_integer.rb +++ b/test/ruby/test_integer.rb @@ -2,15 +2,47 @@ require 'test/unit' class TestInteger < Test::Unit::TestCase - BDSIZE = 0x4000000000000000.coerce(0)[0].size - def self.bdsize(x) - ((x + 1) / 8 + BDSIZE) / BDSIZE * BDSIZE - end - def bdsize(x) - self.class.bdsize(x) - end + FIXNUM_MIN = RbConfig::LIMITS['FIXNUM_MIN'] + FIXNUM_MAX = RbConfig::LIMITS['FIXNUM_MAX'] + LONG_MAX = RbConfig::LIMITS['LONG_MAX'] def test_aref + + [ + *-16..16, + *(FIXNUM_MIN-2)..(FIXNUM_MIN+2), + *(FIXNUM_MAX-2)..(FIXNUM_MAX+2), + ].each do |n| + (-64..64).each do |idx| + assert_equal((n >> idx) & 1, n[idx]) + end + [*-66..-62, *-34..-30, *-5..5, *30..34, *62..66].each do |idx| + (0..100).each do |len| + assert_equal((n >> idx) & ((1 << len) - 1), n[idx, len], "#{ n }[#{ idx }, #{ len }]") + end + (0..100).each do |len| + assert_equal((n >> idx) & ((1 << (len + 1)) - 1), n[idx..idx+len], "#{ n }[#{ idx }..#{ idx+len }]") + assert_equal((n >> idx) & ((1 << len) - 1), n[idx...idx+len], "#{ n }[#{ idx }...#{ idx+len }]") + end + + # endless + assert_equal((n >> idx), n[idx..], "#{ n }[#{ idx }..]") + assert_equal((n >> idx), n[idx...], "#{ n }[#{ idx }...#]") + + # beginless + if idx >= 0 && n & ((1 << (idx + 1)) - 1) != 0 + assert_raise(ArgumentError, "#{ n }[..#{ idx }]") { n[..idx] } + else + assert_equal(0, n[..idx], "#{ n }[..#{ idx }]") + end + if idx >= 0 && n & ((1 << idx) - 1) != 0 + assert_raise(ArgumentError, "#{ n }[...#{ idx }]") { n[...idx] } + else + assert_equal(0, n[...idx], "#{ n }[...#{ idx }]") + end + end + end + # assert_equal(1, (1 << 0x40000000)[0x40000000], "[ruby-dev:31271]") # assert_equal(0, (-1 << 0x40000001)[0x40000000], "[ruby-dev:31271]") big_zero = 0x40000000.coerce(0)[0] @@ -24,6 +56,31 @@ class TestInteger < Test::Unit::TestCase rescue nil end, "[ruby-dev:32084] [ruby-dev:34547]") + + assert_raise(ArgumentError) {2 ** -0x4000000000000000} + + <<~EXPRS.each_line.with_index(__LINE__+1) do |expr, line| + crash01: 111r+11**-11111161111111 + crash02: 1118111111111**-1111111111111111**1+1==11111 + crash03: -1111111**-1111*11 - -11** -1111111 + crash04: 1118111111111** -1111111111111111**1+11111111111**1 ===111 + crash05: 11** -111155555555555555 -55 !=5-555 + crash07: 1 + 111111111**-1111811111 + crash08: 18111111111**-1111111111111111**1 + 1111111111**-1111**1 + crash10: -7 - -1111111** -1111**11 + crash12: 1118111111111** -1111111111111111**1 + 1111 - -1111111** -1111*111111111119 + crash13: 1.0i - -11** -1111111 + crash14: 11111**111111111**111111 * -11111111111111111111**-111111111111 + crash15: ~1**1111 + -~1**~1**111 + crash17: 11** -1111111**1111 /11i + crash18: 5555i**-5155 - -9111111**-1111**11 + crash19: 111111*-11111111111111111111**-1111111111111111 + crash20: 1111**111-11**-11111**11 + crash21: 11**-10111111119-1i -1r + EXPRS + name, expr = expr.split(':', 2) + assert_ruby_status(%w"-W0", "begin; #{ expr }; rescue ArgumentError; end", name) + end end def test_lshift @@ -31,11 +88,16 @@ class TestInteger < Test::Unit::TestCase assert_equal(0, 1 << -0x40000001) assert_equal(0, 1 << -0x80000000) assert_equal(0, 1 << -0x80000001) - # assert_equal(bdsize(0x80000000), (1 << 0x80000000).size) + + char_bit = RbConfig::LIMITS["UCHAR_MAX"].bit_length + size_max = RbConfig::LIMITS["SIZE_MAX"] + size_bit_max = size_max * char_bit + assert_raise_with_message(RangeError, /shift width/) { + 1 << size_bit_max + } end def test_rshift - # assert_equal(bdsize(0x40000001), (1 >> -0x40000001).size) assert_predicate((1 >> 0x80000000), :zero?) assert_predicate((1 >> 0xffffffff), :zero?) assert_predicate((1 >> 0x100000000), :zero?) @@ -75,23 +137,20 @@ class TestInteger < Test::Unit::TestCase assert_equal(1234, Integer(1234)) assert_equal(1, Integer(1.234)) - # base argument - assert_equal(1234, Integer("1234", 10)) - assert_equal(668, Integer("1234", 8)) - assert_equal(4660, Integer("1234", 16)) - assert_equal(49360, Integer("1234", 36)) - # decimal, not octal - assert_equal(1234, Integer("01234", 10)) - assert_raise(ArgumentError) { Integer("0x123", 10) } - assert_raise(ArgumentError) { Integer(1234, 10) } - assert_raise(ArgumentError) { Integer(12.34, 10) } - assert_raise(ArgumentError) { Integer(Object.new, 1) } - - assert_raise(ArgumentError) { Integer(1, 1, 1) } - assert_equal(2 ** 50, Integer(2.0 ** 50)) assert_raise(TypeError) { Integer(nil) } + bug14552 = '[ruby-core:85813]' + obj = Object.new + def obj.to_int; "str"; end + assert_raise(TypeError, bug14552) { Integer(obj) } + def obj.to_i; 42; end + assert_equal(42, Integer(obj), bug14552) + + obj = Object.new + def obj.to_i; "str"; end + assert_raise(TypeError) { Integer(obj) } + bug6192 = '[ruby-core:43566]' assert_raise(Encoding::CompatibilityError, bug6192) {Integer("0".encode("utf-16be"))} assert_raise(Encoding::CompatibilityError, bug6192) {Integer("0".encode("utf-16le"))} @@ -99,7 +158,9 @@ class TestInteger < Test::Unit::TestCase assert_raise(Encoding::CompatibilityError, bug6192) {Integer("0".encode("utf-32le"))} assert_raise(Encoding::CompatibilityError, bug6192) {Integer("0".encode("iso-2022-jp"))} - assert_raise_with_message(ArgumentError, /\u{1f4a1}/) {Integer("\u{1f4a1}")} + EnvUtil.with_default_internal(Encoding::UTF_8) do + assert_raise_with_message(ArgumentError, /\u{1f4a1}/) {Integer("\u{1f4a1}")} + end obj = Struct.new(:s).new(%w[42 not-an-integer]) def obj.to_str; s.shift; end @@ -116,6 +177,94 @@ class TestInteger < Test::Unit::TestCase end; end + def test_Integer_with_invalid_exception + assert_raise(ArgumentError) { + Integer("0", exception: 1) + } + end + + def test_Integer_with_exception_keyword + assert_nothing_raised(ArgumentError) { + assert_equal(nil, Integer("1z", exception: false)) + } + assert_nothing_raised(ArgumentError) { + assert_equal(nil, Integer(Object.new, exception: false)) + } + assert_nothing_raised(ArgumentError) { + o = Object.new + def o.to_i; 42.5; end + assert_equal(nil, Integer(o, exception: false)) + } + assert_nothing_raised(ArgumentError) { + o = Object.new + def o.to_i; raise; end + assert_equal(nil, Integer(o, exception: false)) + } + assert_nothing_raised(ArgumentError) { + o = Object.new + def o.to_int; raise; end + assert_equal(nil, Integer(o, exception: false)) + } + assert_nothing_raised(FloatDomainError) { + assert_equal(nil, Integer(Float::INFINITY, exception: false)) + } + assert_nothing_raised(FloatDomainError) { + assert_equal(nil, Integer(-Float::INFINITY, exception: false)) + } + assert_nothing_raised(FloatDomainError) { + assert_equal(nil, Integer(Float::NAN, exception: false)) + } + + assert_raise(ArgumentError) { + Integer("1z", exception: true) + } + assert_raise(TypeError) { + Integer(nil, exception: true) + } + assert_nothing_raised(TypeError) { + assert_equal(nil, Integer(nil, exception: false)) + } + + assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") + begin; + class Integer;def method_missing(*);"";end;end + assert_equal(0, Integer("0", 2)) + end; + end + + def test_Integer_when_to_str + def (obj = Object.new).to_str + "0x10" + end + assert_equal(16, Integer(obj)) + end + + def test_Integer_with_base + assert_equal(1234, Integer("1234", 10)) + assert_equal(668, Integer("1234", 8)) + assert_equal(4660, Integer("1234", 16)) + assert_equal(49360, Integer("1234", 36)) + # decimal, not octal + assert_equal(1234, Integer("01234", 10)) + assert_raise(ArgumentError) { Integer("0x123", 10) } + assert_raise(ArgumentError) { Integer(1234, 10) } + assert_raise(ArgumentError) { Integer(12.34, 10) } + assert_raise(ArgumentError) { Integer(Object.new, 1) } + + assert_raise(ArgumentError) { Integer(1, 1, 1) } + + def (base = Object.new).to_int + 8 + end + assert_equal(8, Integer("10", base)) + + assert_raise(TypeError) { Integer("10", "8") } + def (base = Object.new).to_int + "8" + end + assert_raise(TypeError) { Integer("10", base) } + end + def test_int_p assert_not_predicate(1.0, :integer?) assert_predicate(1, :integer?) @@ -129,35 +278,36 @@ class TestInteger < Test::Unit::TestCase assert_equal("a", "a".ord.chr) assert_raise(RangeError) { (-1).chr } assert_raise(RangeError) { 0x100.chr } + assert_raise_with_message(RangeError, "3000000000 out of char range") { 3_000_000_000.chr } end def test_upto a = [] - 1.upto(3) {|x| a << x } + assert_equal(1, 1.upto(3) {|x| a << x }) assert_equal([1, 2, 3], a) a = [] - 1.upto(0) {|x| a << x } + assert_equal(1, 1.upto(0) {|x| a << x }) assert_equal([], a) y = 2**30 - 1 a = [] - y.upto(y+2) {|x| a << x } + assert_equal(y, y.upto(y+2) {|x| a << x }) assert_equal([y, y+1, y+2], a) end def test_downto a = [] - -1.downto(-3) {|x| a << x } + assert_equal(-1, -1.downto(-3) {|x| a << x }) assert_equal([-1, -2, -3], a) a = [] - 1.downto(2) {|x| a << x } + assert_equal(1, 1.downto(2) {|x| a << x }) assert_equal([], a) y = -(2**30) a = [] - y.downto(y-2) {|x| a << x } + assert_equal(y, y.downto(y-2) {|x| a << x }) assert_equal([y, y-1, y-2], a) end @@ -167,6 +317,42 @@ class TestInteger < Test::Unit::TestCase end end + def test_times_bignum_redefine_plus_lt + assert_separately([], "#{<<-"begin;"}\n#{<<~"end;"}") + begin; + called = false + Integer.class_eval do + alias old_succ succ + undef succ + define_method(:succ){|x| called = true; x+1} + alias old_lt < + undef < + define_method(:<){|x| called = true} + end + + fix = 1 + fix.times{break 0} + fix_called = called + + called = false + + big = 2**65 + big.times{break 0} + big_called = called + + Integer.class_eval do + undef succ + alias succ old_succ + undef < + alias < old_lt + end + + # Asssert that Fixnum and Bignum behave consistently + bug18377 = "[ruby-core:106361]" + assert_equal(fix_called, big_called, bug18377) + end; + end + def assert_int_equal(expected, result, mesg = nil) assert_kind_of(Integer, result, mesg) assert_equal(expected, result, mesg) @@ -280,6 +466,10 @@ class TestInteger < Test::Unit::TestCase assert_int_equal(1111_1111_1111_1111_1111_1111_1111_1111, 1111_1111_1111_1111_1111_1111_1111_1111.floor(1)) assert_int_equal(10**400, (10**400).floor(1)) + + assert_int_equal(-10000000000, -1.floor(-10), "[Bug #20654]") + assert_int_equal(-100000000000000000000, -1.floor(-20), "[Bug #20654]") + assert_int_equal(-100000000000000000000000000000000000000000000000000, -1.floor(-50), "[Bug #20654]") end def test_ceil @@ -308,6 +498,10 @@ class TestInteger < Test::Unit::TestCase assert_int_equal(1111_1111_1111_1111_1111_1111_1111_1111, 1111_1111_1111_1111_1111_1111_1111_1111.ceil(1)) assert_int_equal(10**400, (10**400).ceil(1)) + + assert_int_equal(10000000000, 1.ceil(-10), "[Bug #20654]") + assert_int_equal(100000000000000000000, 1.ceil(-20), "[Bug #20654]") + assert_int_equal(100000000000000000000000000000000000000000000000000, 1.ceil(-50), "[Bug #20654]") end def test_truncate @@ -444,6 +638,8 @@ class TestInteger < Test::Unit::TestCase assert_equal([0, 9, 8, 7, 6, 5, 4, 3, 2, 1], 1234567890.digits) assert_equal([90, 78, 56, 34, 12], 1234567890.digits(100)) assert_equal([10, 5, 6, 8, 0, 10, 8, 6, 1], 1234567890.digits(13)) + assert_equal((2 ** 1024).to_s(7).chars.map(&:to_i).reverse, (2 ** 1024).digits(7)) + assert_equal([0] * 100 + [1], (2 ** (128 * 100)).digits(2 ** 128)) end def test_digits_for_negative_numbers @@ -509,11 +705,26 @@ class TestInteger < Test::Unit::TestCase failures << n unless root*root <= n && (root+1)*(root+1) > n end assert_empty(failures, bug13440) + + x = 0xffff_ffff_ffff_ffff + assert_equal(x, Integer.sqrt(x ** 2), "[ruby-core:95453]") + end + + def test_bug_21217 + assert_equal(0x10000 * 2**10, Integer.sqrt(0x100000008 * 2**20)) end def test_fdiv assert_equal(1.0, 1.fdiv(1)) assert_equal(0.5, 1.fdiv(2)) + + m = 50 << Float::MANT_DIG + prev = 1.0 + (1..100).each do |i| + val = (m + i).fdiv(m) + assert_operator val, :>=, prev, "1+epsilon*(#{i}/100)" + prev = val + end end def test_obj_fdiv @@ -525,4 +736,42 @@ class TestInteger < Test::Unit::TestCase def o.fdiv(x); 1; end assert_equal(1.0, 1.fdiv(o)) end + + def test_try_convert + assert_equal(1, Integer.try_convert(1)) + assert_equal(1, Integer.try_convert(1.0)) + assert_nil Integer.try_convert("1") + o = Object.new + assert_nil Integer.try_convert(o) + def o.to_i; 1; end + assert_nil Integer.try_convert(o) + o = Object.new + def o.to_int; 1; end + assert_equal(1, Integer.try_convert(o)) + + o = Object.new + def o.to_int; Object.new; end + assert_raise_with_message(TypeError, /can't convert Object to Integer/) {Integer.try_convert(o)} + end + + def test_ceildiv + assert_equal(0, 0.ceildiv(3)) + assert_equal(1, 1.ceildiv(3)) + assert_equal(1, 3.ceildiv(3)) + assert_equal(2, 4.ceildiv(3)) + + assert_equal(-1, 4.ceildiv(-3)) + assert_equal(-1, -4.ceildiv(3)) + assert_equal(2, -4.ceildiv(-3)) + + assert_equal(3, 3.ceildiv(1.2)) + assert_equal(3, 3.ceildiv(6/5r)) + + assert_equal(10, (10**100-11).ceildiv(10**99-1)) + assert_equal(11, (10**100-9).ceildiv(10**99-1)) + + o = Object.new + def o.coerce(other); [other, 10]; end + assert_equal(124, 1234.ceildiv(o)) + end end |
