3 require 'models/minimalistic'
5 class AttributeMethodsTest
< ActiveRecord
::TestCase
8 @old_suffixes = ActiveRecord
::Base.send(:attribute_method_suffixes).dup
9 @target = Class
.new(ActiveRecord
::Base)
10 @target.table_name
= 'topics'
14 ActiveRecord
::Base.send(:attribute_method_suffixes).clear
15 ActiveRecord
::Base.attribute_method_suffix
*@old_suffixes
18 def test_match_attribute_method_query_returns_match_data
19 assert_not_nil md
= @target.match_attribute_method
?('title=')
20 assert_equal
'title', md
.pre_match
21 assert_equal
['='], md
.captures
23 %w(_hello_world ist
! _maybe
?).each
do |suffix
|
24 @target.class_eval
"def attribute#{suffix}(*args) args end"
25 @target.attribute_method_suffix suffix
27 assert_not_nil md
= @target.match_attribute_method
?("title#{suffix}")
28 assert_equal
'title', md
.pre_match
29 assert_equal
[suffix
], md
.captures
33 def test_declared_attribute_method_affects_respond_to_and_method_missing
34 topic
= @target.new(:title => 'Budget')
35 assert topic
.respond_to
?('title')
36 assert_equal
'Budget', topic
.title
37 assert
!topic
.respond_to
?('title_hello_world')
38 assert_raise(NoMethodError
) { topic
.title_hello_world
}
40 %w(_hello_world _it
! _candidate
= able
?).each
do |suffix
|
41 @target.class_eval
"def attribute#{suffix}(*args) args end"
42 @target.attribute_method_suffix suffix
44 meth
= "title#{suffix}"
45 assert topic
.respond_to
?(meth
)
46 assert_equal
['title'], topic
.send(meth
)
47 assert_equal
['title', 'a'], topic
.send(meth
, 'a')
48 assert_equal
['title', 1, 2, 3], topic
.send(meth
, 1, 2, 3)
52 def test_should_unserialize_attributes_for_frozen_records
53 myobj
= {:value1 => :value2}
54 topic
= Topic
.create("content" => myobj
)
56 assert_equal myobj
, topic
.content
59 def test_typecast_attribute_from_select_to_false
60 topic
= Topic
.create(:title => 'Budget')
61 topic
= Topic
.find(:first, :select => "topics.*, 1=2 as is_test")
62 assert
!topic
.is_test
?
65 def test_typecast_attribute_from_select_to_true
66 topic
= Topic
.create(:title => 'Budget')
67 topic
= Topic
.find(:first, :select => "topics.*, 2=2 as is_test")
71 def test_kernel_methods_not_implemented_in_activerecord
72 %w(test name display y
).each
do |method
|
73 assert
!ActiveRecord
::Base.instance_method_already_implemented
?(method
), "##{method} is defined"
77 def test_primary_key_implemented
78 assert Class
.new(ActiveRecord
::Base).instance_method_already_implemented
?('id')
81 def test_defined_kernel_methods_implemented_in_model
82 %w(test name display y
).each
do |method
|
83 klass
= Class
.new ActiveRecord
::Base
84 klass
.class_eval
"def #{method}() 'defined #{method}' end"
85 assert klass
.instance_method_already_implemented
?(method
), "##{method} is not defined"
89 def test_defined_kernel_methods_implemented_in_model_abstract_subclass
90 %w(test name display y
).each
do |method
|
91 abstract
= Class
.new ActiveRecord
::Base
92 abstract
.class_eval
"def #{method}() 'defined #{method}' end"
93 abstract
.abstract_class
= true
94 klass
= Class
.new abstract
95 assert klass
.instance_method_already_implemented
?(method
), "##{method} is not defined"
99 def test_raises_dangerous_attribute_error_when_defining_activerecord_method_in_model
100 %w(save create_or_update
).each
do |method
|
101 klass
= Class
.new ActiveRecord
::Base
102 klass
.class_eval
"def #{method}() 'defined #{method}' end"
103 assert_raise ActiveRecord
::DangerousAttributeError do
104 klass
.instance_method_already_implemented
?(method
)
109 def test_only_time_related_columns_are_meant_to_be_cached_by_default
110 expected
= %w(datetime timestamp time date
).sort
111 assert_equal expected
, ActiveRecord
::Base.attribute_types_cached_by_default
.map(&:to_s).sort
114 def test_declaring_attributes_as_cached_adds_them_to_the_attributes_cached_by_default
115 default_attributes
= Topic
.cached_attributes
116 Topic
.cache_attributes
:replies_count
117 expected
= default_attributes
+ ["replies_count"]
118 assert_equal expected
.sort
, Topic
.cached_attributes
.sort
119 Topic
.instance_variable_set
"@cached_attributes", nil
122 def test_time_related_columns_are_actually_cached
123 column_types
= %w(datetime timestamp time date
).map(&:to_sym)
124 column_names
= Topic
.columns
.select
{|c
| column_types
.include?(c
.type
) }.map(&:name)
126 assert_equal column_names
.sort
, Topic
.cached_attributes
.sort
127 assert_equal time_related_columns_on_topic
.sort
, Topic
.cached_attributes
.sort
130 def test_accessing_cached_attributes_caches_the_converted_values_and_nothing_else
132 cache
= t
.instance_variable_get
"@attributes_cache"
137 all_columns
= Topic
.columns
.map(&:name)
138 cached_columns
= time_related_columns_on_topic
139 uncached_columns
= all_columns
- cached_columns
141 all_columns
.each
do |attr_name
|
142 attribute_gets_cached
= Topic
.cache_attribute
?(attr_name
)
143 val
= t
.send attr_name
unless attr_name
== "type"
144 if attribute_gets_cached
145 assert cached_columns
.include?(attr_name
)
146 assert_equal val
, cache
[attr_name
]
148 assert uncached_columns
.include?(attr_name
)
149 assert
!cache
.include?(attr_name
)
154 def test_time_attributes_are_retrieved_in_current_time_zone
155 in_time_zone
"Pacific Time (US & Canada)" do
156 utc_time
= Time
.utc(2008, 1, 1)
158 record
[:written_on] = utc_time
159 assert_equal utc_time
, record
.written_on
# record.written on is equal to (i.e., simultaneous with) utc_time
160 assert_kind_of ActiveSupport
::TimeWithZone, record
.written_on
# but is a TimeWithZone
161 assert_equal ActiveSupport
::TimeZone["Pacific Time (US & Canada)"], record
.written_on
.time_zone
# and is in the current Time.zone
162 assert_equal Time
.utc(2007, 12, 31, 16), record
.written_on
.time
# and represents time values adjusted accordingly
166 def test_setting_time_zone_aware_attribute_to_utc
167 in_time_zone
"Pacific Time (US & Canada)" do
168 utc_time
= Time
.utc(2008, 1, 1)
170 record
.written_on
= utc_time
171 assert_equal utc_time
, record
.written_on
172 assert_equal ActiveSupport
::TimeZone["Pacific Time (US & Canada)"], record
.written_on
.time_zone
173 assert_equal Time
.utc(2007, 12, 31, 16), record
.written_on
.time
177 def test_setting_time_zone_aware_attribute_in_other_time_zone
178 utc_time
= Time
.utc(2008, 1, 1)
179 cst_time
= utc_time
.in_time_zone("Central Time (US & Canada)")
180 in_time_zone
"Pacific Time (US & Canada)" do
182 record
.written_on
= cst_time
183 assert_equal utc_time
, record
.written_on
184 assert_equal ActiveSupport
::TimeZone["Pacific Time (US & Canada)"], record
.written_on
.time_zone
185 assert_equal Time
.utc(2007, 12, 31, 16), record
.written_on
.time
189 def test_setting_time_zone_aware_attribute_with_string
190 utc_time
= Time
.utc(2008, 1, 1)
191 (-11..13).each
do |timezone_offset
|
192 time_string
= utc_time
.in_time_zone(timezone_offset
).to_s
193 in_time_zone
"Pacific Time (US & Canada)" do
195 record
.written_on
= time_string
196 assert_equal Time
.zone
.parse(time_string
), record
.written_on
197 assert_equal ActiveSupport
::TimeZone["Pacific Time (US & Canada)"], record
.written_on
.time_zone
198 assert_equal Time
.utc(2007, 12, 31, 16), record
.written_on
.time
203 def test_setting_time_zone_aware_attribute_to_blank_string_returns_nil
204 in_time_zone
"Pacific Time (US & Canada)" do
206 record
.written_on
= ' '
207 assert_nil record
.written_on
211 def test_setting_time_zone_aware_attribute_interprets_time_zone_unaware_string_in_time_zone
212 time_string
= 'Tue Jan 01 00:00:00 2008'
213 (-11..13).each
do |timezone_offset
|
214 in_time_zone timezone_offset
do
216 record
.written_on
= time_string
217 assert_equal Time
.zone
.parse(time_string
), record
.written_on
218 assert_equal ActiveSupport
::TimeZone[timezone_offset
], record
.written_on
.time_zone
219 assert_equal Time
.utc(2008, 1, 1), record
.written_on
.time
224 def test_setting_time_zone_aware_attribute_in_current_time_zone
225 utc_time
= Time
.utc(2008, 1, 1)
226 in_time_zone
"Pacific Time (US & Canada)" do
228 record
.written_on
= utc_time
.in_time_zone
229 assert_equal utc_time
, record
.written_on
230 assert_equal ActiveSupport
::TimeZone["Pacific Time (US & Canada)"], record
.written_on
.time_zone
231 assert_equal Time
.utc(2007, 12, 31, 16), record
.written_on
.time
235 def test_setting_time_zone_conversion_for_attributes_should_write_value_on_class_variable
236 Topic
.skip_time_zone_conversion_for_attributes
= [:field_a]
237 Minimalistic
.skip_time_zone_conversion_for_attributes
= [:field_b]
239 assert_equal
[:field_a], Topic
.skip_time_zone_conversion_for_attributes
240 assert_equal
[:field_b], Minimalistic
.skip_time_zone_conversion_for_attributes
243 def test_read_attributes_respect_access_control
246 topic
= @target.new(:title => "The pros and cons of programming naked.")
247 assert
!topic
.respond_to
?(:title)
248 exception
= assert_raise(NoMethodError
) { topic
.title
}
249 assert_equal
"Attempt to call private method", exception
.message
250 assert_equal
"I'm private", topic
.send(:title)
253 def test_write_attributes_respect_access_control
254 privatize("title=(value)")
257 assert
!topic
.respond_to
?(:title=)
258 exception
= assert_raise(NoMethodError
) { topic
.title
= "Pants"}
259 assert_equal
"Attempt to call private method", exception
.message
260 topic
.send(:title=, "Very large pants")
263 def test_question_attributes_respect_access_control
266 topic
= @target.new(:title => "Isaac Newton's pants")
267 assert
!topic
.respond_to
?(:title?)
268 exception
= assert_raise(NoMethodError
) { topic
.title
? }
269 assert_equal
"Attempt to call private method", exception
.message
270 assert topic
.send(:title?)
273 def test_bulk_update_respects_access_control
274 privatize("title=(value)")
276 assert_raise(ActiveRecord
::UnknownAttributeError) { topic
= @target.new(:title => "Rants about pants") }
277 assert_raise(ActiveRecord
::UnknownAttributeError) { @target.new
.attributes
= { :title => "Ants in pants" } }
281 def time_related_columns_on_topic
282 Topic
.columns
.select
{|c
| [:time, :date, :datetime, :timestamp].include?(c
.type
)}.map(&:name)
285 def in_time_zone(zone
)
287 old_tz
= ActiveRecord
::Base.time_zone_aware_attributes
289 Time
.zone
= zone
? ActiveSupport
::TimeZone[zone
] : nil
290 ActiveRecord
::Base.time_zone_aware_attributes
= !zone
.nil?
294 ActiveRecord
::Base.time_zone_aware_attributes
= old_tz
297 def privatize(method_signature
)
298 @target.class_eval
<<-private_method
300 def #{method_signature}