1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Use the correct values for int max and min

We had accidentally gone one power of two too far. In addition, we need
to handle minimum values as well as the maximum.
This commit is contained in:
Sean Griffin 2014-10-31 13:25:16 -06:00
parent aeb431a6ca
commit 6af9411c2d
3 changed files with 119 additions and 56 deletions

View file

@ -3,12 +3,21 @@ module ActiveRecord
class Integer < Value # :nodoc:
include Numeric
def initialize(*)
super
@range = -max_value...max_value
end
def type
:integer
end
alias type_cast_for_database type_cast
protected
attr_reader :range
private
def cast_value(value)
@ -17,25 +26,20 @@ module ActiveRecord
when false then 0
else
result = value.to_i rescue nil
ensure_below_max(result) if result
ensure_in_range(result) if result
result
end
end
def ensure_below_max(value)
if value > max_value
def ensure_in_range(value)
unless range.cover?(value)
raise RangeError, "#{value} is too large for #{self.class} with limit #{limit || 4}"
end
end
def max_value
@max_value = determine_max_value unless defined?(@max_value)
@max_value
end
def determine_max_value
limit = self.limit || 4
2 << (limit * 8 - 1) # 8 bits per byte with one bit for sign
1 << (limit * 8 - 1) # 8 bits per byte with one bit for sign
end
end
end

View file

@ -0,0 +1,106 @@
require "cases/helper"
require "models/company"
module ActiveRecord
module Type
class IntegerTest < ActiveRecord::TestCase
test "simple values" do
type = Type::Integer.new
assert_equal 1, type.type_cast_from_user(1)
assert_equal 1, type.type_cast_from_user('1')
assert_equal 1, type.type_cast_from_user('1ignore')
assert_equal 0, type.type_cast_from_user('bad1')
assert_equal 0, type.type_cast_from_user('bad')
assert_equal 1, type.type_cast_from_user(1.7)
assert_equal 0, type.type_cast_from_user(false)
assert_equal 1, type.type_cast_from_user(true)
assert_nil type.type_cast_from_user(nil)
end
test "random objects cast to nil" do
type = Type::Integer.new
assert_nil type.type_cast_from_user([1,2])
assert_nil type.type_cast_from_user({1 => 2})
assert_nil type.type_cast_from_user((1..2))
end
test "casting ActiveRecord models" do
type = Type::Integer.new
firm = Firm.create(:name => 'Apple')
assert_nil type.type_cast_from_user(firm)
end
test "casting objects without to_i" do
type = Type::Integer.new
assert_nil type.type_cast_from_user(::Object.new)
end
test "casting nan and infinity" do
type = Type::Integer.new
assert_nil type.type_cast_from_user(::Float::NAN)
assert_nil type.type_cast_from_user(1.0/0.0)
end
test "changed?" do
type = Type::Integer.new
assert type.changed?(5, 5, '5wibble')
assert_not type.changed?(5, 5, '5')
assert_not type.changed?(5, 5, '5.0')
assert_not type.changed?(nil, nil, nil)
end
test "values below int min value are out of range" do
assert_raises(::RangeError) do
Integer.new.type_cast_from_user("-2147483649")
end
end
test "values above int max value are out of range" do
assert_raises(::RangeError) do
Integer.new.type_cast_from_user("2147483648")
end
end
test "very small numbers are out of range" do
assert_raises(::RangeError) do
Integer.new.type_cast_from_user("-9999999999999999999999999999999")
end
end
test "very large numbers are in range" do
assert_raises(::RangeError) do
Integer.new.type_cast_from_user("9999999999999999999999999999999")
end
end
test "normal numbers are in range" do
type = Integer.new
assert_equal(0, type.type_cast_from_user("0"))
assert_equal(-1, type.type_cast_from_user("-1"))
assert_equal(1, type.type_cast_from_user("1"))
end
test "int max value is in range" do
assert_equal(2147483647, Integer.new.type_cast_from_user("2147483647"))
end
test "int min value is in range" do
assert_equal(-2147483648, Integer.new.type_cast_from_user("-2147483648"))
end
test "columns with a larger limit have larger ranges" do
type = Integer.new(limit: 8)
assert_equal(9223372036854775807, type.type_cast_from_user("9223372036854775807"))
assert_equal(-9223372036854775808, type.type_cast_from_user("-9223372036854775808"))
assert_raises(::RangeError) do
type.type_cast_from_user("-9999999999999999999999999999999")
end
assert_raises(::RangeError) do
type.type_cast_from_user("9999999999999999999999999999999")
end
end
end
end
end

View file

@ -1,5 +1,4 @@
require "cases/helper"
require 'models/company'
module ActiveRecord
module ConnectionAdapters
@ -37,52 +36,6 @@ module ActiveRecord
end
end
def test_type_cast_integer
type = Type::Integer.new
assert_equal 1, type.type_cast_from_user(1)
assert_equal 1, type.type_cast_from_user('1')
assert_equal 1, type.type_cast_from_user('1ignore')
assert_equal 0, type.type_cast_from_user('bad1')
assert_equal 0, type.type_cast_from_user('bad')
assert_equal 1, type.type_cast_from_user(1.7)
assert_equal 0, type.type_cast_from_user(false)
assert_equal 1, type.type_cast_from_user(true)
assert_nil type.type_cast_from_user(nil)
end
def test_type_cast_non_integer_to_integer
type = Type::Integer.new
assert_nil type.type_cast_from_user([1,2])
assert_nil type.type_cast_from_user({1 => 2})
assert_nil type.type_cast_from_user((1..2))
end
def test_type_cast_activerecord_to_integer
type = Type::Integer.new
firm = Firm.create(:name => 'Apple')
assert_nil type.type_cast_from_user(firm)
end
def test_type_cast_object_without_to_i_to_integer
type = Type::Integer.new
assert_nil type.type_cast_from_user(Object.new)
end
def test_type_cast_nan_and_infinity_to_integer
type = Type::Integer.new
assert_nil type.type_cast_from_user(Float::NAN)
assert_nil type.type_cast_from_user(1.0/0.0)
end
def test_changing_integers
type = Type::Integer.new
assert type.changed?(5, 5, '5wibble')
assert_not type.changed?(5, 5, '5')
assert_not type.changed?(5, 5, '5.0')
assert_not type.changed?(nil, nil, nil)
end
def test_type_cast_float
type = Type::Float.new
assert_equal 1.0, type.type_cast_from_user("1")