Froze rails gems
[depot.git] / vendor / rails / activerecord / test / cases / attribute_methods_test.rb
1 require "cases/helper"
2 require 'models/topic'
3 require 'models/minimalistic'
4
5 class AttributeMethodsTest < ActiveRecord::TestCase
6 fixtures :topics
7 def setup
8 @old_suffixes = ActiveRecord::Base.send(:attribute_method_suffixes).dup
9 @target = Class.new(ActiveRecord::Base)
10 @target.table_name = 'topics'
11 end
12
13 def teardown
14 ActiveRecord::Base.send(:attribute_method_suffixes).clear
15 ActiveRecord::Base.attribute_method_suffix *@old_suffixes
16 end
17
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
22
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
26
27 assert_not_nil md = @target.match_attribute_method?("title#{suffix}")
28 assert_equal 'title', md.pre_match
29 assert_equal [suffix], md.captures
30 end
31 end
32
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 }
39
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
43
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)
49 end
50 end
51
52 def test_should_unserialize_attributes_for_frozen_records
53 myobj = {:value1 => :value2}
54 topic = Topic.create("content" => myobj)
55 topic.freeze
56 assert_equal myobj, topic.content
57 end
58
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"
62 end
63 end
64
65 def test_primary_key_implemented
66 assert Class.new(ActiveRecord::Base).instance_method_already_implemented?('id')
67 end
68
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"
74 end
75 end
76
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"
84 end
85 end
86
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)
93 end
94 end
95 end
96
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
100 end
101
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
108 end
109
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)
113
114 assert_equal column_names.sort, Topic.cached_attributes.sort
115 assert_equal time_related_columns_on_topic.sort, Topic.cached_attributes.sort
116 end
117
118 def test_accessing_cached_attributes_caches_the_converted_values_and_nothing_else
119 t = topics(:first)
120 cache = t.instance_variable_get "@attributes_cache"
121
122 assert_not_nil cache
123 assert cache.empty?
124
125 all_columns = Topic.columns.map(&:name)
126 cached_columns = time_related_columns_on_topic
127 uncached_columns = all_columns - cached_columns
128
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]
135 else
136 assert uncached_columns.include?(attr_name)
137 assert !cache.include?(attr_name)
138 end
139 end
140 end
141
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)
145 record = @target.new
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
151 end
152 end
153
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)
157 record = @target.new
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
162 end
163 end
164
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
169 record = @target.new
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
174 end
175 end
176
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
182 record = @target.new
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
187 end
188 end
189 end
190
191 def test_setting_time_zone_aware_attribute_to_blank_string_returns_nil
192 in_time_zone "Pacific Time (US & Canada)" do
193 record = @target.new
194 record.written_on = ' '
195 assert_nil record.written_on
196 end
197 end
198
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
203 record = @target.new
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
208 end
209 end
210 end
211
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
215 record = @target.new
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
220 end
221 end
222
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]
226
227 assert_equal [:field_a], Topic.skip_time_zone_conversion_for_attributes
228 assert_equal [:field_b], Minimalistic.skip_time_zone_conversion_for_attributes
229 end
230
231 def test_read_attributes_respect_access_control
232 privatize("title")
233
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)
239 end
240
241 def test_write_attributes_respect_access_control
242 privatize("title=(value)")
243
244 topic = @target.new
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")
249 end
250
251 def test_question_attributes_respect_access_control
252 privatize("title?")
253
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?)
259 end
260
261 def test_bulk_update_respects_access_control
262 privatize("title=(value)")
263
264 assert_raise(ActiveRecord::UnknownAttributeError) { topic = @target.new(:title => "Rants about pants") }
265 assert_raise(ActiveRecord::UnknownAttributeError) { @target.new.attributes = { :title => "Ants in pants" } }
266 end
267
268 private
269 def time_related_columns_on_topic
270 Topic.columns.select{|c| [:time, :date, :datetime, :timestamp].include?(c.type)}.map(&:name)
271 end
272
273 def in_time_zone(zone)
274 old_zone = Time.zone
275 old_tz = ActiveRecord::Base.time_zone_aware_attributes
276
277 Time.zone = zone ? ActiveSupport::TimeZone[zone] : nil
278 ActiveRecord::Base.time_zone_aware_attributes = !zone.nil?
279 yield
280 ensure
281 Time.zone = old_zone
282 ActiveRecord::Base.time_zone_aware_attributes = old_tz
283 end
284
285 def privatize(method_signature)
286 @target.class_eval <<-private_method
287 private
288 def #{method_signature}
289 "I'm private"
290 end
291 private_method
292 end
293 end