test: cover test_soft_deleting_predicate_is_false_for_a_non_paranoid_...

This commit is contained in:
dualfroz committed 2026-09-12 21:32:44 +02:00
1 parent 36c3bd517c
commit af5303247c
1 file changed
+188
+188
View File
@@ -156,3 +156,191 @@ class OrmParanoiaTest < Minitest::Test
widget.really_destroy!
assert_equal false, seen
end
def test_soft_deleting_predicate_is_false_for_a_non_paranoid_model
seen = nil
plain_class = Class.new(Prism::Orm::Model) do
table_name :plain_things
before_destroy { seen = soft_deleting? }
end
plain_class.store = @store
thing = plain_class.create!(name: 'gizmo')
thing.destroy
assert_equal false, seen
end
def test_restore_undoes_a_soft_delete
widget = Widget.create!(name: 'gizmo')
widget.destroy
refute_includes Widget.all.map(&:id), widget.id
widget.restore
refute widget.destroyed?
refute widget.deleted?
assert_includes Widget.all.map(&:id), widget.id
assert_nil Widget.find(widget.id).deleted_at
end
def test_restore_on_a_record_that_was_never_deleted_is_a_no_op
widget = Widget.create!(name: 'gizmo')
widget.restore
refute widget.deleted?
end
def test_with_deleted_sees_both_live_and_soft_deleted_records
live = Widget.create!(name: 'live')
dead = Widget.create!(name: 'dead')
dead.destroy
ids = Widget.with_deleted.map(&:id)
assert_includes ids, live.id
assert_includes ids, dead.id
assert_equal [dead.id], Widget.only_deleted.map(&:id)
end
def test_really_destroy_bang_removes_the_row_for_real
widget = Widget.create!(name: 'gizmo')
widget.destroy
assert_includes Widget.only_deleted.map(&:id), widget.id
widget.really_destroy!
assert_nil @store.find('widgets', widget.id)
refute_includes Widget.with_deleted.map(&:id), widget.id
end
def test_really_destroy_bang_on_a_non_paranoid_model_behaves_like_plain_destroy
thing = PlainThing.create!(name: 'gizmo')
thing.really_destroy!
assert_raises(Prism::Orm::RecordNotFound) { PlainThing.find(thing.id) }
end
def test_dependent_destroy_cascades_a_soft_delete_to_paranoid_children
author = Author.create!(name: 'foksiu')
post = Post.create!(title: 'hello', author_id: author.id)
author.destroy
refute_nil @store.find('posts', post.id), 'child row must still physically exist'
assert_empty Post.all.to_a
assert_includes Post.only_deleted.map(&:id), post.id
end
def test_paranoid_destroy_still_respects_optimistic_locking
original = LockedWidget.create!(name: 'a')
stale_copy = LockedWidget.find(original.id)
original.update!(name: 'changed')
error = assert_raises(Prism::Orm::StaleObjectError) { stale_copy.destroy }
assert_equal :destroy, error.attempted_action
refute stale_copy.destroyed?
refute_nil LockedWidget.find(original.id), 'stale soft-delete must not have stamped the row'
end
def test_paranoid_column_can_be_customized
@store.create_table(:archivables, %w[id name archived_at])
archivable_class = Class.new(Prism::Orm::Model) do
table_name :archivables
acts_as_paranoid column: 'archived_at'
end
archivable_class.store = @store
record = archivable_class.create!(name: 'a')
record.destroy
assert_equal 'archived_at', archivable_class.paranoid_column
assert_empty archivable_class.all.to_a
refute_nil @store.find('archivables', record.id)['archived_at']
end
def test_paranoid_setting_is_inherited_by_subclasses
subclass = Class.new(Widget) { table_name :widgets }
subclass.store = @store
assert subclass.paranoid?
assert_equal 'deleted_at', subclass.paranoid_column
record = subclass.create!(name: 'a')
record.destroy
assert_empty subclass.all.to_a
end
def test_plain_restore_does_not_bring_back_dependent_destroyed_children
blog = Blog.create!(name: 'main', entries_count: 0)
entry = Entry.create!(title: 'first', blog_id: blog.id)
blog.destroy
assert_includes Entry.only_deleted.map(&:id), entry.id
blog.restore
refute blog.deleted?
assert_includes Entry.only_deleted.map(&:id), entry.id, 'a non-recursive restore must leave children trashed'
end
def test_recursive_restore_brings_back_paranoid_dependent_children
blog = Blog.create!(name: 'main', entries_count: 0)
e1 = Entry.create!(title: 'first', blog_id: blog.id)
e2 = Entry.create!(title: 'second', blog_id: blog.id)
blog.destroy
assert_empty Entry.all.to_a
blog.restore(recursive: true)
ids = Entry.all.map(&:id)
assert_includes ids, e1.id
assert_includes ids, e2.id
assert_equal 2, blog.reload.entries_count, 'counter_cache must be restored along with each child'
end
def test_recursive_restore_recurses_into_grandchildren
@store.create_table(:pages, %w[id title entry_id deleted_at])
page_class = Class.new(Prism::Orm::Model) do
table_name :pages
acts_as_paranoid
belongs_to :entry, class_name: 'Entry', foreign_key: 'entry_id'
end
page_class.store = @store
Object.const_set(:Page, page_class)
Entry.has_many :pages, class_name: 'Page', foreign_key: 'entry_id', dependent: :destroy
blog = Blog.create!(name: 'main', entries_count: 0)
entry = Entry.create!(title: 'first', blog_id: blog.id)
page = Page.create!(title: 'sub', entry_id: entry.id)
blog.destroy
assert_includes Page.only_deleted.map(&:id), page.id
blog.restore(recursive: true)
assert_includes Page.all.map(&:id), page.id
ensure
Object.send(:remove_const, :Page) if Object.const_defined?(:Page)
end
def test_restore_runs_before_and_after_restore_callbacks_in_order
calls = []
Widget.before_restore { calls << :before }
Widget.after_restore { calls << :after }
widget = Widget.create!(name: 'gizmo')
widget.destroy
widget.restore
assert_equal %i[before after], calls
end
def test_before_restore_abort_leaves_the_record_soft_deleted
Widget.before_restore { throw :abort }
widget = Widget.create!(name: 'gizmo')
widget.destroy
widget.restore
assert widget.deleted?
assert_includes Widget.only_deleted.map(&:id), widget.id
end
end