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:
parent
aeb431a6ca
commit
6af9411c2d
3 changed files with 119 additions and 56 deletions
|
@ -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
|
||||
|
|
106
activerecord/test/cases/type/integer_test.rb
Normal file
106
activerecord/test/cases/type/integer_test.rb
Normal 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
|
|
@ -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")
|
||||
|
|
Loading…
Reference in a new issue