diff --git a/lib/ancestry/materialized_path.rb b/lib/ancestry/materialized_path.rb index 3b334aaf..fa903975 100644 --- a/lib/ancestry/materialized_path.rb +++ b/lib/ancestry/materialized_path.rb @@ -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 @@ -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 diff --git a/test/concerns/materialized_path2_test.rb b/test/concerns/materialized_path2_test.rb new file mode 100644 index 00000000..2284d237 --- /dev/null +++ b/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 diff --git a/test/concerns/materialized_path_test.rb b/test/concerns/materialized_path_test.rb new file mode 100644 index 00000000..2c705f12 --- /dev/null +++ b/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 diff --git a/test/concerns/tree_navigation_test.rb b/test/concerns/tree_navigation_test.rb index 191bd71b..28230843 100644 --- a/test/concerns/tree_navigation_test.rb +++ b/test/concerns/tree_navigation_test.rb @@ -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}, @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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) @@ -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 diff --git a/test/concerns/validations_test.rb b/test/concerns/validations_test.rb deleted file mode 100644 index 0d95b368..00000000 --- a/test/concerns/validations_test.rb +++ /dev/null @@ -1,81 +0,0 @@ -require_relative '../environment' - -class ValidationsTest < ActiveSupport::TestCase - def test_ancestry_column_validation - AncestryTestDatabase.with_model do |model| - node = model.create # assuming id == 1 - if AncestryTestDatabase.materialized_path2? - vals = ['/3/', '/10/2/', '/9/4/30/', model.ancestry_root] - else - vals = ['3', '10/2', '9/4/30', model.ancestry_root] - end - vals.each do |value| - node.send :write_attribute, model.ancestry_column, value - assert node.sane_ancestor_ids? - node.valid? - assert node.errors[model.ancestry_column].blank? - end - end - end - - def test_ancestry_column_validation_fails - AncestryTestDatabase.with_model do |model| - node = model.create - if AncestryTestDatabase.materialized_path2? - vals = ['/a/', '/a/b/', '/-34/'] - else - vals = ['a', 'a/b', '-34'] - end - vals.each do |value| - node.send :write_attribute, model.ancestry_column, value - refute node.sane_ancestor_ids? - node.valid? - refute node.errors[model.ancestry_column].blank? - end - end - end - - def test_ancestry_column_validation_string_key - AncestryTestDatabase.with_model(:id => :string, :primary_key_format => /[a-z]/) do |model| - node = model.create(:id => 'z') - if AncestryTestDatabase.materialized_path2? - vals = ['/a/', '/a/b/', '/a/b/c/', model.ancestry_root] - else - vals = ['a', 'a/b', 'a/b/c', model.ancestry_root] - end - vals.each do |value| - node.send :write_attribute, model.ancestry_column, value - node.valid? - assert node.errors[model.ancestry_column].blank? - end - end - end - - def test_ancestry_column_validation_string_key_fails - AncestryTestDatabase.with_model(:id => :string, :primary_key_format => /[a-z]/) do |model| - node = model.create(:id => 'z') - if AncestryTestDatabase.materialized_path2? - vals = ['/1/', '/1/2/', '/a-b/c/'] - else - vals = ['1', '1/2', 'a-b/c'] - end - vals.each do |value| - node.send :write_attribute, model.ancestry_column, value - node.valid? - refute node.errors[model.ancestry_column].blank? - end - end - end - - def test_ancestry_validation_exclude_self - 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 -end