cmoran92-paranoia 2.0.2a

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,760 @@
1
+ require 'active_record'
2
+
3
+ test_framework = if ActiveRecord::VERSION::STRING >= "4.1"
4
+ require 'minitest/autorun'
5
+ MiniTest::Test
6
+ else
7
+ require 'test/unit'
8
+ Test::Unit::TestCase
9
+ end
10
+ require File.expand_path(File.dirname(__FILE__) + "/../lib/paranoia")
11
+
12
+ def connect!
13
+ ActiveRecord::Base.establish_connection :adapter => 'sqlite3', database: ':memory:'
14
+ ActiveRecord::Base.connection.execute 'CREATE TABLE parent_models (id INTEGER NOT NULL PRIMARY KEY, deleted_at DATETIME)'
15
+ ActiveRecord::Base.connection.execute 'CREATE TABLE paranoid_models (id INTEGER NOT NULL PRIMARY KEY, parent_model_id INTEGER, deleted_at DATETIME)'
16
+ ActiveRecord::Base.connection.execute 'CREATE TABLE paranoid_model_with_belongs (id INTEGER NOT NULL PRIMARY KEY, parent_model_id INTEGER, deleted_at DATETIME, paranoid_model_with_has_one_id INTEGER)'
17
+ ActiveRecord::Base.connection.execute 'CREATE TABLE paranoid_model_with_anthor_class_name_belongs (id INTEGER NOT NULL PRIMARY KEY, parent_model_id INTEGER, deleted_at DATETIME, paranoid_model_with_has_one_id INTEGER)'
18
+ ActiveRecord::Base.connection.execute 'CREATE TABLE paranoid_model_with_foreign_key_belongs (id INTEGER NOT NULL PRIMARY KEY, parent_model_id INTEGER, deleted_at DATETIME, has_one_foreign_key_id INTEGER)'
19
+ ActiveRecord::Base.connection.execute 'CREATE TABLE featureful_models (id INTEGER NOT NULL PRIMARY KEY, deleted_at DATETIME, name VARCHAR(32))'
20
+ ActiveRecord::Base.connection.execute 'CREATE TABLE plain_models (id INTEGER NOT NULL PRIMARY KEY, deleted_at DATETIME)'
21
+ ActiveRecord::Base.connection.execute 'CREATE TABLE callback_models (id INTEGER NOT NULL PRIMARY KEY, deleted_at DATETIME)'
22
+ ActiveRecord::Base.connection.execute 'CREATE TABLE fail_callback_models (id INTEGER NOT NULL PRIMARY KEY, deleted_at DATETIME)'
23
+ ActiveRecord::Base.connection.execute 'CREATE TABLE related_models (id INTEGER NOT NULL PRIMARY KEY, parent_model_id INTEGER NOT NULL, deleted_at DATETIME)'
24
+ ActiveRecord::Base.connection.execute 'CREATE TABLE asplode_models (id INTEGER NOT NULL PRIMARY KEY, parent_model_id INTEGER, deleted_at DATETIME)'
25
+ ActiveRecord::Base.connection.execute 'CREATE TABLE employers (id INTEGER NOT NULL PRIMARY KEY, deleted_at DATETIME)'
26
+ ActiveRecord::Base.connection.execute 'CREATE TABLE employees (id INTEGER NOT NULL PRIMARY KEY, deleted_at DATETIME)'
27
+ ActiveRecord::Base.connection.execute 'CREATE TABLE jobs (id INTEGER NOT NULL PRIMARY KEY, employer_id INTEGER NOT NULL, employee_id INTEGER NOT NULL, deleted_at DATETIME)'
28
+ ActiveRecord::Base.connection.execute 'CREATE TABLE custom_column_models (id INTEGER NOT NULL PRIMARY KEY, destroyed_at DATETIME)'
29
+ ActiveRecord::Base.connection.execute 'CREATE TABLE custom_sentinel_models (id INTEGER NOT NULL PRIMARY KEY, deleted_at DATETIME NOT NULL)'
30
+ ActiveRecord::Base.connection.execute 'CREATE TABLE non_paranoid_models (id INTEGER NOT NULL PRIMARY KEY, parent_model_id INTEGER)'
31
+ end
32
+
33
+ class WithDifferentConnection < ActiveRecord::Base
34
+ establish_connection adapter: 'sqlite3', database: ':memory:'
35
+ connection.execute 'CREATE TABLE with_different_connections (id INTEGER NOT NULL PRIMARY KEY, deleted_at DATETIME)'
36
+ acts_as_paranoid
37
+ end
38
+
39
+ connect!
40
+
41
+ class ParanoiaTest < test_framework
42
+ def setup
43
+ ActiveRecord::Base.connection.tables.each do |table|
44
+ ActiveRecord::Base.connection.execute "DELETE FROM #{table}"
45
+ end
46
+ end
47
+
48
+ def test_plain_model_class_is_not_paranoid
49
+ assert_equal false, PlainModel.paranoid?
50
+ end
51
+
52
+ def test_paranoid_model_class_is_paranoid
53
+ assert_equal true, ParanoidModel.paranoid?
54
+ end
55
+
56
+ def test_plain_models_are_not_paranoid
57
+ assert_equal false, PlainModel.new.paranoid?
58
+ end
59
+
60
+ def test_paranoid_models_are_paranoid
61
+ assert_equal true, ParanoidModel.new.paranoid?
62
+ end
63
+
64
+ def test_paranoid_models_to_param
65
+ model = ParanoidModel.new
66
+ model.save
67
+ to_param = model.to_param
68
+
69
+ model.destroy
70
+
71
+ assert model.to_param
72
+ assert_equal to_param, model.to_param
73
+ end
74
+
75
+ def test_destroy_behavior_for_plain_models
76
+ model = PlainModel.new
77
+ assert_equal 0, model.class.count
78
+ model.save!
79
+ assert_equal 1, model.class.count
80
+ model.destroy
81
+
82
+ assert_equal true, model.deleted_at.nil?
83
+
84
+ assert_equal 0, model.class.count
85
+ assert_equal 0, model.class.unscoped.count
86
+ end
87
+
88
+ # Anti-regression test for #81, which would've introduced a bug to break this test.
89
+ def test_destroy_behavior_for_plain_models_callbacks
90
+ model = CallbackModel.new
91
+ model.save
92
+ model.remove_called_variables # clear called callback flags
93
+ model.destroy
94
+
95
+ assert_equal nil, model.instance_variable_get(:@update_callback_called)
96
+ assert_equal nil, model.instance_variable_get(:@save_callback_called)
97
+ assert_equal nil, model.instance_variable_get(:@validate_called)
98
+
99
+ assert model.instance_variable_get(:@destroy_callback_called)
100
+ assert model.instance_variable_get(:@after_destroy_callback_called)
101
+ assert model.instance_variable_get(:@after_commit_callback_called)
102
+ end
103
+
104
+
105
+ def test_delete_behavior_for_plain_models_callbacks
106
+ model = CallbackModel.new
107
+ model.save
108
+ model.remove_called_variables # clear called callback flags
109
+ model.delete
110
+
111
+ assert_equal nil, model.instance_variable_get(:@update_callback_called)
112
+ assert_equal nil, model.instance_variable_get(:@save_callback_called)
113
+ assert_equal nil, model.instance_variable_get(:@validate_called)
114
+ assert_equal nil, model.instance_variable_get(:@destroy_callback_called)
115
+ assert_equal nil, model.instance_variable_get(:@after_destroy_callback_called)
116
+ assert model.instance_variable_get(:@after_commit_callback_called)
117
+ end
118
+
119
+ def test_destroy_behavior_for_paranoid_models
120
+ model = ParanoidModel.new
121
+ assert_equal 0, model.class.count
122
+ model.save!
123
+ assert_equal 1, model.class.count
124
+ model.destroy
125
+
126
+ assert_equal false, model.deleted_at.nil?
127
+
128
+ assert_equal 0, model.class.count
129
+ assert_equal 1, model.class.unscoped.count
130
+ end
131
+
132
+ def test_scoping_behavior_for_paranoid_models
133
+ parent1 = ParentModel.create
134
+ parent2 = ParentModel.create
135
+ p1 = ParanoidModel.create(:parent_model => parent1)
136
+ p2 = ParanoidModel.create(:parent_model => parent2)
137
+ p1.destroy
138
+ p2.destroy
139
+ assert_equal 0, parent1.paranoid_models.count
140
+ assert_equal 1, parent1.paranoid_models.only_deleted.count
141
+ assert_equal 1, parent1.paranoid_models.deleted.count
142
+ p3 = ParanoidModel.create(:parent_model => parent1)
143
+ assert_equal 2, parent1.paranoid_models.with_deleted.count
144
+ assert_equal [p1,p3], parent1.paranoid_models.with_deleted
145
+ end
146
+
147
+ def test_destroy_behavior_for_custom_column_models
148
+ model = CustomColumnModel.new
149
+ assert_equal 0, model.class.count
150
+ model.save!
151
+ assert_nil model.destroyed_at
152
+ assert_equal 1, model.class.count
153
+ model.destroy
154
+
155
+ assert_equal false, model.destroyed_at.nil?
156
+ assert model.destroyed?
157
+
158
+ assert_equal 0, model.class.count
159
+ assert_equal 1, model.class.unscoped.count
160
+ assert_equal 1, model.class.only_deleted.count
161
+ assert_equal 1, model.class.deleted.count
162
+ end
163
+
164
+ def test_default_sentinel_value
165
+ assert_equal nil, ParanoidModel.paranoia_sentinel_value
166
+ end
167
+
168
+ def test_sentinel_value_for_custom_sentinel_models
169
+ model = CustomSentinelModel.new
170
+ assert_equal 0, model.class.count
171
+ model.save!
172
+ assert_equal DateTime.new(0), model.deleted_at
173
+ assert_equal 1, model.class.count
174
+ model.destroy
175
+
176
+ assert DateTime.new(0) != model.deleted_at
177
+ assert model.destroyed?
178
+
179
+ assert_equal 0, model.class.count
180
+ assert_equal 1, model.class.unscoped.count
181
+ assert_equal 1, model.class.only_deleted.count
182
+ assert_equal 1, model.class.deleted.count
183
+
184
+ model.restore
185
+ assert_equal DateTime.new(0), model.deleted_at
186
+ assert !model.destroyed?
187
+
188
+ assert_equal 1, model.class.count
189
+ assert_equal 1, model.class.unscoped.count
190
+ assert_equal 0, model.class.only_deleted.count
191
+ assert_equal 0, model.class.deleted.count
192
+ end
193
+
194
+ def test_destroy_behavior_for_featureful_paranoid_models
195
+ model = get_featureful_model
196
+ assert_equal 0, model.class.count
197
+ model.save!
198
+ assert_equal 1, model.class.count
199
+ model.destroy
200
+
201
+ assert_equal false, model.deleted_at.nil?
202
+
203
+ assert_equal 0, model.class.count
204
+ assert_equal 1, model.class.unscoped.count
205
+ end
206
+
207
+ # Regression test for #24
208
+ def test_chaining_for_paranoid_models
209
+ scope = FeaturefulModel.where(:name => "foo").only_deleted
210
+ assert_equal "foo", scope.where_values_hash['name']
211
+ assert_equal 2, scope.where_values.count
212
+ end
213
+
214
+ def test_only_destroyed_scope_for_paranoid_models
215
+ model = ParanoidModel.new
216
+ model.save
217
+ model.destroy
218
+ model2 = ParanoidModel.new
219
+ model2.save
220
+
221
+ assert_equal model, ParanoidModel.only_deleted.last
222
+ assert_equal false, ParanoidModel.only_deleted.include?(model2)
223
+ end
224
+
225
+ def test_default_scope_for_has_many_relationships
226
+ parent = ParentModel.create
227
+ assert_equal 0, parent.related_models.count
228
+
229
+ child = parent.related_models.create
230
+ assert_equal 1, parent.related_models.count
231
+
232
+ child.destroy
233
+ assert_equal false, child.deleted_at.nil?
234
+
235
+ assert_equal 0, parent.related_models.count
236
+ assert_equal 1, parent.related_models.unscoped.count
237
+ end
238
+
239
+ def test_default_scope_for_has_many_through_relationships
240
+ employer = Employer.create
241
+ employee = Employee.create
242
+ assert_equal 0, employer.jobs.count
243
+ assert_equal 0, employer.employees.count
244
+ assert_equal 0, employee.jobs.count
245
+ assert_equal 0, employee.employers.count
246
+
247
+ job = Job.create :employer => employer, :employee => employee
248
+ assert_equal 1, employer.jobs.count
249
+ assert_equal 1, employer.employees.count
250
+ assert_equal 1, employee.jobs.count
251
+ assert_equal 1, employee.employers.count
252
+
253
+ employee2 = Employee.create
254
+ job2 = Job.create :employer => employer, :employee => employee2
255
+ employee2.destroy
256
+ assert_equal 2, employer.jobs.count
257
+ assert_equal 1, employer.employees.count
258
+
259
+ job.destroy
260
+ assert_equal 1, employer.jobs.count
261
+ assert_equal 0, employer.employees.count
262
+ assert_equal 0, employee.jobs.count
263
+ assert_equal 0, employee.employers.count
264
+ end
265
+
266
+ def test_delete_behavior_for_callbacks
267
+ model = CallbackModel.new
268
+ model.save
269
+ model.delete
270
+ assert_equal nil, model.instance_variable_get(:@destroy_callback_called)
271
+ end
272
+
273
+ def test_destroy_behavior_for_callbacks
274
+ model = CallbackModel.new
275
+ model.save
276
+ model.destroy
277
+ assert model.instance_variable_get(:@destroy_callback_called)
278
+ end
279
+
280
+ def test_restore
281
+ model = ParanoidModel.new
282
+ model.save
283
+ id = model.id
284
+ model.destroy
285
+
286
+ assert model.destroyed?
287
+
288
+ model = ParanoidModel.only_deleted.find(id)
289
+ model.restore!
290
+ model.reload
291
+
292
+ assert_equal false, model.destroyed?
293
+ end
294
+
295
+ def test_restore_on_object_return_self
296
+ model = ParanoidModel.create
297
+ model.destroy
298
+
299
+ assert_equal model.class, model.restore.class
300
+ end
301
+
302
+ # Regression test for #92
303
+ def test_destroy_twice
304
+ model = ParanoidModel.new
305
+ model.save
306
+ model.destroy
307
+ model.destroy
308
+
309
+ assert_equal 1, ParanoidModel.unscoped.where(id: model.id).count
310
+ end
311
+
312
+ def test_destroy_return_value_on_success
313
+ model = ParanoidModel.create
314
+ return_value = model.destroy
315
+
316
+ assert_equal(return_value, model)
317
+ end
318
+
319
+ def test_destroy_return_value_on_failure
320
+ model = FailCallbackModel.create
321
+ return_value = model.destroy
322
+
323
+ assert_equal(return_value, false)
324
+ end
325
+
326
+ def test_restore_behavior_for_callbacks
327
+ model = CallbackModel.new
328
+ model.save
329
+ id = model.id
330
+ model.destroy
331
+
332
+ assert model.destroyed?
333
+
334
+ model = CallbackModel.only_deleted.find(id)
335
+ model.restore!
336
+ model.reload
337
+
338
+ assert model.instance_variable_get(:@restore_callback_called)
339
+ end
340
+
341
+ def test_really_destroy
342
+ model = ParanoidModel.new
343
+ model.save
344
+ model.really_destroy!
345
+ refute ParanoidModel.unscoped.exists?(model.id)
346
+ end
347
+
348
+ def test_real_destroy_dependent_destroy
349
+ parent = ParentModel.create
350
+ child = parent.very_related_models.create
351
+ parent.really_destroy!
352
+ refute RelatedModel.unscoped.exists?(child.id)
353
+ end
354
+
355
+ def test_real_destroy_dependent_destroy_after_normal_destroy
356
+ parent = ParentModel.create
357
+ child = parent.very_related_models.create
358
+ parent.destroy
359
+ parent.really_destroy!
360
+ refute RelatedModel.unscoped.exists?(child.id)
361
+ end
362
+
363
+ def test_real_destroy_dependent_destroy_after_normal_destroy_does_not_delete_other_children
364
+ parent_1 = ParentModel.create
365
+ child_1 = parent_1.very_related_models.create
366
+
367
+ parent_2 = ParentModel.create
368
+ child_2 = parent_2.very_related_models.create
369
+ parent_1.destroy
370
+ parent_1.really_destroy!
371
+ assert RelatedModel.unscoped.exists?(child_2.id)
372
+ end
373
+
374
+ if ActiveRecord::VERSION::STRING < "4.1"
375
+ def test_real_destroy
376
+ model = ParanoidModel.new
377
+ model.save
378
+ model.destroy!
379
+ refute ParanoidModel.unscoped.exists?(model.id)
380
+ end
381
+ end
382
+
383
+ def test_real_delete
384
+ model = ParanoidModel.new
385
+ model.save
386
+ model.delete!
387
+
388
+ refute ParanoidModel.unscoped.exists?(model.id)
389
+ end
390
+
391
+ def test_multiple_restore
392
+ a = ParanoidModel.new
393
+ a.save
394
+ a_id = a.id
395
+ a.destroy
396
+
397
+ b = ParanoidModel.new
398
+ b.save
399
+ b_id = b.id
400
+ b.destroy
401
+
402
+ c = ParanoidModel.new
403
+ c.save
404
+ c_id = c.id
405
+ c.destroy
406
+
407
+ ParanoidModel.restore([a_id, c_id])
408
+
409
+ a.reload
410
+ b.reload
411
+ c.reload
412
+
413
+ refute a.destroyed?
414
+ assert b.destroyed?
415
+ refute c.destroyed?
416
+ end
417
+
418
+ def test_restore_with_associations
419
+ parent = ParentModel.create
420
+ first_child = parent.very_related_models.create
421
+ second_child = parent.non_paranoid_models.create
422
+
423
+ parent.destroy
424
+ assert_equal false, parent.deleted_at.nil?
425
+ assert_equal false, first_child.reload.deleted_at.nil?
426
+ assert_equal true, second_child.destroyed?
427
+
428
+ parent.restore!
429
+ assert_equal true, parent.deleted_at.nil?
430
+ assert_equal false, first_child.reload.deleted_at.nil?
431
+ assert_equal true, second_child.destroyed?
432
+
433
+ parent.destroy
434
+ parent.restore(:recursive => true)
435
+ assert_equal true, parent.deleted_at.nil?
436
+ assert_equal true, first_child.reload.deleted_at.nil?
437
+ assert_equal true, second_child.destroyed?
438
+
439
+ parent.destroy
440
+ ParentModel.restore(parent.id, :recursive => true)
441
+ assert_equal true, parent.reload.deleted_at.nil?
442
+ assert_equal true, first_child.reload.deleted_at.nil?
443
+ assert_equal true, second_child.destroyed?
444
+ end
445
+
446
+ # regression tests for #118
447
+ def test_restore_with_has_one_association
448
+ # setup and destroy test objects
449
+ hasOne = ParanoidModelWithHasOne.create
450
+ belongsTo = ParanoidModelWithBelong.create
451
+ anthorClassName = ParanoidModelWithAnthorClassNameBelong.create
452
+ foreignKey = ParanoidModelWithForeignKeyBelong.create
453
+ hasOne.paranoid_model_with_belong = belongsTo
454
+ hasOne.class_name_belong = anthorClassName
455
+ hasOne.paranoid_model_with_foreign_key_belong = foreignKey
456
+ hasOne.save!
457
+
458
+ hasOne.destroy
459
+ assert_equal false, hasOne.deleted_at.nil?
460
+ assert_equal false, belongsTo.deleted_at.nil?
461
+
462
+ # Does it restore has_one associations?
463
+ hasOne.restore(:recursive => true)
464
+ hasOne.save!
465
+
466
+ assert_equal true, hasOne.reload.deleted_at.nil?
467
+ assert_equal true, belongsTo.reload.deleted_at.nil?, "#{belongsTo.deleted_at}"
468
+ assert ParanoidModelWithBelong.with_deleted.reload.count != 0, "There should be a record"
469
+ assert ParanoidModelWithAnthorClassNameBelong.with_deleted.reload.count != 0, "There should be an other record"
470
+ assert ParanoidModelWithForeignKeyBelong.with_deleted.reload.count != 0, "There should be a foreign_key record"
471
+ end
472
+
473
+ def test_new_restore_with_has_one_association
474
+ # setup and destroy test objects
475
+ hasOne = ParanoidModelWithHasOne.create
476
+ belongsTo = ParanoidModelWithBelong.create
477
+ anthorClassName = ParanoidModelWithAnthorClassNameBelong.create
478
+ foreignKey = ParanoidModelWithForeignKeyBelong.create
479
+ hasOne.paranoid_model_with_belong = belongsTo
480
+ hasOne.class_name_belong = anthorClassName
481
+ hasOne.paranoid_model_with_foreign_key_belong = foreignKey
482
+ hasOne.save!
483
+
484
+ hasOne.destroy
485
+ assert_equal false, hasOne.deleted_at.nil?
486
+ assert_equal false, belongsTo.deleted_at.nil?
487
+
488
+ # Does it restore has_one associations?
489
+ newHasOne = ParanoidModelWithHasOne.with_deleted.find(hasOne.id)
490
+ newHasOne.restore(:recursive => true)
491
+ newHasOne.save!
492
+
493
+ assert_equal true, hasOne.reload.deleted_at.nil?
494
+ assert_equal true, belongsTo.reload.deleted_at.nil?, "#{belongsTo.deleted_at}"
495
+ assert ParanoidModelWithBelong.with_deleted.reload.count != 0, "There should be a record"
496
+ assert ParanoidModelWithAnthorClassNameBelong.with_deleted.reload.count != 0, "There should be an other record"
497
+ assert ParanoidModelWithForeignKeyBelong.with_deleted.reload.count != 0, "There should be a foreign_key record"
498
+ end
499
+
500
+ def test_model_restore_with_has_one_association
501
+ # setup and destroy test objects
502
+ hasOne = ParanoidModelWithHasOne.create
503
+ belongsTo = ParanoidModelWithBelong.create
504
+ anthorClassName = ParanoidModelWithAnthorClassNameBelong.create
505
+ foreignKey = ParanoidModelWithForeignKeyBelong.create
506
+ hasOne.paranoid_model_with_belong = belongsTo
507
+ hasOne.class_name_belong = anthorClassName
508
+ hasOne.paranoid_model_with_foreign_key_belong = foreignKey
509
+ hasOne.save!
510
+
511
+ hasOne.destroy
512
+ assert_equal false, hasOne.deleted_at.nil?
513
+ assert_equal false, belongsTo.deleted_at.nil?
514
+
515
+ # Does it restore has_one associations?
516
+ ParanoidModelWithHasOne.restore(hasOne.id, :recursive => true)
517
+ hasOne.save!
518
+
519
+ assert_equal true, hasOne.reload.deleted_at.nil?
520
+ assert_equal true, belongsTo.reload.deleted_at.nil?, "#{belongsTo.deleted_at}"
521
+ assert ParanoidModelWithBelong.with_deleted.reload.count != 0, "There should be a record"
522
+ assert ParanoidModelWithAnthorClassNameBelong.with_deleted.reload.count != 0, "There should be an other record"
523
+ assert ParanoidModelWithForeignKeyBelong.with_deleted.reload.count != 0, "There should be a foreign_key record"
524
+ end
525
+
526
+ def test_restore_with_nil_has_one_association
527
+ # setup and destroy test object
528
+ hasOne = ParanoidModelWithHasOne.create
529
+ hasOne.destroy
530
+ assert_equal false, hasOne.reload.deleted_at.nil?
531
+
532
+ # Does it raise NoMethodException on restore of nil
533
+ hasOne.restore(:recursive => true)
534
+
535
+ assert hasOne.reload.deleted_at.nil?
536
+ end
537
+
538
+ # covers #131
539
+ def test_has_one_really_destroy_with_nil
540
+ model = ParanoidModelWithHasOne.create
541
+ model.really_destroy!
542
+
543
+ refute ParanoidModelWithBelong.unscoped.exists?(model.id)
544
+ end
545
+
546
+ def test_has_one_really_destroy_with_record
547
+ model = ParanoidModelWithHasOne.create { |record| record.build_paranoid_model_with_belong }
548
+ model.really_destroy!
549
+
550
+ refute ParanoidModelWithBelong.unscoped.exists?(model.id)
551
+ end
552
+
553
+ def test_observers_notified
554
+ a = ParanoidModelWithObservers.create
555
+ a.destroy
556
+ a.restore!
557
+
558
+ assert a.observers_notified.select {|args| args == [:before_restore, a]}
559
+ assert a.observers_notified.select {|args| args == [:after_restore, a]}
560
+ end
561
+
562
+ def test_observers_not_notified_if_not_supported
563
+ a = ParanoidModelWithObservers.create
564
+ a.destroy
565
+ a.restore!
566
+ # essentially, we're just ensuring that this doesn't crash
567
+ end
568
+
569
+ def test_i_am_the_destroyer
570
+ output = capture(:stdout) { ParanoidModel.I_AM_THE_DESTROYER! }
571
+ assert_equal %Q{
572
+ Sharon: "There should be a method called I_AM_THE_DESTROYER!"
573
+ Ryan: "What should this method do?"
574
+ Sharon: "It should fix all the spelling errors on the page!"
575
+ }, output
576
+ end
577
+
578
+ def test_destroy_fails_if_callback_raises_exception
579
+ parent = AsplodeModel.create
580
+
581
+ assert_raises(StandardError) { parent.destroy }
582
+
583
+ #transaction should be rolled back, so parent NOT deleted
584
+ refute parent.destroyed?, 'Parent record was destroyed, even though AR callback threw exception'
585
+ end
586
+
587
+ def test_destroy_fails_if_association_callback_raises_exception
588
+ parent = ParentModel.create
589
+ children = []
590
+ 3.times { children << parent.asplode_models.create }
591
+
592
+ assert_raises(StandardError) { parent.destroy }
593
+
594
+ #transaction should be rolled back, so parent and children NOT deleted
595
+ refute parent.destroyed?, 'Parent record was destroyed, even though AR callback threw exception'
596
+ refute children.any?(&:destroyed?), 'Child record was destroyed, even though AR callback threw exception'
597
+ end
598
+
599
+ def test_restore_model_with_different_connection
600
+ ActiveRecord::Base.remove_connection # Disconnect the main connection
601
+ a = WithDifferentConnection.create
602
+ a.destroy!
603
+ a.restore!
604
+ # This test passes if no exception is raised
605
+ connect! # Reconnect the main connection
606
+ end
607
+
608
+ def test_restore_clear_association_cache_if_associations_present
609
+ parent = ParentModel.create
610
+ 3.times { parent.very_related_models.create }
611
+
612
+ parent.destroy
613
+
614
+ assert_equal 0, parent.very_related_models.count
615
+ assert_equal 0, parent.very_related_models.size
616
+
617
+ parent.restore(recursive: true)
618
+
619
+ assert_equal 3, parent.very_related_models.count
620
+ assert_equal 3, parent.very_related_models.size
621
+ end
622
+
623
+ private
624
+ def get_featureful_model
625
+ FeaturefulModel.new(:name => "not empty")
626
+ end
627
+ end
628
+
629
+ # Helper classes
630
+
631
+ class ParanoidModel < ActiveRecord::Base
632
+ belongs_to :parent_model
633
+ acts_as_paranoid
634
+ end
635
+
636
+ class FailCallbackModel < ActiveRecord::Base
637
+ belongs_to :parent_model
638
+ acts_as_paranoid
639
+
640
+ before_destroy { |_| false }
641
+ end
642
+
643
+ class FeaturefulModel < ActiveRecord::Base
644
+ acts_as_paranoid
645
+ validates :name, :presence => true, :uniqueness => true
646
+ end
647
+
648
+ class PlainModel < ActiveRecord::Base
649
+ end
650
+
651
+ class CallbackModel < ActiveRecord::Base
652
+ acts_as_paranoid
653
+ before_destroy {|model| model.instance_variable_set :@destroy_callback_called, true }
654
+ before_restore {|model| model.instance_variable_set :@restore_callback_called, true }
655
+ before_update {|model| model.instance_variable_set :@update_callback_called, true }
656
+ before_save {|model| model.instance_variable_set :@save_callback_called, true}
657
+
658
+ after_destroy {|model| model.instance_variable_set :@after_destroy_callback_called, true }
659
+ after_commit {|model| model.instance_variable_set :@after_commit_callback_called, true }
660
+
661
+ validate {|model| model.instance_variable_set :@validate_called, true }
662
+
663
+ def remove_called_variables
664
+ instance_variables.each {|name| (name.to_s.end_with?('_called')) ? remove_instance_variable(name) : nil}
665
+ end
666
+ end
667
+
668
+ class ParentModel < ActiveRecord::Base
669
+ acts_as_paranoid
670
+ has_many :paranoid_models
671
+ has_many :related_models
672
+ has_many :very_related_models, :class_name => 'RelatedModel', dependent: :destroy
673
+ has_many :non_paranoid_models, dependent: :destroy
674
+ has_many :asplode_models, dependent: :destroy
675
+ end
676
+
677
+ class RelatedModel < ActiveRecord::Base
678
+ acts_as_paranoid
679
+ belongs_to :parent_model
680
+ end
681
+
682
+ class Employer < ActiveRecord::Base
683
+ acts_as_paranoid
684
+ has_many :jobs
685
+ has_many :employees, :through => :jobs
686
+ end
687
+
688
+ class Employee < ActiveRecord::Base
689
+ acts_as_paranoid
690
+ has_many :jobs
691
+ has_many :employers, :through => :jobs
692
+ end
693
+
694
+ class Job < ActiveRecord::Base
695
+ acts_as_paranoid
696
+ belongs_to :employer
697
+ belongs_to :employee
698
+ end
699
+
700
+ class CustomColumnModel < ActiveRecord::Base
701
+ acts_as_paranoid column: :destroyed_at
702
+ end
703
+
704
+ class CustomSentinelModel < ActiveRecord::Base
705
+ acts_as_paranoid sentinel_value: DateTime.new(0)
706
+ end
707
+
708
+ class NonParanoidModel < ActiveRecord::Base
709
+ end
710
+
711
+ class ParanoidModelWithObservers < ParanoidModel
712
+ def observers_notified
713
+ @observers_notified ||= []
714
+ end
715
+
716
+ def self.notify_observer(*args)
717
+ observers_notified << args
718
+ end
719
+ end
720
+
721
+ class ParanoidModelWithoutObservers < ParanoidModel
722
+ self.class.send(remove_method :notify_observers) if method_defined?(:notify_observers)
723
+ end
724
+
725
+ # refer back to regression test for #118
726
+ class ParanoidModelWithHasOne < ParanoidModel
727
+ has_one :paranoid_model_with_belong, :dependent => :destroy
728
+ has_one :class_name_belong, :dependent => :destroy, :class_name => "ParanoidModelWithAnthorClassNameBelong"
729
+ has_one :paranoid_model_with_foreign_key_belong, :dependent => :destroy, :foreign_key => "has_one_foreign_key_id"
730
+ end
731
+
732
+ class ParanoidModelWithBelong < ActiveRecord::Base
733
+ acts_as_paranoid
734
+ belongs_to :paranoid_model_with_has_one
735
+ end
736
+
737
+ class ParanoidModelWithAnthorClassNameBelong < ActiveRecord::Base
738
+ acts_as_paranoid
739
+ belongs_to :paranoid_model_with_has_one
740
+ end
741
+
742
+ class ParanoidModelWithForeignKeyBelong < ActiveRecord::Base
743
+ acts_as_paranoid
744
+ belongs_to :paranoid_model_with_has_one
745
+ end
746
+
747
+ class FlaggedModel < PlainModel
748
+ acts_as_paranoid :flag_column => :is_deleted
749
+ end
750
+
751
+ class FlaggedModelWithCustomIndex < PlainModel
752
+ acts_as_paranoid :flag_column => :is_deleted, :indexed_column => :is_deleted
753
+ end
754
+
755
+ class AsplodeModel < ActiveRecord::Base
756
+ acts_as_paranoid
757
+ before_destroy do |r|
758
+ raise StandardError, 'ASPLODE!'
759
+ end
760
+ end