test: add orm store, model, and relation tests
This commit is contained in:
1 parent
d321e2fd1e
commit
703f6cd845
3 files changed
+279
No files matched your search
@@ -0,0 +1,107 @@
|
|||||||
|
require 'minitest/autorun'
|
||||||
|
require 'prism'
|
||||||
|
require 'tmpdir'
|
||||||
|
|
||||||
|
class OrmModelTest < Minitest::Test
|
||||||
|
def setup
|
||||||
|
@dir = Dir.mktmpdir('prism-model-store')
|
||||||
|
@store = Prism::Orm::Store.new(File.join(@dir, 'test.pstore'))
|
||||||
|
@store.create_table(:widgets, %w[id name price created_at updated_at])
|
||||||
|
define_widget_class
|
||||||
|
end
|
||||||
|
|
||||||
|
def teardown
|
||||||
|
FileUtils.remove_entry(@dir)
|
||||||
|
Object.send(:remove_const, :Widget) if Object.const_defined?(:Widget)
|
||||||
|
end
|
||||||
|
|
||||||
|
def define_widget_class
|
||||||
|
store = @store
|
||||||
|
widget_class = Class.new(Prism::Orm::Model) do
|
||||||
|
table_name :widgets
|
||||||
|
self.store = store
|
||||||
|
end
|
||||||
|
Object.const_set(:Widget, widget_class)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_create_persists_and_returns_record
|
||||||
|
widget = Widget.create(name: 'gizmo', price: 10)
|
||||||
|
assert widget.persisted?
|
||||||
|
refute_nil widget.id
|
||||||
|
assert_equal 'gizmo', Widget.find(widget.id).name
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_dynamic_attribute_accessors
|
||||||
|
widget = Widget.new(name: 'gadget')
|
||||||
|
assert_equal 'gadget', widget.name
|
||||||
|
widget.name = 'renamed'
|
||||||
|
assert_equal 'renamed', widget.name
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_find_raises_for_missing_record
|
||||||
|
assert_raises(Prism::Orm::RecordNotFound) { Widget.find(9999) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_update_persists_new_values
|
||||||
|
widget = Widget.create(name: 'gizmo', price: 10)
|
||||||
|
widget.update(price: 25)
|
||||||
|
assert_equal 25, Widget.find(widget.id).price
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_destroy_removes_record
|
||||||
|
widget = Widget.create(name: 'gizmo')
|
||||||
|
id = widget.id
|
||||||
|
widget.destroy
|
||||||
|
assert widget.destroyed?
|
||||||
|
assert_raises(Prism::Orm::RecordNotFound) { Widget.find(id) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_reload_refreshes_attributes
|
||||||
|
widget = Widget.create(name: 'gizmo', price: 10)
|
||||||
|
Widget.find(widget.id).update(price: 99)
|
||||||
|
widget.reload
|
||||||
|
assert_equal 99, widget.price
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_timestamps_are_touched_on_save
|
||||||
|
widget = Widget.create(name: 'gizmo')
|
||||||
|
refute_nil widget.created_at
|
||||||
|
refute_nil widget.updated_at
|
||||||
|
created_at = widget.created_at
|
||||||
|
widget.update(price: 5)
|
||||||
|
assert_equal created_at, widget.created_at
|
||||||
|
refute_nil widget.updated_at
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_equality_by_class_and_id
|
||||||
|
widget = Widget.create(name: 'gizmo')
|
||||||
|
same = Widget.find(widget.id)
|
||||||
|
assert_equal widget, same
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_save_fails_and_returns_false_when_invalid
|
||||||
|
Widget.validates(:name, presence: true)
|
||||||
|
widget = Widget.new(name: '')
|
||||||
|
refute widget.save
|
||||||
|
assert_includes widget.errors[:name], 'must be present'
|
||||||
|
ensure
|
||||||
|
Widget.validators.clear
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_save_bang_raises_on_invalid_record
|
||||||
|
Widget.validates(:name, presence: true)
|
||||||
|
widget = Widget.new(name: '')
|
||||||
|
assert_raises(Prism::Orm::RecordInvalid) { widget.save! }
|
||||||
|
ensure
|
||||||
|
Widget.validators.clear
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_reset_schema_picks_up_columns_added_after_the_model_was_first_used
|
||||||
|
Widget.new # forces load_schema! against the original column set
|
||||||
|
@store.add_column(:widgets, :sku)
|
||||||
|
Widget.reset_schema!
|
||||||
|
|
||||||
|
widget = Widget.create(name: 'gizmo', sku: 'SKU-1')
|
||||||
|
assert_equal 'SKU-1', widget.sku
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
require 'minitest/autorun'
|
||||||
|
require 'prism'
|
||||||
|
require 'tmpdir'
|
||||||
|
|
||||||
|
class OrmRelationTest < Minitest::Test
|
||||||
|
def setup
|
||||||
|
@dir = Dir.mktmpdir('prism-relation-store')
|
||||||
|
@store = Prism::Orm::Store.new(File.join(@dir, 'test.pstore'))
|
||||||
|
@store.create_table(:items, %w[id name category])
|
||||||
|
item_class = Class.new(Prism::Orm::Model) do
|
||||||
|
table_name :items
|
||||||
|
end
|
||||||
|
item_class.store = @store
|
||||||
|
Object.const_set(:Item, item_class)
|
||||||
|
end
|
||||||
|
|
||||||
|
def teardown
|
||||||
|
FileUtils.remove_entry(@dir)
|
||||||
|
Object.send(:remove_const, :Item) if Object.const_defined?(:Item)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_offset_skips_leading_rows
|
||||||
|
%w[a b c d].each { |name| Item.create!(name: name) }
|
||||||
|
names = Item.order(:name).offset(2).map(&:name)
|
||||||
|
assert_equal %w[c d], names
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_offset_combined_with_limit_paginates
|
||||||
|
%w[a b c d e].each { |name| Item.create!(name: name) }
|
||||||
|
page_two = Item.order(:name).offset(2).limit(2).map(&:name)
|
||||||
|
assert_equal %w[c d], page_two
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_chained_where_calls_combine_with_and_semantics
|
||||||
|
Item.create!(name: 'match', category: 'tools')
|
||||||
|
Item.create!(name: 'match', category: 'other')
|
||||||
|
Item.create!(name: 'nope', category: 'tools')
|
||||||
|
|
||||||
|
result = Item.where(name: 'match').where(category: 'tools').to_a
|
||||||
|
assert_equal 1, result.size
|
||||||
|
assert_equal 'match', result.first.name
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_relation_is_enumerable
|
||||||
|
Item.create!(name: 'b')
|
||||||
|
Item.create!(name: 'a')
|
||||||
|
assert_equal %w[a b], Item.order(:name).sort_by(&:name).map(&:name)
|
||||||
|
assert_equal 2, Item.all.count
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_exists_predicate
|
||||||
|
refute Item.where(name: 'ghost').exists?
|
||||||
|
Item.create!(name: 'ghost')
|
||||||
|
assert Item.where(name: 'ghost').exists?
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
require 'minitest/autorun'
|
||||||
|
require 'prism'
|
||||||
|
require 'tmpdir'
|
||||||
|
|
||||||
|
class OrmStoreTest < Minitest::Test
|
||||||
|
def setup
|
||||||
|
@dir = Dir.mktmpdir('prism-store')
|
||||||
|
@path = File.join(@dir, 'test.pstore')
|
||||||
|
@store = Prism::Orm::Store.new(@path)
|
||||||
|
end
|
||||||
|
|
||||||
|
def teardown
|
||||||
|
FileUtils.remove_entry(@dir)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_create_table_and_insert
|
||||||
|
@store.create_table(:users, %w[id name])
|
||||||
|
id = @store.insert(:users, name: 'foksiu')
|
||||||
|
assert_equal 1, id
|
||||||
|
assert_equal({ 'id' => 1, 'name' => 'foksiu' }, @store.find(:users, 1))
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_create_table_twice_raises
|
||||||
|
@store.create_table(:users, %w[id name])
|
||||||
|
assert_raises(Prism::Orm::Store::TableExists) { @store.create_table(:users, %w[id name]) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_insert_assigns_incrementing_ids
|
||||||
|
@store.create_table(:users, %w[id name])
|
||||||
|
first = @store.insert(:users, name: 'a')
|
||||||
|
second = @store.insert(:users, name: 'b')
|
||||||
|
assert_equal 1, first
|
||||||
|
assert_equal 2, second
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_update_merges_attributes
|
||||||
|
@store.create_table(:users, %w[id name role])
|
||||||
|
id = @store.insert(:users, name: 'foksiu', role: 'admin')
|
||||||
|
@store.update(:users, id, role: 'owner')
|
||||||
|
row = @store.find(:users, id)
|
||||||
|
assert_equal 'foksiu', row['name']
|
||||||
|
assert_equal 'owner', row['role']
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_update_missing_record_raises
|
||||||
|
@store.create_table(:users, %w[id name])
|
||||||
|
assert_raises(Prism::Orm::Store::RecordNotFound) { @store.update(:users, 999, name: 'nope') }
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_delete_removes_row
|
||||||
|
@store.create_table(:users, %w[id name])
|
||||||
|
id = @store.insert(:users, name: 'foksiu')
|
||||||
|
@store.delete(:users, id)
|
||||||
|
assert_nil @store.find(:users, id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_all_returns_every_row
|
||||||
|
@store.create_table(:users, %w[id name])
|
||||||
|
@store.insert(:users, name: 'a')
|
||||||
|
@store.insert(:users, name: 'b')
|
||||||
|
assert_equal ['a', 'b'], @store.all(:users).map { |row| row['name'] }
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_count
|
||||||
|
@store.create_table(:users, %w[id name])
|
||||||
|
@store.insert(:users, name: 'a')
|
||||||
|
@store.insert(:users, name: 'b')
|
||||||
|
assert_equal 2, @store.count(:users)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_unknown_table_raises
|
||||||
|
assert_raises(Prism::Orm::Store::UnknownTable) { @store.find(:ghosts, 1) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_add_column_defaults_existing_rows
|
||||||
|
@store.create_table(:users, %w[id name])
|
||||||
|
id = @store.insert(:users, name: 'foksiu')
|
||||||
|
@store.add_column(:users, :active, default: true)
|
||||||
|
assert_equal true, @store.find(:users, id)['active']
|
||||||
|
assert_includes @store.columns(:users), 'active'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_remove_column_strips_existing_rows
|
||||||
|
@store.create_table(:users, %w[id name role])
|
||||||
|
id = @store.insert(:users, name: 'foksiu', role: 'admin')
|
||||||
|
@store.remove_column(:users, :role)
|
||||||
|
refute @store.find(:users, id).key?('role')
|
||||||
|
refute_includes @store.columns(:users), 'role'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_drop_table
|
||||||
|
@store.create_table(:users, %w[id name])
|
||||||
|
@store.drop_table(:users)
|
||||||
|
refute @store.table_exists?(:users)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_migration_bookkeeping
|
||||||
|
assert_empty @store.applied_migrations
|
||||||
|
@store.record_migration('20260101000000')
|
||||||
|
assert_equal ['20260101000000'], @store.applied_migrations
|
||||||
|
@store.record_migration('20260101000000')
|
||||||
|
assert_equal ['20260101000000'], @store.applied_migrations, 'recording twice must not duplicate'
|
||||||
|
@store.forget_migration('20260101000000')
|
||||||
|
assert_empty @store.applied_migrations
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_data_survives_reopening_the_store
|
||||||
|
@store.create_table(:users, %w[id name])
|
||||||
|
@store.insert(:users, name: 'persisted-foksiu')
|
||||||
|
|
||||||
|
reopened = Prism::Orm::Store.new(@path)
|
||||||
|
row = reopened.find(:users, 1)
|
||||||
|
refute_nil row
|
||||||
|
assert_equal 'persisted-foksiu', row['name']
|
||||||
|
end
|
||||||
|
end
|
||||||
Reference in new issue
Block a user