assert('Integer', '15.2.8') do
assert_equal Class, Integer.class
end
assert('Integer#+', '15.2.8.3.1') do
a = 1+1
b = 1+1.0 if Object.const_defined?(:Float)
assert_equal 2, a
assert_equal 2.0, b if Object.const_defined?(:Float)
assert_raise(TypeError){ 0+nil }
assert_raise(TypeError){ 1+nil }
end
assert('Integer#-', '15.2.8.3.2') do
a = 2-1
b = 2-1.0 if Object.const_defined?(:Float)
assert_equal 1, a
assert_equal 1.0, b if Object.const_defined?(:Float)
end
assert('Integer#*', '15.2.8.3.3') do
a = 1*1
assert_equal 1, a
if Object.const_defined?(:Float)
b = 1*1.0
assert_equal 1.0, b
end
assert_raise(TypeError){ 0*nil }
assert_raise(TypeError){ 1*nil }
end
assert('Integer#/', '15.2.8.3.4') do
a = 2/1
assert_equal 2, a
a = 5/2
assert_equal 2, a
b = -1/2
assert_equal(-1, b)
b = 1/-2
assert_equal(-1, b)
skip unless Object.const_defined?(:Float)
b = 2/1.0
assert_equal 2.0, b
end
if Object.const_defined?(:Float)
assert('Integer#quo') do
a = 6.quo(5)
assert_equal 1.2, a
end
end
assert('Integer#%', '15.2.8.3.5') do
a = 1%1
b = 2%4
c = 2%5
d = 2%-5
e = -2%5
f = -2%-5
g = 2%-2
h = -2%2
i = -2%-2
assert_equal 0, a
assert_equal 2, b
assert_equal 2, c
assert_equal(-3, d)
assert_equal 3, e
assert_equal(-2, f)
assert_equal 0, g
assert_equal 0, h
assert_equal 0, i
assert_raise(ZeroDivisionError) { 0%0 }
skip unless Object.const_defined?(:Float)
j = 1%1.0
assert_equal 0.0, j
assert_equal 0.0, 0%2.5
assert_kind_of Float, 0%2.5
assert_raise(ZeroDivisionError) { 0%0.0 }
end
assert('Integer#<=>', '15.2.9.3.6') do
a = 1<=>0
b = 1<=>1
c = 1<=>2
assert_equal 1, a
assert_equal 0, b
assert_equal(-1, c)
end
assert('Integer#==', '15.2.8.3.7') do
a = 1==0
b = 1==1
assert_false a
assert_true b
end
assert('Integer comparison with a Float that stands for another number') do
skip unless Object.const_defined?(:Float)
f = 2.0
f *= 2 while f + 1.0 != f
begin
n = f.to_i + 1
rescue RangeError
skip 'no mrb_int here is wider than the significand of an mrb_float'
end
assert_false(n == f)
assert_false(n.__send__(:==, f)) assert_equal(1, n <=> f)
assert_true(n > f)
assert_true(n.__send__(:>, f))
assert_true(n >= f)
assert_false(n < f)
assert_false(n <= f)
assert_false([n] == [f]) end
assert('Integer comparison with a NaN') do
skip unless Object.const_defined?(:Float)
nan = Float::NAN
assert_nil(1 <=> nan)
assert_false(1.__send__(:<, nan))
assert_false(1.__send__(:<=, nan))
assert_false(1.__send__(:>, nan))
assert_false(1.__send__(:>=, nan))
assert_false(1 < nan) end
assert('Integer wider than an mrb_int compared with a NaN') do
skip unless Object.const_defined?(:Float)
begin
big = 1 << 70
rescue RangeError
skip 'no integer here is wider than an mrb_int'
end
nan = Float::NAN
assert_nil(big <=> nan)
assert_nil(nan <=> big)
assert_false(big.__send__(:<, nan))
assert_false(big.__send__(:>=, nan))
assert_false(nan.__send__(:<, big))
assert_false(nan.__send__(:>=, big))
end
assert('Integer comparison with a Float at the ends of the mrb_int range') do
skip unless Object.const_defined?(:Float)
begin
half = 1 << 62
rescue RangeError
skip 'an mrb_int here is narrower than 64 bits'
end
imin = -half - half imax = half - 1 + half fmin = -(2.0 ** 63)
fmax = 2.0 ** 63
inf = 1.0 / 0.0
assert_true(imin == fmin)
assert_equal(0, imin <=> fmin)
assert_equal(1, (imin + 3) <=> fmin)
assert_true((imin + 3) > fmin)
assert_false(imax == fmax)
assert_equal(-1, imax <=> fmax)
assert_true(imax < fmax)
assert_true(imax < inf)
assert_true(imin > -inf)
end
assert('Integer comparison of two values too wide to store inline') do
pairs = [[1 << 30, (1 << 30) + 1]]
begin
k = 62
pairs << [1 << k, (1 << k) + 1]
rescue RangeError
end
pairs.each do |small, large|
assert_equal(-1, small.__send__(:<=>, large))
assert_equal(1, large.__send__(:<=>, small))
assert_equal(0, large.__send__(:<=>, large))
assert_true(small.__send__(:<, large))
assert_true(small.__send__(:<=, large))
assert_false(small.__send__(:>, large))
assert_false(small.__send__(:>=, large))
assert_true(large.__send__(:>, small))
end
end
assert('Integer#~', '15.2.8.3.8') do
assert_equal(-1, ~0)
assert_equal(-3, ~2)
end
assert('Integer#&', '15.2.8.3.9') do
assert_equal 1, 5 & 3
end
assert('Integer#|', '15.2.8.3.10') do
assert_equal 7, 5 | 3
end
assert('Integer#^', '15.2.8.3.11') do
assert_equal 6, 5 ^ 3
end
assert('Integer bitwise ops reject non-Integer operands') do
if Object.const_defined?(:Float)
assert_raise(TypeError) { 5 & 5.0 }
assert_raise(TypeError) { 5 | 5.0 }
assert_raise(TypeError) { 5 ^ 5.0 }
end
assert_raise(TypeError) { 5 | "3" }
assert_raise(TypeError) { 5 & nil }
assert_raise(TypeError) { 5 ^ :sym }
end
assert('Integer#<<', '15.2.8.3.12') do
assert_equal 46, 23 << 1
assert_equal 23, 46 << -1
skip unless Object.const_defined?(:Float)
end
assert('Integer#>>', '15.2.8.3.13') do
assert_equal 23, 46 >> 1
assert_equal 46, 23 >> -1
assert_equal 0, 23 >> 128
end
assert('Integer#ceil', '15.2.8.3.14') do
assert_equal 10, 10.ceil
assert_equal 10, 10.ceil(2)
assert_equal 1300, 1234.ceil(-2)
assert_equal(-1200, -1234.ceil(-2))
assert_equal 0, (-99).ceil(-2)
end
assert('Integer#ceil keeps a value that is already a multiple') do
assert_equal 0, 0.ceil(-1)
assert_equal 10, 10.ceil(-1)
assert_equal 100, 100.ceil(-2)
assert_equal 1200, 1200.ceil(-2)
assert_equal(-100, -100.ceil(-2))
assert_equal(-1200, -1200.ceil(-2))
end
assert('Integer#downto', '15.2.8.3.15') do
a = 0
3.downto(1) do |i|
a += i
end
assert_equal 6, a
end
assert('Integer#eql?', '15.2.8.3.16') do
a = 1.eql?(1)
b = 1.eql?(2)
c = 1.eql?(nil)
assert_true a
assert_false b
assert_false c
if Object.const_defined?(:Float)
assert_false 1.eql?(1.0)
assert_true 1 == 1.0
end
end
assert('Integer#floor', '15.2.8.3.17') do
a = 1.floor
assert_equal 1, a
assert_equal 1, 1.floor(2)
assert_equal 1200, 1234.floor(-2)
assert_equal(-1300, -1234.floor(-2))
assert_equal 0, 99.floor(-2)
end
assert('Integer#floor keeps a value that is already a multiple') do
assert_equal 0, 0.floor(-1)
assert_equal(-10, -10.floor(-1))
assert_equal(-100, -100.floor(-2))
assert_equal(-1200, -1200.floor(-2))
assert_equal 100, 100.floor(-2)
assert_equal 1200, 1200.floor(-2)
end
assert('Integer#next', '15.2.8.3.19') do
assert_equal 2, 1.next
end
assert('Integer#round', '15.2.8.3.20') do
assert_equal 1, 1.round
assert_equal 1, 1.round(2)
assert_equal 12300, 12345.round(-2)
assert_equal 12350, 12345.round(-1)
assert_equal 12000, 12345.round(-3)
assert_equal(-12300, -12345.round(-2))
assert_equal 0, 4.round(-1)
assert_equal 100, 99.round(-2)
assert_equal 0, 0.round(-1)
end
assert('Integer#round keeps a value that is already a multiple') do
assert_equal 10, 10.round(-1)
assert_equal 100, 100.round(-2)
assert_equal 1200, 1200.round(-2)
assert_equal(-100, -100.round(-2))
assert_equal(-1200, -1200.round(-2))
end
assert('Integer#round breaks a tie away from zero') do
assert_equal 10, 5.round(-1)
assert_equal 20, 15.round(-1)
assert_equal 30, 25.round(-1)
assert_equal 200, 150.round(-2)
assert_equal 300, 250.round(-2)
assert_equal(-10, -5.round(-1))
assert_equal(-20, -15.round(-1))
assert_equal(-30, -25.round(-1))
assert_equal(-200, -150.round(-2))
end
assert('Integer#succ', '15.2.8.3.21') do
assert_equal 2, 1.succ
end
assert('Integer#times', '15.2.8.3.22') do
a = 0
3.times do
a += 1
end
assert_equal 3, a
end
assert('Integer#to_f', '15.2.8.3.23') do
skip unless Object.const_defined?(:Float)
assert_equal 1.0, 1.to_f
end
assert('Integer#to_i', '15.2.8.3.24') do
assert_equal 1, 1.to_i
end
assert('Integer#to_s', '15.2.8.3.25') do
assert_equal "1", 1.to_s
assert_equal "-1", -1.to_s
assert_equal "1010", 10.to_s(2)
assert_equal "a", 10.to_s(36)
assert_equal "-a", -10.to_s(36)
assert_equal "30071", 12345.to_s(8)
assert_raise(ArgumentError) { 10.to_s(-1) }
assert_raise(ArgumentError) { 10.to_s(0) }
assert_raise(ArgumentError) { 10.to_s(1) }
assert_raise(ArgumentError) { 10.to_s(37) }
end
assert('Integer#to_s(2) with the smallest Integer') do
[31, 63].each do |e|
begin
min = -(1 << (e - 1)) * 2
rescue RangeError
next
end
assert_equal "-1" + "0" * e, min.to_s(2)
end
end
assert('Integer#truncate', '15.2.8.3.26') do
assert_equal 1, 1.truncate
assert_equal 1, 1.truncate(2)
assert_equal 1200, 1234.truncate(-2)
assert_equal(-1200, -1234.truncate(-2))
assert_equal 1200, 1200.truncate(-2)
assert_equal 0, 99.truncate(-2)
end
assert('Integer rounding to a power of ten wider than an mrb_int') do
(19..25).each do |n|
assert_equal 0, 12345.round(-n)
assert_equal 0, (-12345).round(-n)
assert_equal 0, 12345.truncate(-n)
assert_equal 0, 12345.floor(-n)
assert_equal 0, (-12345).ceil(-n)
end
end
assert('Integer#upto', '15.2.8.3.27') do
a = 0
1.upto(3) do |i|
a += i
end
assert_equal 6, a
end
assert('Integer#divmod', '15.2.8.3.30') do
assert_equal [ 0, 0], 0.divmod(1)
assert_equal [ 0, 1], 1.divmod(3)
assert_equal [ 3, 0], 3.divmod(1)
assert_equal [ 2, 6], 20.divmod(7)
assert_equal [-1, 2], -3.divmod(5)
assert_equal [-2, -1], 25.divmod(-13)
assert_equal [ 1, -6], -13.divmod(-7)
end
assert('Integer.__ensure converts its argument without dispatching') do
evil = Class.new { def __to_int; 2; end }.new
assert_raise(TypeError) { Integer.__ensure(evil) }
assert_raise(TypeError) { Integer.__ensure(Class.new { def to_int; 2; end }.new) }
assert_equal 2, Integer.__ensure(2)
assert_equal 1, Integer.__ensure(1.9) if Object.const_defined?(:Float)
assert_raise(TypeError) { Integer.__ensure("2") }
assert_raise(TypeError) { Integer.__ensure(nil) }
end
assert('Integer arithmetic redefined on Integer itself reaches the redefinition') do
Integer.class_eval do
alias_method :__add_before_test, :+
alias_method :__sub_before_test, :-
alias_method :__mul_before_test, :*
alias_method :__div_before_test, :/
def +(other) [:add, self, other] end
def -(other) [:sub, self, other] end
def *(other) [:mul, self, other] end
def /(other) [:div, self, other] end
end
begin
a = 7
b = 2
sum = a + b
diff = a - b
prod = a * b
quot = a / b
imm_sum = a + 1
imm_diff = a - 1
lv = a
lv += 1
lv_sum = lv
lv = a
lv -= 1
lv_diff = lv
mixed = a + 2.5 if Object.const_defined?(:Float)
ensure
Integer.class_eval do
alias_method :+, :__add_before_test
alias_method :-, :__sub_before_test
alias_method :*, :__mul_before_test
alias_method :/, :__div_before_test
if respond_to?(:remove_method, true)
remove_method :__add_before_test, :__sub_before_test,
:__mul_before_test, :__div_before_test
end
end
end
assert_equal [:add, 7, 2], sum
assert_equal [:sub, 7, 2], diff
assert_equal [:mul, 7, 2], prod
assert_equal [:div, 7, 2], quot
assert_equal [:add, 7, 1], imm_sum
assert_equal [:sub, 7, 1], imm_diff
assert_equal [:add, 7, 1], lv_sum
assert_equal [:sub, 7, 1], lv_diff
assert_equal [:add, 7, 2.5], mixed if Object.const_defined?(:Float)
a = 7
b = 2
assert_equal 9, a + b
assert_equal 8, a + 1
a += 1
assert_equal 8, a
end
assert('Integer comparison redefined on Integer itself reaches the redefinition') do
Integer.class_eval do
alias_method :__eq_before_test, :==
alias_method :__lt_before_test, :<
alias_method :__le_before_test, :<=
alias_method :__gt_before_test, :>
alias_method :__ge_before_test, :>=
def ==(other) [:eq, self, other] end
def <(other) [:lt, self, other] end
def <=(other) [:le, self, other] end
def >(other) [:gt, self, other] end
def >=(other) [:ge, self, other] end
end
begin
a = 7
b = 2
eq = a == b
same = a == a
lt = a < b
le = a <= b
gt = a > b
ge = a >= b
mixed = a < 2.5 if Object.const_defined?(:Float)
index = [a].index(b)
ensure
Integer.class_eval do
alias_method :==, :__eq_before_test
alias_method :<, :__lt_before_test
alias_method :<=, :__le_before_test
alias_method :>, :__gt_before_test
alias_method :>=, :__ge_before_test
if respond_to?(:remove_method, true)
remove_method :__eq_before_test, :__lt_before_test, :__le_before_test,
:__gt_before_test, :__ge_before_test
end
end
end
assert_equal [:eq, 7, 2], eq
assert_equal [:eq, 7, 7], same
assert_equal [:lt, 7, 2], lt
assert_equal [:le, 7, 2], le
assert_equal [:gt, 7, 2], gt
assert_equal [:ge, 7, 2], ge
assert_equal 0, index
assert_equal [:lt, 7, 2.5], mixed if Object.const_defined?(:Float)
a = 7
b = 2
assert_false a == b
assert_true a == a
assert_false a < b
assert_true a >= b
end
assert('Integer operators on two literals reach a redefinition') do
Integer.class_eval do
alias_method :__add_before_test, :+
alias_method :__sub_before_test, :-
alias_method :__mul_before_test, :*
alias_method :__div_before_test, :/
alias_method :__lshift_before_test, :<<
alias_method :__rshift_before_test, :>>
alias_method :__mod_before_test, :%
alias_method :__and_before_test, :&
alias_method :__or_before_test, :|
alias_method :__xor_before_test, :^
alias_method :__inv_before_test, :~
def +(other) [:add, self, other] end
def -(other) [:sub, self, other] end
def *(other) [:mul, self, other] end
def /(other) [:div, self, other] end
def <<(other) [:lshift, self, other] end
def >>(other) [:rshift, self, other] end
def %(other) [:mod, self, other] end
def &(other) [:and, self, other] end
def |(other) [:or, self, other] end
def ^(other) [:xor, self, other] end
def ~() [:inv, self] end
end
begin
got = [1 + 2, 5 - 3, 5 * 3, 6 / 3, 1 << 2, 8 >> 1, 7 % 3, 6 & 3, 6 | 3, 6 ^ 3, ~1]
i = 7
i += 1
incremented = i
negative = -1
ensure
Integer.class_eval do
alias_method :+, :__add_before_test
alias_method :-, :__sub_before_test
alias_method :*, :__mul_before_test
alias_method :/, :__div_before_test
alias_method :<<, :__lshift_before_test
alias_method :>>, :__rshift_before_test
alias_method :%, :__mod_before_test
alias_method :&, :__and_before_test
alias_method :|, :__or_before_test
alias_method :^, :__xor_before_test
alias_method :~, :__inv_before_test
if respond_to?(:remove_method, true)
remove_method :__add_before_test, :__sub_before_test, :__mul_before_test,
:__div_before_test, :__lshift_before_test, :__rshift_before_test,
:__mod_before_test, :__and_before_test, :__or_before_test,
:__xor_before_test, :__inv_before_test
end
end
end
assert_equal [[:add, 1, 2], [:sub, 5, 3], [:mul, 5, 3], [:div, 6, 3],
[:lshift, 1, 2], [:rshift, 8, 1], [:mod, 7, 3],
[:and, 6, 3], [:or, 6, 3], [:xor, 6, 3], [:inv, 1]], got
assert_equal [:add, 7, 1], incremented
assert_equal(-1, negative)
assert_equal 3, 1 + 2
assert_equal 4, 1 << 2
assert_equal(-2, ~1)
i = 7
i += 1
assert_equal 8, i
end