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_kernel_methods_not_implemented_in_activerecord
60 %w(test name display y
).each
do |method
|
61 assert
!ActiveRecord
::Base.instance_method_already_implemented
?(method
), "##{method} is defined"
65 def test_primary_key_implemented
66 assert Class
.new(ActiveRecord
::Base).instance_method_already_implemented
?('id')
69 def test_defined_kernel_methods_implemented_in_model
70 %w(test name display y
).each
do |method
|
71 klass
= Class
.new ActiveRecord
::Base
72 klass
.class_eval
"def #{method}() 'defined #{method}' end"
73 assert klass
.instance_method_already_implemented
?(method
), "##{method} is not defined"
77 def test_defined_kernel_methods_implemented_in_model_abstract_subclass
78 %w(test name display y
).each
do |method
|
79 abstract
= Class
.new ActiveRecord
::Base
80 abstract
.class_eval
"def #{method}() 'defined #{method}' end"
81 abstract
.abstract_class
= true
82 klass
= Class
.new abstract
83 assert klass
.instance_method_already_implemented
?(method
), "##{method} is not defined"
87 def test_raises_dangerous_attribute_error_when_defining_activerecord_method_in_model
88 %w(save create_or_update
).each
do |method
|
89 klass
= Class
.new ActiveRecord
::Base
90 klass
.class_eval
"def #{method}() 'defined #{method}' end"
91 assert_raises ActiveRecord
::DangerousAttributeError do
92 klass
.instance_method_already_implemented
?(method
)
97 def test_only_time_related_columns_are_meant_to_be_cached_by_default
98 expected
= %w(datetime timestamp time date
).sort
99 assert_equal expected
, ActiveRecord
::Base.attribute_types_cached_by_default
.map(&:to_s).sort
102 def test_declaring_attributes_as_cached_adds_them_to_the_attributes_cached_by_default
103 default_attributes
= Topic
.cached_attributes
104 Topic
.cache_attributes
:replies_count
105 expected
= default_attributes
+ ["replies_count"]
106 assert_equal expected
.sort
, Topic
.cached_attributes
.sort
107 Topic
.instance_variable_set
"@cached_attributes", nil
110 def test_time_related_columns_are_actually_cached
111 column_types
= %w(datetime timestamp time date
).map(&:to_sym)
112 column_names
= Topic
.columns
.select
{|c
| column_types
.include?(c
.type
) }.map(&:name)
114 assert_equal column_names
.sort
, Topic
.cached_attributes
.sort
115 assert_equal time_related_columns_on_topic
.sort
, Topic
.cached_attributes
.sort
118 def test_accessing_cached_attributes_caches_the_converted_values_and_nothing_else
120 cache
= t
.instance_variable_get
"@attributes_cache"
125 all_columns
= Topic
.columns
.map(&:name)
126 cached_columns
= time_related_columns_on_topic
127 uncached_columns
= all_columns
- cached_columns
129 all_columns
.each
do |attr_name
|
130 attribute_gets_cached
= Topic
.cache_attribute
?(attr_name
)
131 val
= t
.send attr_name
unless attr_name
== "type"
132 if attribute_gets_cached
133 assert cached_columns
.include?(attr_name
)
134 assert_equal val
, cache
[attr_name
]
136 assert uncached_columns
.include?(attr_name
)
137 assert
!cache
.include?(attr_name
)
142 def test_time_attributes_are_retrieved_in_current_time_zone
143 in_time_zone
"Pacific Time (US & Canada)" do
144 utc_time
= Time
.utc(2008, 1, 1)
146 record
[:written_on] = utc_time
147 assert_equal utc_time
, record
.written_on
# record.written on is equal to (i.e., simultaneous with) utc_time
148 assert_kind_of ActiveSupport
::TimeWithZone, record
.written_on
# but is a TimeWithZone
149 assert_equal ActiveSupport
::TimeZone["Pacific Time (US & Canada)"], record
.written_on
.time_zone
# and is in the current Time.zone
150 assert_equal Time
.utc(2007, 12, 31, 16), record
.written_on
.time
# and represents time values adjusted accordingly
154 def test_setting_time_zone_aware_attribute_to_utc
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
160 assert_equal ActiveSupport
::TimeZone["Pacific Time (US & Canada)"], record
.written_on
.time_zone
161 assert_equal Time
.utc(2007, 12, 31, 16), record
.written_on
.time
165 def test_setting_time_zone_aware_attribute_in_other_time_zone
166 utc_time
= Time
.utc(2008, 1, 1)
167 cst_time
= utc_time
.in_time_zone("Central Time (US & Canada)")
168 in_time_zone
"Pacific Time (US & Canada)" do
170 record
.written_on
= cst_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_with_string
178 utc_time
= Time
.utc(2008, 1, 1)
179 (-11..13).each
do |timezone_offset
|
180 time_string
= utc_time
.in_time_zone(timezone_offset
).to_s
181 in_time_zone
"Pacific Time (US & Canada)" do
183 record
.written_on
= time_string
184 assert_equal Time
.zone
.parse(time_string
), record
.written_on
185 assert_equal ActiveSupport
::TimeZone["Pacific Time (US & Canada)"], record
.written_on
.time_zone
186 assert_equal Time
.utc(2007, 12, 31, 16), record
.written_on
.time
191 def test_setting_time_zone_aware_attribute_to_blank_string_returns_nil
192 in_time_zone
"Pacific Time (US & Canada)" do
194 record
.written_on
= ' '
195 assert_nil record
.written_on
199 def test_setting_time_zone_aware_attribute_interprets_time_zone_unaware_string_in_time_zone
200 time_string
= 'Tue Jan 01 00:00:00 2008'
201 (-11..13).each
do |timezone_offset
|
202 in_time_zone timezone_offset
do
204 record
.written_on
= time_string
205 assert_equal Time
.zone
.parse(time_string
), record
.written_on
206 assert_equal ActiveSupport
::TimeZone[timezone_offset
], record
.written_on
.time_zone
207 assert_equal Time
.utc(2008, 1, 1), record
.written_on
.time
212 def test_setting_time_zone_aware_attribute_in_current_time_zone
213 utc_time
= Time
.utc(2008, 1, 1)
214 in_time_zone
"Pacific Time (US & Canada)" do
216 record
.written_on
= utc_time
.in_time_zone
217 assert_equal utc_time
, record
.written_on
218 assert_equal ActiveSupport
::TimeZone["Pacific Time (US & Canada)"], record
.written_on
.time_zone
219 assert_equal Time
.utc(2007, 12, 31, 16), record
.written_on
.time
223 def test_setting_time_zone_conversion_for_attributes_should_write_value_on_class_variable
224 Topic
.skip_time_zone_conversion_for_attributes
= [:field_a]
225 Minimalistic
.skip_time_zone_conversion_for_attributes
= [:field_b]
227 assert_equal
[:field_a], Topic
.skip_time_zone_conversion_for_attributes
228 assert_equal
[:field_b], Minimalistic
.skip_time_zone_conversion_for_attributes
231 def test_read_attributes_respect_access_control
234 topic
= @target.new(:title => "The pros and cons of programming naked.")
235 assert
!topic
.respond_to
?(:title)
236 exception
= assert_raise(NoMethodError
) { topic
.title
}
237 assert_equal
"Attempt to call private method", exception
.message
238 assert_equal
"I'm private", topic
.send(:title)
241 def test_write_attributes_respect_access_control
242 privatize("title=(value)")
245 assert
!topic
.respond_to
?(:title=)
246 exception
= assert_raise(NoMethodError
) { topic
.title
= "Pants"}
247 assert_equal
"Attempt to call private method", exception
.message
248 topic
.send(:title=, "Very large pants")
251 def test_question_attributes_respect_access_control
254 topic
= @target.new(:title => "Isaac Newton's pants")
255 assert
!topic
.respond_to
?(:title?)
256 exception
= assert_raise(NoMethodError
) { topic
.title
? }
257 assert_equal
"Attempt to call private method", exception
.message
258 assert topic
.send(:title?)
261 def test_bulk_update_respects_access_control
262 privatize("title=(value)")
264 assert_raise(ActiveRecord
::UnknownAttributeError) { topic
= @target.new(:title => "Rants about pants") }
265 assert_raise(ActiveRecord
::UnknownAttributeError) { @target.new
.attributes
= { :title => "Ants in pants" } }
269 def time_related_columns_on_topic
270 Topic
.columns
.select
{|c
| [:time, :date, :datetime, :timestamp].include?(c
.type
)}.map(&:name)
273 def in_time_zone(zone
)
275 old_tz
= ActiveRecord
::Base.time_zone_aware_attributes
277 Time
.zone
= zone
? ActiveSupport
::TimeZone[zone
] : nil
278 ActiveRecord
::Base.time_zone_aware_attributes
= !zone
.nil?
282 ActiveRecord
::Base.time_zone_aware_attributes
= old_tz
285 def privatize(method_signature
)
286 @target.class_eval
<<-private_method
288 def #{method_signature}