2012-01-11 20:13:54 -05:00
|
|
|
require "cases/helper"
|
Fix undefined method `to_i' introduced since 3.2.8
This commit fixes a bug introduced in 96a13fc7 which breaks behaviour of
integer fields.
In 3.2.8, setting the value of an integer field to a non-integer (eg.
Array, Hash, etc.) would default to 1 (true) :
# 3.2.8
p = Post.new
p.category_id = [ 1, 2 ]
p.category_id # => 1
p.category_id = { 3 => 4 }
p.category_id # => 1
In 3.2.9 and above, this will raise a NoMethodError :
# 3.2.9
p = Post.new
p.category_id = [ 1, 2 ]
NoMethodError: undefined method `to_i' for [1, 2]:Array
Whilst at first blush this appear to be sensible, it combines in bad
ways with scoping.
For example, it is common to use scopes to control access to data :
@collection = Posts.where(:category_id => [ 1, 2 ])
@new_post = @collection.new
In 3.2.8, this would work as expected, creating a new Post object
(albeit with @new_post.category_id = 1). However, in 3.2.9 this will
cause the NoMethodError to be raised as above.
It is difficult to avoid triggering this error without descoping before
calling .new, breaking any apps running on 3.2.8 that rely on this
behaviour.
This patch deviates from 3.2.8 in that it does not retain the somewhat
spurious behaviour of setting the attribute to 1. Instead, it explicitly
sets these invalid values to nil :
p = Post.new
p.category_id = [ 1, 2 ]
p.category_id # => nil
This also fixes the situation where a scope using an array will
"pollute" any newly instantiated records.
@new_post = @collection.new
@new_post.category_id # => nil
Finally, 3.2.8 exhibited a behaviour where setting an object to an
integer field caused it to be coerced to "1". This has not been
retained, as it is spurious and surprising in the same way that setting
Arrays and Heshes was :
c = Category.find(6)
p = Post.new
# 3.2.8
p.category_id = c
p.category_id # => 1
# This patch
p.category_id = c
p.category_id # => nil
This commit includes explicit test cases that expose the original issue
with calling new on a scope that uses an Array. As this is a common
situation, an explicit test case is the best way to prevent regressions
in the future.
It also updates and separates existing tests to be explicit about the
situation that is being tested (eg. AR objects vs. other objects vs.
non-integers)
2013-01-03 06:26:53 -05:00
|
|
|
require 'models/company'
|
2012-01-11 20:13:54 -05:00
|
|
|
|
|
|
|
module ActiveRecord
|
|
|
|
module ConnectionAdapters
|
|
|
|
class ColumnTest < ActiveRecord::TestCase
|
|
|
|
def test_type_cast_boolean
|
|
|
|
column = Column.new("field", nil, "boolean")
|
2013-04-02 21:14:48 -04:00
|
|
|
assert column.type_cast('').nil?
|
|
|
|
assert column.type_cast(nil).nil?
|
|
|
|
|
2012-01-11 20:13:54 -05:00
|
|
|
assert column.type_cast(true)
|
|
|
|
assert column.type_cast(1)
|
|
|
|
assert column.type_cast('1')
|
|
|
|
assert column.type_cast('t')
|
|
|
|
assert column.type_cast('T')
|
|
|
|
assert column.type_cast('true')
|
|
|
|
assert column.type_cast('TRUE')
|
|
|
|
assert column.type_cast('on')
|
|
|
|
assert column.type_cast('ON')
|
2013-04-02 21:14:48 -04:00
|
|
|
|
|
|
|
# explicitly check for false vs nil
|
|
|
|
assert_equal false, column.type_cast(false)
|
|
|
|
assert_equal false, column.type_cast(0)
|
|
|
|
assert_equal false, column.type_cast('0')
|
|
|
|
assert_equal false, column.type_cast('f')
|
|
|
|
assert_equal false, column.type_cast('F')
|
|
|
|
assert_equal false, column.type_cast('false')
|
|
|
|
assert_equal false, column.type_cast('FALSE')
|
|
|
|
assert_equal false, column.type_cast('off')
|
|
|
|
assert_equal false, column.type_cast('OFF')
|
|
|
|
assert_equal false, column.type_cast(' ')
|
|
|
|
assert_equal false, column.type_cast("\u3000\r\n")
|
|
|
|
assert_equal false, column.type_cast("\u0000")
|
|
|
|
assert_equal false, column.type_cast('SOMETHING RANDOM')
|
2012-01-11 20:13:54 -05:00
|
|
|
end
|
2012-04-30 13:37:31 -04:00
|
|
|
|
|
|
|
def test_type_cast_integer
|
|
|
|
column = Column.new("field", nil, "integer")
|
|
|
|
assert_equal 1, column.type_cast(1)
|
|
|
|
assert_equal 1, column.type_cast('1')
|
|
|
|
assert_equal 1, column.type_cast('1ignore')
|
|
|
|
assert_equal 0, column.type_cast('bad1')
|
|
|
|
assert_equal 0, column.type_cast('bad')
|
|
|
|
assert_equal 1, column.type_cast(1.7)
|
2012-10-29 20:47:58 -04:00
|
|
|
assert_equal 0, column.type_cast(false)
|
|
|
|
assert_equal 1, column.type_cast(true)
|
2012-04-30 13:37:31 -04:00
|
|
|
assert_nil column.type_cast(nil)
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_type_cast_non_integer_to_integer
|
|
|
|
column = Column.new("field", nil, "integer")
|
Fix undefined method `to_i' introduced since 3.2.8
This commit fixes a bug introduced in 96a13fc7 which breaks behaviour of
integer fields.
In 3.2.8, setting the value of an integer field to a non-integer (eg.
Array, Hash, etc.) would default to 1 (true) :
# 3.2.8
p = Post.new
p.category_id = [ 1, 2 ]
p.category_id # => 1
p.category_id = { 3 => 4 }
p.category_id # => 1
In 3.2.9 and above, this will raise a NoMethodError :
# 3.2.9
p = Post.new
p.category_id = [ 1, 2 ]
NoMethodError: undefined method `to_i' for [1, 2]:Array
Whilst at first blush this appear to be sensible, it combines in bad
ways with scoping.
For example, it is common to use scopes to control access to data :
@collection = Posts.where(:category_id => [ 1, 2 ])
@new_post = @collection.new
In 3.2.8, this would work as expected, creating a new Post object
(albeit with @new_post.category_id = 1). However, in 3.2.9 this will
cause the NoMethodError to be raised as above.
It is difficult to avoid triggering this error without descoping before
calling .new, breaking any apps running on 3.2.8 that rely on this
behaviour.
This patch deviates from 3.2.8 in that it does not retain the somewhat
spurious behaviour of setting the attribute to 1. Instead, it explicitly
sets these invalid values to nil :
p = Post.new
p.category_id = [ 1, 2 ]
p.category_id # => nil
This also fixes the situation where a scope using an array will
"pollute" any newly instantiated records.
@new_post = @collection.new
@new_post.category_id # => nil
Finally, 3.2.8 exhibited a behaviour where setting an object to an
integer field caused it to be coerced to "1". This has not been
retained, as it is spurious and surprising in the same way that setting
Arrays and Heshes was :
c = Category.find(6)
p = Post.new
# 3.2.8
p.category_id = c
p.category_id # => 1
# This patch
p.category_id = c
p.category_id # => nil
This commit includes explicit test cases that expose the original issue
with calling new on a scope that uses an Array. As this is a common
situation, an explicit test case is the best way to prevent regressions
in the future.
It also updates and separates existing tests to be explicit about the
situation that is being tested (eg. AR objects vs. other objects vs.
non-integers)
2013-01-03 06:26:53 -05:00
|
|
|
assert_nil column.type_cast([1,2])
|
|
|
|
assert_nil column.type_cast({1 => 2})
|
|
|
|
assert_nil column.type_cast((1..2))
|
|
|
|
end
|
2012-10-29 20:47:58 -04:00
|
|
|
|
Fix undefined method `to_i' introduced since 3.2.8
This commit fixes a bug introduced in 96a13fc7 which breaks behaviour of
integer fields.
In 3.2.8, setting the value of an integer field to a non-integer (eg.
Array, Hash, etc.) would default to 1 (true) :
# 3.2.8
p = Post.new
p.category_id = [ 1, 2 ]
p.category_id # => 1
p.category_id = { 3 => 4 }
p.category_id # => 1
In 3.2.9 and above, this will raise a NoMethodError :
# 3.2.9
p = Post.new
p.category_id = [ 1, 2 ]
NoMethodError: undefined method `to_i' for [1, 2]:Array
Whilst at first blush this appear to be sensible, it combines in bad
ways with scoping.
For example, it is common to use scopes to control access to data :
@collection = Posts.where(:category_id => [ 1, 2 ])
@new_post = @collection.new
In 3.2.8, this would work as expected, creating a new Post object
(albeit with @new_post.category_id = 1). However, in 3.2.9 this will
cause the NoMethodError to be raised as above.
It is difficult to avoid triggering this error without descoping before
calling .new, breaking any apps running on 3.2.8 that rely on this
behaviour.
This patch deviates from 3.2.8 in that it does not retain the somewhat
spurious behaviour of setting the attribute to 1. Instead, it explicitly
sets these invalid values to nil :
p = Post.new
p.category_id = [ 1, 2 ]
p.category_id # => nil
This also fixes the situation where a scope using an array will
"pollute" any newly instantiated records.
@new_post = @collection.new
@new_post.category_id # => nil
Finally, 3.2.8 exhibited a behaviour where setting an object to an
integer field caused it to be coerced to "1". This has not been
retained, as it is spurious and surprising in the same way that setting
Arrays and Heshes was :
c = Category.find(6)
p = Post.new
# 3.2.8
p.category_id = c
p.category_id # => 1
# This patch
p.category_id = c
p.category_id # => nil
This commit includes explicit test cases that expose the original issue
with calling new on a scope that uses an Array. As this is a common
situation, an explicit test case is the best way to prevent regressions
in the future.
It also updates and separates existing tests to be explicit about the
situation that is being tested (eg. AR objects vs. other objects vs.
non-integers)
2013-01-03 06:26:53 -05:00
|
|
|
def test_type_cast_activerecord_to_integer
|
|
|
|
column = Column.new("field", nil, "integer")
|
|
|
|
firm = Firm.create(:name => 'Apple')
|
|
|
|
assert_nil column.type_cast(firm)
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_type_cast_object_without_to_i_to_integer
|
|
|
|
column = Column.new("field", nil, "integer")
|
|
|
|
assert_nil column.type_cast(Object.new)
|
2012-04-30 13:37:31 -04:00
|
|
|
end
|
2012-04-29 12:39:16 -04:00
|
|
|
|
2013-01-06 15:39:09 -05:00
|
|
|
def test_type_cast_nan_and_infinity_to_integer
|
|
|
|
column = Column.new("field", nil, "integer")
|
|
|
|
assert_nil column.type_cast(Float::NAN)
|
|
|
|
assert_nil column.type_cast(1.0/0.0)
|
|
|
|
end
|
|
|
|
|
2012-04-29 12:39:16 -04:00
|
|
|
def test_type_cast_time
|
|
|
|
column = Column.new("field", nil, "time")
|
2013-04-02 21:14:48 -04:00
|
|
|
assert_equal nil, column.type_cast(nil)
|
2012-04-29 12:39:16 -04:00
|
|
|
assert_equal nil, column.type_cast('')
|
2013-04-02 21:14:48 -04:00
|
|
|
assert_equal nil, column.type_cast('ABC')
|
2012-04-29 12:39:16 -04:00
|
|
|
|
|
|
|
time_string = Time.now.utc.strftime("%T")
|
|
|
|
assert_equal time_string, column.type_cast(time_string).strftime("%T")
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_type_cast_datetime_and_timestamp
|
|
|
|
[Column.new("field", nil, "datetime"), Column.new("field", nil, "timestamp")].each do |column|
|
2013-04-02 21:14:48 -04:00
|
|
|
assert_equal nil, column.type_cast(nil)
|
2012-04-29 12:39:16 -04:00
|
|
|
assert_equal nil, column.type_cast('')
|
|
|
|
assert_equal nil, column.type_cast(' ')
|
2013-04-02 21:14:48 -04:00
|
|
|
assert_equal nil, column.type_cast('ABC')
|
2012-04-29 12:39:16 -04:00
|
|
|
|
|
|
|
datetime_string = Time.now.utc.strftime("%FT%T")
|
|
|
|
assert_equal datetime_string, column.type_cast(datetime_string).strftime("%FT%T")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_type_cast_date
|
|
|
|
column = Column.new("field", nil, "date")
|
2013-04-02 21:14:48 -04:00
|
|
|
assert_equal nil, column.type_cast(nil)
|
2012-04-29 12:39:16 -04:00
|
|
|
assert_equal nil, column.type_cast('')
|
2013-04-02 21:14:48 -04:00
|
|
|
assert_equal nil, column.type_cast(' ')
|
|
|
|
assert_equal nil, column.type_cast('ABC')
|
2012-04-29 12:39:16 -04:00
|
|
|
|
|
|
|
date_string = Time.now.utc.strftime("%F")
|
|
|
|
assert_equal date_string, column.type_cast(date_string).strftime("%F")
|
|
|
|
end
|
2012-07-04 23:39:16 -04:00
|
|
|
|
|
|
|
def test_type_cast_duration_to_integer
|
|
|
|
column = Column.new("field", nil, "integer")
|
|
|
|
assert_equal 1800, column.type_cast(30.minutes)
|
|
|
|
assert_equal 7200, column.type_cast(2.hours)
|
|
|
|
end
|
2012-01-11 20:13:54 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|