summaryrefslogtreecommitdiff
path: root/test/ruby/test_integer.rb
diff options
context:
space:
mode:
Diffstat (limited to 'test/ruby/test_integer.rb')
-rw-r--r--test/ruby/test_integer.rb309
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