Froze rails gems
[depot.git] / vendor / rails / activerecord / test / cases / dirty_test.rb
1 require 'cases/helper'
2 require 'models/topic' # For booleans
3 require 'models/pirate' # For timestamps
4 require 'models/parrot'
5 require 'models/person' # For optimistic locking
6
7 class Pirate # Just reopening it, not defining it
8 attr_accessor :detected_changes_in_after_update # Boolean for if changes are detected
9 attr_accessor :changes_detected_in_after_update # Actual changes
10
11 after_update :check_changes
12
13 private
14 # after_save/update in sweepers, observers, and the model itself
15 # can end up checking dirty status and acting on the results
16 def check_changes
17 if self.changed?
18 self.detected_changes_in_after_update = true
19 self.changes_detected_in_after_update = self.changes
20 end
21 end
22 end
23
24 class DirtyTest < ActiveRecord::TestCase
25 def test_attribute_changes
26 # New record - no changes.
27 pirate = Pirate.new
28 assert !pirate.catchphrase_changed?
29 assert_nil pirate.catchphrase_change
30
31 # Change catchphrase.
32 pirate.catchphrase = 'arrr'
33 assert pirate.catchphrase_changed?
34 assert_nil pirate.catchphrase_was
35 assert_equal [nil, 'arrr'], pirate.catchphrase_change
36
37 # Saved - no changes.
38 pirate.save!
39 assert !pirate.catchphrase_changed?
40 assert_nil pirate.catchphrase_change
41
42 # Same value - no changes.
43 pirate.catchphrase = 'arrr'
44 assert !pirate.catchphrase_changed?
45 assert_nil pirate.catchphrase_change
46 end
47
48 def test_aliased_attribute_changes
49 # the actual attribute here is name, title is an
50 # alias setup via alias_attribute
51 parrot = Parrot.new
52 assert !parrot.title_changed?
53 assert_nil parrot.title_change
54
55 parrot.name = 'Sam'
56 assert parrot.title_changed?
57 assert_nil parrot.title_was
58 assert_equal parrot.name_change, parrot.title_change
59 end
60
61 def test_nullable_integer_not_marked_as_changed_if_new_value_is_blank
62 pirate = Pirate.new
63
64 ["", nil].each do |value|
65 pirate.parrot_id = value
66 assert !pirate.parrot_id_changed?
67 assert_nil pirate.parrot_id_change
68 end
69 end
70
71 def test_zero_to_blank_marked_as_changed
72 pirate = Pirate.new
73 pirate.catchphrase = "Yarrrr, me hearties"
74 pirate.parrot_id = 1
75 pirate.save
76
77 # check the change from 1 to ''
78 pirate = Pirate.find_by_catchphrase("Yarrrr, me hearties")
79 pirate.parrot_id = ''
80 assert pirate.parrot_id_changed?
81 assert_equal([1, nil], pirate.parrot_id_change)
82 pirate.save
83
84 # check the change from nil to 0
85 pirate = Pirate.find_by_catchphrase("Yarrrr, me hearties")
86 pirate.parrot_id = 0
87 assert pirate.parrot_id_changed?
88 assert_equal([nil, 0], pirate.parrot_id_change)
89 pirate.save
90
91 # check the change from 0 to ''
92 pirate = Pirate.find_by_catchphrase("Yarrrr, me hearties")
93 pirate.parrot_id = ''
94 assert pirate.parrot_id_changed?
95 assert_equal([0, nil], pirate.parrot_id_change)
96 end
97
98 def test_object_should_be_changed_if_any_attribute_is_changed
99 pirate = Pirate.new
100 assert !pirate.changed?
101 assert_equal [], pirate.changed
102 assert_equal Hash.new, pirate.changes
103
104 pirate.catchphrase = 'arrr'
105 assert pirate.changed?
106 assert_nil pirate.catchphrase_was
107 assert_equal %w(catchphrase), pirate.changed
108 assert_equal({'catchphrase' => [nil, 'arrr']}, pirate.changes)
109
110 pirate.save
111 assert !pirate.changed?
112 assert_equal [], pirate.changed
113 assert_equal Hash.new, pirate.changes
114 end
115
116 def test_attribute_will_change!
117 pirate = Pirate.create!(:catchphrase => 'arr')
118
119 pirate.catchphrase << ' matey'
120 assert !pirate.catchphrase_changed?
121
122 assert pirate.catchphrase_will_change!
123 assert pirate.catchphrase_changed?
124 assert_equal ['arr matey', 'arr matey'], pirate.catchphrase_change
125
126 pirate.catchphrase << '!'
127 assert pirate.catchphrase_changed?
128 assert_equal ['arr matey', 'arr matey!'], pirate.catchphrase_change
129 end
130
131 def test_association_assignment_changes_foreign_key
132 pirate = Pirate.create!(:catchphrase => 'jarl')
133 pirate.parrot = Parrot.create!
134 assert pirate.changed?
135 assert_equal %w(parrot_id), pirate.changed
136 end
137
138 def test_attribute_should_be_compared_with_type_cast
139 topic = Topic.new
140 assert topic.approved?
141 assert !topic.approved_changed?
142
143 # Coming from web form.
144 params = {:topic => {:approved => 1}}
145 # In the controller.
146 topic.attributes = params[:topic]
147 assert topic.approved?
148 assert !topic.approved_changed?
149 end
150
151 def test_partial_update
152 pirate = Pirate.new(:catchphrase => 'foo')
153 old_updated_on = 1.hour.ago.beginning_of_day
154
155 with_partial_updates Pirate, false do
156 assert_queries(2) { 2.times { pirate.save! } }
157 Pirate.update_all({ :updated_on => old_updated_on }, :id => pirate.id)
158 end
159
160 with_partial_updates Pirate, true do
161 assert_queries(0) { 2.times { pirate.save! } }
162 assert_equal old_updated_on, pirate.reload.updated_on
163
164 assert_queries(1) { pirate.catchphrase = 'bar'; pirate.save! }
165 assert_not_equal old_updated_on, pirate.reload.updated_on
166 end
167 end
168
169 def test_partial_update_with_optimistic_locking
170 person = Person.new(:first_name => 'foo')
171 old_lock_version = 1
172
173 with_partial_updates Person, false do
174 assert_queries(2) { 2.times { person.save! } }
175 Person.update_all({ :first_name => 'baz' }, :id => person.id)
176 end
177
178 with_partial_updates Person, true do
179 assert_queries(0) { 2.times { person.save! } }
180 assert_equal old_lock_version, person.reload.lock_version
181
182 assert_queries(1) { person.first_name = 'bar'; person.save! }
183 assert_not_equal old_lock_version, person.reload.lock_version
184 end
185 end
186
187 def test_changed_attributes_should_be_preserved_if_save_failure
188 pirate = Pirate.new
189 pirate.parrot_id = 1
190 assert !pirate.save
191 check_pirate_after_save_failure(pirate)
192
193 pirate = Pirate.new
194 pirate.parrot_id = 1
195 assert_raises(ActiveRecord::RecordInvalid) { pirate.save! }
196 check_pirate_after_save_failure(pirate)
197 end
198
199 def test_reload_should_clear_changed_attributes
200 pirate = Pirate.create!(:catchphrase => "shiver me timbers")
201 pirate.catchphrase = "*hic*"
202 assert pirate.changed?
203 pirate.reload
204 assert !pirate.changed?
205 end
206
207 def test_reverted_changes_are_not_dirty
208 phrase = "shiver me timbers"
209 pirate = Pirate.create!(:catchphrase => phrase)
210 pirate.catchphrase = "*hic*"
211 assert pirate.changed?
212 pirate.catchphrase = phrase
213 assert !pirate.changed?
214 end
215
216 def test_reverted_changes_are_not_dirty_after_multiple_changes
217 phrase = "shiver me timbers"
218 pirate = Pirate.create!(:catchphrase => phrase)
219 10.times do |i|
220 pirate.catchphrase = "*hic*" * i
221 assert pirate.changed?
222 end
223 assert pirate.changed?
224 pirate.catchphrase = phrase
225 assert !pirate.changed?
226 end
227
228
229 def test_reverted_changes_are_not_dirty_going_from_nil_to_value_and_back
230 pirate = Pirate.create!(:catchphrase => "Yar!")
231
232 pirate.parrot_id = 1
233 assert pirate.changed?
234 assert pirate.parrot_id_changed?
235 assert !pirate.catchphrase_changed?
236
237 pirate.parrot_id = nil
238 assert !pirate.changed?
239 assert !pirate.parrot_id_changed?
240 assert !pirate.catchphrase_changed?
241 end
242
243 def test_save_should_store_serialized_attributes_even_with_partial_updates
244 with_partial_updates(Topic) do
245 topic = Topic.create!(:content => {:a => "a"})
246 topic.content[:b] = "b"
247 #assert topic.changed? # Known bug, will fail
248 topic.save!
249 assert_equal "b", topic.content[:b]
250 topic.reload
251 assert_equal "b", topic.content[:b]
252 end
253 end
254
255 private
256 def with_partial_updates(klass, on = true)
257 old = klass.partial_updates?
258 klass.partial_updates = on
259 yield
260 ensure
261 klass.partial_updates = old
262 end
263
264 def check_pirate_after_save_failure(pirate)
265 assert pirate.changed?
266 assert pirate.parrot_id_changed?
267 assert_equal %w(parrot_id), pirate.changed
268 assert_nil pirate.parrot_id_was
269 end
270 end