To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.
root / .svn / pristine / c7 / c76b4386c82424294b50c9641cdeb22f3fba841c.svn-base @ 1297:0a574315af3e
History | View | Annotate | Download (6.33 KB)
| 1 | 1296:038ba2d95de8 | Chris | # Redmine - project management software |
|---|---|---|---|
| 2 | # Copyright (C) 2006-2012 Jean-Philippe Lang |
||
| 3 | # |
||
| 4 | # This program is free software; you can redistribute it and/or |
||
| 5 | # modify it under the terms of the GNU General Public License |
||
| 6 | # as published by the Free Software Foundation; either version 2 |
||
| 7 | # of the License, or (at your option) any later version. |
||
| 8 | # |
||
| 9 | # This program is distributed in the hope that it will be useful, |
||
| 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
| 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
| 12 | # GNU General Public License for more details. |
||
| 13 | # |
||
| 14 | # You should have received a copy of the GNU General Public License |
||
| 15 | # along with this program; if not, write to the Free Software |
||
| 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||
| 17 | |||
| 18 | require File.expand_path('../../test_helper', __FILE__)
|
||
| 19 | |||
| 20 | class ProjectNestedSetTest < ActiveSupport::TestCase |
||
| 21 | |||
| 22 | def setup |
||
| 23 | Project.delete_all |
||
| 24 | |||
| 25 | @a = Project.create!(:name => 'A', :identifier => 'projecta') |
||
| 26 | @a1 = Project.create!(:name => 'A1', :identifier => 'projecta1') |
||
| 27 | @a1.set_parent!(@a) |
||
| 28 | @a2 = Project.create!(:name => 'A2', :identifier => 'projecta2') |
||
| 29 | @a2.set_parent!(@a) |
||
| 30 | |||
| 31 | @c = Project.create!(:name => 'C', :identifier => 'projectc') |
||
| 32 | @c1 = Project.create!(:name => 'C1', :identifier => 'projectc1') |
||
| 33 | @c1.set_parent!(@c) |
||
| 34 | |||
| 35 | @b = Project.create!(:name => 'B', :identifier => 'projectb') |
||
| 36 | @b2 = Project.create!(:name => 'B2', :identifier => 'projectb2') |
||
| 37 | @b2.set_parent!(@b) |
||
| 38 | @b1 = Project.create!(:name => 'B1', :identifier => 'projectb1') |
||
| 39 | @b1.set_parent!(@b) |
||
| 40 | @b11 = Project.create!(:name => 'B11', :identifier => 'projectb11') |
||
| 41 | @b11.set_parent!(@b1) |
||
| 42 | |||
| 43 | @a, @a1, @a2, @b, @b1, @b11, @b2, @c, @c1 = *(Project.all.sort_by(&:name)) |
||
| 44 | end |
||
| 45 | |||
| 46 | def test_valid_tree |
||
| 47 | assert_valid_nested_set |
||
| 48 | end |
||
| 49 | |||
| 50 | def test_rebuild_should_build_valid_tree |
||
| 51 | Project.update_all "lft = NULL, rgt = NULL" |
||
| 52 | |||
| 53 | Project.rebuild! |
||
| 54 | assert_valid_nested_set |
||
| 55 | end |
||
| 56 | |||
| 57 | def test_rebuild_tree_should_build_valid_tree_even_with_valid_lft_rgt_values |
||
| 58 | Project.update_all "name = 'YY'", {:id => @a.id }
|
||
| 59 | # lft and rgt values are still valid (Project.rebuild! would not update anything) |
||
| 60 | # but projects are not ordered properly (YY is in the first place) |
||
| 61 | |||
| 62 | Project.rebuild_tree! |
||
| 63 | assert_valid_nested_set |
||
| 64 | end |
||
| 65 | |||
| 66 | def test_moving_a_child_to_a_different_parent_should_keep_valid_tree |
||
| 67 | assert_no_difference 'Project.count' do |
||
| 68 | Project.find_by_name('B1').set_parent!(Project.find_by_name('A2'))
|
||
| 69 | end |
||
| 70 | assert_valid_nested_set |
||
| 71 | end |
||
| 72 | |||
| 73 | def test_renaming_a_root_to_first_position_should_update_nested_set_order |
||
| 74 | @c.name = '1' |
||
| 75 | @c.save! |
||
| 76 | assert_valid_nested_set |
||
| 77 | end |
||
| 78 | |||
| 79 | def test_renaming_a_root_to_middle_position_should_update_nested_set_order |
||
| 80 | @a.name = 'BA' |
||
| 81 | @a.save! |
||
| 82 | assert_valid_nested_set |
||
| 83 | end |
||
| 84 | |||
| 85 | def test_renaming_a_root_to_last_position_should_update_nested_set_order |
||
| 86 | @a.name = 'D' |
||
| 87 | @a.save! |
||
| 88 | assert_valid_nested_set |
||
| 89 | end |
||
| 90 | |||
| 91 | def test_renaming_a_root_to_same_position_should_update_nested_set_order |
||
| 92 | @c.name = 'D' |
||
| 93 | @c.save! |
||
| 94 | assert_valid_nested_set |
||
| 95 | end |
||
| 96 | |||
| 97 | def test_renaming_a_child_should_update_nested_set_order |
||
| 98 | @a1.name = 'A3' |
||
| 99 | @a1.save! |
||
| 100 | assert_valid_nested_set |
||
| 101 | end |
||
| 102 | |||
| 103 | def test_renaming_a_child_with_child_should_update_nested_set_order |
||
| 104 | @b1.name = 'B3' |
||
| 105 | @b1.save! |
||
| 106 | assert_valid_nested_set |
||
| 107 | end |
||
| 108 | |||
| 109 | def test_adding_a_root_to_first_position_should_update_nested_set_order |
||
| 110 | project = Project.create!(:name => '1', :identifier => 'projectba') |
||
| 111 | assert_valid_nested_set |
||
| 112 | end |
||
| 113 | |||
| 114 | def test_adding_a_root_to_middle_position_should_update_nested_set_order |
||
| 115 | project = Project.create!(:name => 'BA', :identifier => 'projectba') |
||
| 116 | assert_valid_nested_set |
||
| 117 | end |
||
| 118 | |||
| 119 | def test_adding_a_root_to_last_position_should_update_nested_set_order |
||
| 120 | project = Project.create!(:name => 'Z', :identifier => 'projectba') |
||
| 121 | assert_valid_nested_set |
||
| 122 | end |
||
| 123 | |||
| 124 | def test_destroying_a_root_with_children_should_keep_valid_tree |
||
| 125 | assert_difference 'Project.count', -4 do |
||
| 126 | Project.find_by_name('B').destroy
|
||
| 127 | end |
||
| 128 | assert_valid_nested_set |
||
| 129 | end |
||
| 130 | |||
| 131 | def test_destroying_a_child_with_children_should_keep_valid_tree |
||
| 132 | assert_difference 'Project.count', -2 do |
||
| 133 | Project.find_by_name('B1').destroy
|
||
| 134 | end |
||
| 135 | assert_valid_nested_set |
||
| 136 | end |
||
| 137 | |||
| 138 | private |
||
| 139 | |||
| 140 | def assert_nested_set_values(h) |
||
| 141 | assert Project.valid? |
||
| 142 | h.each do |project, expected| |
||
| 143 | project.reload |
||
| 144 | assert_equal expected, [project.parent_id, project.lft, project.rgt], "Unexpected nested set values for #{project.name}"
|
||
| 145 | end |
||
| 146 | end |
||
| 147 | |||
| 148 | def assert_valid_nested_set |
||
| 149 | projects = Project.all |
||
| 150 | lft_rgt = projects.map {|p| [p.lft, p.rgt]}.flatten
|
||
| 151 | assert_equal projects.size * 2, lft_rgt.uniq.size |
||
| 152 | assert_equal 1, lft_rgt.min |
||
| 153 | assert_equal projects.size * 2, lft_rgt.max |
||
| 154 | |||
| 155 | projects.each do |project| |
||
| 156 | # lft should always be < rgt |
||
| 157 | assert project.lft < project.rgt, "lft=#{project.lft} was not < rgt=#{project.rgt} for project #{project.name}"
|
||
| 158 | if project.parent_id |
||
| 159 | # child lft/rgt values must be greater/lower |
||
| 160 | assert_not_nil project.parent, "parent was nil for project #{project.name}"
|
||
| 161 | assert project.lft > project.parent.lft, "lft=#{project.lft} was not > parent.lft=#{project.parent.lft} for project #{project.name}"
|
||
| 162 | assert project.rgt < project.parent.rgt, "rgt=#{project.rgt} was not < parent.rgt=#{project.parent.rgt} for project #{project.name}"
|
||
| 163 | end |
||
| 164 | # no overlapping lft/rgt values |
||
| 165 | overlapping = projects.detect {|other|
|
||
| 166 | other != project && ( |
||
| 167 | (other.lft > project.lft && other.lft < project.rgt && other.rgt > project.rgt) || |
||
| 168 | (other.rgt > project.lft && other.rgt < project.rgt && other.lft < project.lft) |
||
| 169 | ) |
||
| 170 | } |
||
| 171 | assert_nil overlapping, (overlapping && "Project #{overlapping.name} (#{overlapping.lft}/#{overlapping.rgt}) overlapped #{project.name} (#{project.lft}/#{project.rgt})")
|
||
| 172 | end |
||
| 173 | |||
| 174 | # root projects sorted alphabetically |
||
| 175 | assert_equal Project.roots.map(&:name).sort, Project.roots.sort_by(&:lft).map(&:name), "Root projects were not properly sorted" |
||
| 176 | projects.each do |project| |
||
| 177 | if project.children.any? |
||
| 178 | # sibling projects sorted alphabetically |
||
| 179 | assert_equal project.children.map(&:name).sort, project.children.order('lft').map(&:name), "Project #{project.name}'s children were not properly sorted"
|
||
| 180 | end |
||
| 181 | end |
||
| 182 | end |
||
| 183 | end |