Skip to content

Commit

Permalink
Merge pull request #648 from kbrock/splitup_validations
Browse files Browse the repository at this point in the history
Splitup validations
  • Loading branch information
kbrock committed Mar 25, 2023
2 parents 3cc9c2c + 5a4e0dd commit dbb09c2
Show file tree
Hide file tree
Showing 5 changed files with 267 additions and 93 deletions.
8 changes: 0 additions & 8 deletions lib/ancestry/materialized_path.rb
Expand Up @@ -128,10 +128,6 @@ def ancestor_ids_in_database
parse_ancestry_column(attribute_in_database(self.class.ancestry_column))
end

def ancestor_ids_in_database
parse_ancestry_column(attribute_in_database(self.class.ancestry_column))
end

def ancestor_ids_before_last_save
parse_ancestry_column(attribute_before_last_save(self.class.ancestry_column))
end
Expand All @@ -140,10 +136,6 @@ def parent_id_in_database
parse_ancestry_column(attribute_in_database(self.class.ancestry_column)).last
end

def parent_id_in_database
parse_ancestry_column(attribute_in_database(self.class.ancestry_column)).last
end

def parent_id_before_last_save
parse_ancestry_column(attribute_before_last_save(self.class.ancestry_column)).last
end
Expand Down
123 changes: 123 additions & 0 deletions test/concerns/materialized_path2_test.rb
@@ -0,0 +1,123 @@
require_relative '../environment'

class MaterializedPath2Test < ActiveSupport::TestCase
def test_ancestry_column_mp2
return unless AncestryTestDatabase.materialized_path2?

AncestryTestDatabase.with_model do |model|
root = model.create!
node = model.new

# new node
assert_ancestry node, "/", db: nil
assert_raises(Ancestry::AncestryException) { node.child_ancestry }

# saved
node.save!
assert_ancestry node, "/", child: "/#{node.id}/"

# changed
node.ancestor_ids = [root.id]
assert_ancestry node, "/#{root.id}/", db: "/", child: "/#{node.id}/"

# changed saved
node.save!
assert_ancestry node, "/#{root.id}/", child: "/#{root.id}/#{node.id}/"

# reloaded
node.reload
assert_ancestry node, "/#{root.id}/", child: "/#{root.id}/#{node.id}/"

# fresh node
node = model.find(node.id)
assert_ancestry node, "/#{root.id}/", child: "/#{root.id}/#{node.id}/"
end
end

def test_ancestry_column_validation
return unless AncestryTestDatabase.materialized_path2?

AncestryTestDatabase.with_model do |model|
node = model.create # assuming id == 1
['/3/', '/10/2/', '/9/4/30/', model.ancestry_root].each do |value|
node.send :write_attribute, model.ancestry_column, value
assert node.sane_ancestor_ids?
assert node.valid?
end
end
end

def test_ancestry_column_validation_fails
return unless AncestryTestDatabase.materialized_path2?

AncestryTestDatabase.with_model do |model|
node = model.create
['/a/', '/a/b/', '/-34/'].each do |value|
node.send :write_attribute, model.ancestry_column, value
refute node.sane_ancestor_ids?
refute node.valid?
end
end
end

def test_ancestry_column_validation_string_key
return unless AncestryTestDatabase.materialized_path2?

AncestryTestDatabase.with_model(:id => :string, :primary_key_format => /[a-z]/) do |model|
node = model.create(:id => 'z')
['/a/', '/a/b/', '/a/b/c/', model.ancestry_root].each do |value|
node.send :write_attribute, model.ancestry_column, value
assert node.valid?
end
end
end

def test_ancestry_column_validation_string_key_fails
return unless AncestryTestDatabase.materialized_path2?

AncestryTestDatabase.with_model(:id => :string, :primary_key_format => /[a-z]/) do |model|
node = model.create(:id => 'z')
['/1/', '/1/2/', '/a-b/c/'].each do |value|
node.send :write_attribute, model.ancestry_column, value
refute node.valid?
end
end
end

def test_ancestry_validation_exclude_self
return unless AncestryTestDatabase.materialized_path2?

AncestryTestDatabase.with_model do |model|
parent = model.create!
child = parent.children.create!
assert_raise ActiveRecord::RecordInvalid do
parent.parent = child
refute parent.sane_ancestor_ids?
parent.save!
end
end
end

private

def assert_ancestry(node, value, child: :skip, db: :value)
if value.nil?
assert_nil node.ancestry
else
assert_equal value, node.ancestry
end

db = value if db == :value
if db.nil?
assert_nil node.ancestry_in_database
else
assert_equal db, node.ancestry_in_database
end

if child.nil?
assert_nil node.child_ancestry
elsif child != :skip
assert_equal child, node.child_ancestry
end
end
end
125 changes: 125 additions & 0 deletions test/concerns/materialized_path_test.rb
@@ -0,0 +1,125 @@
require_relative '../environment'

class MaterializedPathTest < ActiveSupport::TestCase
def test_ancestry_column_values
return if AncestryTestDatabase.materialized_path2?

AncestryTestDatabase.with_model do |model|
root = model.create!
node = model.new

# new node
assert_ancestry node, nil
assert_raises(Ancestry::AncestryException) { node.child_ancestry }

# saved
node.save!
assert_ancestry node, nil, child: "#{node.id}"

# changed
node.ancestor_ids = [root.id]
assert_ancestry node, "#{root.id}", db: nil, child: "#{node.id}"

# changed saved
node.save!
assert_ancestry node, "#{root.id}", child: "#{root.id}/#{node.id}"

# reloaded
node.reload
assert_ancestry node, "#{root.id}", child: "#{root.id}/#{node.id}"

# fresh node
node = model.find(node.id)
assert_ancestry node, "#{root.id}", child: "#{root.id}/#{node.id}"
end
end

def test_ancestry_column_validation
return if AncestryTestDatabase.materialized_path2?

AncestryTestDatabase.with_model do |model|
node = model.create # assuming id == 1
['3', '10/2', '9/4/30', model.ancestry_root].each do |value|
node.send :write_attribute, model.ancestry_column, value
assert node.sane_ancestor_ids?
assert node.valid?
end
end
end

def test_ancestry_column_validation_fails
return if AncestryTestDatabase.materialized_path2?

AncestryTestDatabase.with_model do |model|
node = model.create
['a', 'a/b', '-34'].each do |value|
node.send :write_attribute, model.ancestry_column, value
refute node.sane_ancestor_ids?
refute node.valid?
end
end
end

def test_ancestry_column_validation_string_key
return if AncestryTestDatabase.materialized_path2?

AncestryTestDatabase.with_model(:id => :string, :primary_key_format => /[a-z]/) do |model|
node = model.create(:id => 'z')
['a', 'a/b', 'a/b/c', model.ancestry_root].each do |value|
node.send :write_attribute, model.ancestry_column, value
assert node.sane_ancestor_ids?
assert node.valid?
end
end
end

def test_ancestry_column_validation_string_key_fails
return if AncestryTestDatabase.materialized_path2?

AncestryTestDatabase.with_model(:id => :string, :primary_key_format => /[a-z]/) do |model|
node = model.create(:id => 'z')
['1', '1/2', 'a-b/c'].each do |value|
node.send :write_attribute, model.ancestry_column, value
refute node.sane_ancestor_ids?
refute node.valid?
end
end
end

def test_ancestry_validation_exclude_self
return if AncestryTestDatabase.materialized_path2?

AncestryTestDatabase.with_model do |model|
parent = model.create!
child = parent.children.create!
assert_raise ActiveRecord::RecordInvalid do
parent.parent = child
refute parent.sane_ancestor_ids?
parent.save!
end
end
end

private

def assert_ancestry(node, value, child: :skip, db: :value)
if value.nil?
assert_nil node.ancestry
else
assert_equal value, node.ancestry
end

db = value if db == :value
if db.nil?
assert_nil node.ancestry_in_database
else
assert_equal db, node.ancestry_in_database
end

if child.nil?
assert_nil node.child_ancestry
elsif child != :skip
assert_equal child, node.child_ancestry
end
end
end
23 changes: 19 additions & 4 deletions test/concerns/tree_navigation_test.rb
Expand Up @@ -6,9 +6,9 @@ class TreeNavigationTest < ActiveSupport::TestCase
# down: |children|descendants|indirects|
# across: |siblings|subtree |path |
ATTRIBUTE_MATRIX = {
root: {attribute_id: :root_id, exists: :root?},
parent: {attribute_id: :parent_id, exists: :parent?, db: true},
ancestors: {attribute_ids: :ancestor_ids, exists: :ancestors?, db: true},
root: {attribute_id: :root_id},
parent: {attribute_id: :parent_id, exists: :has_parent?, db: true},
ancestors: {attribute_ids: :ancestor_ids, exists: :ancestors?, db: true},
children: {attribute_ids: :child_ids, exists: :children?},
descendants: {attribute_ids: :descendant_ids},
indirects: {attribute_ids: :indirect_ids},
Expand Down Expand Up @@ -40,6 +40,7 @@ def test_node_getters
assert_attributes node1, :subtree, [node1, node11, node111, node12]
assert_attributes node1, :path, [node1]
assert_equal(0, node1.depth)
assert node1.root?

# root: node11
assert_attribute node11, :parent, node1
Expand All @@ -52,6 +53,7 @@ def test_node_getters
assert_attributes node11, :subtree, [node11, node111]
assert_attributes node11, :path, [node1, node11]
assert_equal(1, node11.depth)
refute node11.root?

# root: node111
assert_attribute node111, :parent, node11
Expand All @@ -64,6 +66,7 @@ def test_node_getters
assert_attributes node111, :subtree, [node111]
assert_attributes node111, :path, [node1, node11, node111]
assert_equal(2, node111.depth)
refute node111.root?

# root: node12
assert_attribute node12, :parent, node1
Expand All @@ -76,6 +79,7 @@ def test_node_getters
assert_attributes node12, :subtree, [node12]
assert_attributes node12, :path, [node1, node12]
assert_equal(1, node12.depth)
refute node12.root?

# root: node2
assert_attribute node2, :parent, nil
Expand All @@ -88,6 +92,7 @@ def test_node_getters
assert_attributes node2, :subtree, [node2, node21]
assert_attributes node2, :path, [node2]
assert_equal(0, node2.depth)
assert node2.root?

# root: node21
assert_attribute node21, :parent, node2
Expand All @@ -100,6 +105,7 @@ def test_node_getters
assert_attributes node21, :subtree, [node21]
assert_attributes node21, :path, [node2, node21]
assert_equal(1, node21.depth)
refute node21.root?
end
end

Expand Down Expand Up @@ -262,7 +268,7 @@ def update_descendants_with_new_ancestry

private

def assert_attribute(node, attribute_name, value, db: :value)
def assert_attribute(node, attribute_name, value, db: :value, exists: :value)
attribute_id = ATTRIBUTE_MATRIX[attribute_name][:attribute_id]
if value.nil?
assert_nil node.send(attribute_name)
Expand All @@ -281,6 +287,15 @@ def assert_attribute(node, attribute_name, value, db: :value)
assert_equal db.id, node.send(attribute_db_name)
end
end

exists_name = ATTRIBUTE_MATRIX[attribute_name][:exists] or return

exists = value.present? if exists == :value
if exists
assert node.send(exists_name)
else
refute node.send(exists_name)
end
end

# this is a short form for assert_eaual
Expand Down

0 comments on commit dbb09c2

Please sign in to comment.