To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

Statistics Download as Zip
| Branch: | Tag: | Revision:

root / .svn / pristine / 8b / 8b34b320f3a3448ad5019fb625383697dc8a3c95.svn-base @ 1297:0a574315af3e

History | View | Annotate | Download (15.5 KB)

1
# Redmine - project management software
2
# Copyright (C) 2006-2011  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 IssueNestedSetTest < ActiveSupport::TestCase
21
  fixtures :projects, :users, :members, :member_roles, :roles,
22
           :trackers, :projects_trackers,
23
           :versions,
24
           :issue_statuses, :issue_categories, :issue_relations, :workflows,
25
           :enumerations,
26
           :issues,
27
           :custom_fields, :custom_fields_projects, :custom_fields_trackers, :custom_values,
28
           :time_entries
29

    
30
  self.use_transactional_fixtures = false
31

    
32
  def test_create_root_issue
33
    issue1 = create_issue!
34
    issue2 = create_issue!
35
    issue1.reload
36
    issue2.reload
37

    
38
    assert_equal [issue1.id, nil, 1, 2], [issue1.root_id, issue1.parent_id, issue1.lft, issue1.rgt]
39
    assert_equal [issue2.id, nil, 1, 2], [issue2.root_id, issue2.parent_id, issue2.lft, issue2.rgt]
40
  end
41

    
42
  def test_create_child_issue
43
    parent = create_issue!
44
    child =  create_issue!(:parent_issue_id => parent.id)
45
    parent.reload
46
    child.reload
47

    
48
    assert_equal [parent.id, nil, 1, 4], [parent.root_id, parent.parent_id, parent.lft, parent.rgt]
49
    assert_equal [parent.id, parent.id, 2, 3], [child.root_id, child.parent_id, child.lft, child.rgt]
50
  end
51

    
52
  def test_creating_a_child_in_different_project_should_not_validate
53
    issue = create_issue!
54
    child = Issue.new(:project_id => 2, :tracker_id => 1, :author_id => 1,
55
                      :subject => 'child', :parent_issue_id => issue.id)
56
    assert !child.save
57
    assert_not_nil child.errors[:parent_issue_id]
58
  end
59

    
60
  def test_move_a_root_to_child
61
    parent1 = create_issue!
62
    parent2 = create_issue!
63
    child = create_issue!(:parent_issue_id => parent1.id)
64

    
65
    parent2.parent_issue_id = parent1.id
66
    parent2.save!
67
    child.reload
68
    parent1.reload
69
    parent2.reload
70

    
71
    assert_equal [parent1.id, 1, 6], [parent1.root_id, parent1.lft, parent1.rgt]
72
    assert_equal [parent1.id, 4, 5], [parent2.root_id, parent2.lft, parent2.rgt]
73
    assert_equal [parent1.id, 2, 3], [child.root_id, child.lft, child.rgt]
74
  end
75

    
76
  def test_move_a_child_to_root
77
    parent1 = create_issue!
78
    parent2 = create_issue!
79
    child =   create_issue!(:parent_issue_id => parent1.id)
80

    
81
    child.parent_issue_id = nil
82
    child.save!
83
    child.reload
84
    parent1.reload
85
    parent2.reload
86

    
87
    assert_equal [parent1.id, 1, 2], [parent1.root_id, parent1.lft, parent1.rgt]
88
    assert_equal [parent2.id, 1, 2], [parent2.root_id, parent2.lft, parent2.rgt]
89
    assert_equal [child.id, 1, 2], [child.root_id, child.lft, child.rgt]
90
  end
91

    
92
  def test_move_a_child_to_another_issue
93
    parent1 = create_issue!
94
    parent2 = create_issue!
95
    child =   create_issue!(:parent_issue_id => parent1.id)
96

    
97
    child.parent_issue_id = parent2.id
98
    child.save!
99
    child.reload
100
    parent1.reload
101
    parent2.reload
102

    
103
    assert_equal [parent1.id, 1, 2], [parent1.root_id, parent1.lft, parent1.rgt]
104
    assert_equal [parent2.id, 1, 4], [parent2.root_id, parent2.lft, parent2.rgt]
105
    assert_equal [parent2.id, 2, 3], [child.root_id, child.lft, child.rgt]
106
  end
107

    
108
  def test_move_a_child_with_descendants_to_another_issue
109
    parent1 = create_issue!
110
    parent2 = create_issue!
111
    child =   create_issue!(:parent_issue_id => parent1.id)
112
    grandchild = create_issue!(:parent_issue_id => child.id)
113

    
114
    parent1.reload
115
    parent2.reload
116
    child.reload
117
    grandchild.reload
118

    
119
    assert_equal [parent1.id, 1, 6], [parent1.root_id, parent1.lft, parent1.rgt]
120
    assert_equal [parent2.id, 1, 2], [parent2.root_id, parent2.lft, parent2.rgt]
121
    assert_equal [parent1.id, 2, 5], [child.root_id, child.lft, child.rgt]
122
    assert_equal [parent1.id, 3, 4], [grandchild.root_id, grandchild.lft, grandchild.rgt]
123

    
124
    child.reload.parent_issue_id = parent2.id
125
    child.save!
126
    child.reload
127
    grandchild.reload
128
    parent1.reload
129
    parent2.reload
130

    
131
    assert_equal [parent1.id, 1, 2], [parent1.root_id, parent1.lft, parent1.rgt]
132
    assert_equal [parent2.id, 1, 6], [parent2.root_id, parent2.lft, parent2.rgt]
133
    assert_equal [parent2.id, 2, 5], [child.root_id, child.lft, child.rgt]
134
    assert_equal [parent2.id, 3, 4], [grandchild.root_id, grandchild.lft, grandchild.rgt]
135
  end
136

    
137
  def test_move_a_child_with_descendants_to_another_project
138
    parent1 = create_issue!
139
    child =   create_issue!(:parent_issue_id => parent1.id)
140
    grandchild = create_issue!(:parent_issue_id => child.id)
141

    
142
    assert child.reload.move_to_project(Project.find(2))
143
    child.reload
144
    grandchild.reload
145
    parent1.reload
146

    
147
    assert_equal [1, parent1.id, 1, 2], [parent1.project_id, parent1.root_id, parent1.lft, parent1.rgt]
148
    assert_equal [2, child.id, 1, 4], [child.project_id, child.root_id, child.lft, child.rgt]
149
    assert_equal [2, child.id, 2, 3], [grandchild.project_id, grandchild.root_id, grandchild.lft, grandchild.rgt]
150
  end
151

    
152
  def test_invalid_move_to_another_project
153
    parent1 = create_issue!
154
    child =   create_issue!(:parent_issue_id => parent1.id)
155
    grandchild = create_issue!(:parent_issue_id => child.id, :tracker_id => 2)
156
    Project.find(2).tracker_ids = [1]
157

    
158
    parent1.reload
159
    assert_equal [1, parent1.id, 1, 6], [parent1.project_id, parent1.root_id, parent1.lft, parent1.rgt]
160

    
161
    # child can not be moved to Project 2 because its child is on a disabled tracker
162
    assert_equal false, Issue.find(child.id).move_to_project(Project.find(2))
163
    child.reload
164
    grandchild.reload
165
    parent1.reload
166

    
167
    # no change
168
    assert_equal [1, parent1.id, 1, 6], [parent1.project_id, parent1.root_id, parent1.lft, parent1.rgt]
169
    assert_equal [1, parent1.id, 2, 5], [child.project_id, child.root_id, child.lft, child.rgt]
170
    assert_equal [1, parent1.id, 3, 4], [grandchild.project_id, grandchild.root_id, grandchild.lft, grandchild.rgt]
171
  end
172

    
173
  def test_moving_an_issue_to_a_descendant_should_not_validate
174
    parent1 = create_issue!
175
    parent2 = create_issue!
176
    child =   create_issue!(:parent_issue_id => parent1.id)
177
    grandchild = create_issue!(:parent_issue_id => child.id)
178

    
179
    child.reload
180
    child.parent_issue_id = grandchild.id
181
    assert !child.save
182
    assert_not_nil child.errors[:parent_issue_id]
183
  end
184

    
185
  def test_moving_an_issue_should_keep_valid_relations_only
186
    issue1 = create_issue!
187
    issue2 = create_issue!
188
    issue3 = create_issue!(:parent_issue_id => issue2.id)
189
    issue4 = create_issue!
190
    r1 = IssueRelation.create!(:issue_from => issue1, :issue_to => issue2, :relation_type => IssueRelation::TYPE_PRECEDES)
191
    r2 = IssueRelation.create!(:issue_from => issue1, :issue_to => issue3, :relation_type => IssueRelation::TYPE_PRECEDES)
192
    r3 = IssueRelation.create!(:issue_from => issue2, :issue_to => issue4, :relation_type => IssueRelation::TYPE_PRECEDES)
193
    issue2.reload
194
    issue2.parent_issue_id = issue1.id
195
    issue2.save!
196
    assert !IssueRelation.exists?(r1.id)
197
    assert !IssueRelation.exists?(r2.id)
198
    assert IssueRelation.exists?(r3.id)
199
  end
200

    
201
  def test_destroy_should_destroy_children
202
    issue1 = create_issue!
203
    issue2 = create_issue!
204
    issue3 = create_issue!(:parent_issue_id => issue2.id)
205
    issue4 = create_issue!(:parent_issue_id => issue1.id)
206

    
207
    issue3.init_journal(User.find(2))
208
    issue3.subject = 'child with journal'
209
    issue3.save!
210

    
211
    assert_difference 'Issue.count', -2 do
212
      assert_difference 'Journal.count', -1 do
213
        assert_difference 'JournalDetail.count', -1 do
214
          Issue.find(issue2.id).destroy
215
        end
216
      end
217
    end
218

    
219
    issue1.reload
220
    issue4.reload
221
    assert !Issue.exists?(issue2.id)
222
    assert !Issue.exists?(issue3.id)
223
    assert_equal [issue1.id, 1, 4], [issue1.root_id, issue1.lft, issue1.rgt]
224
    assert_equal [issue1.id, 2, 3], [issue4.root_id, issue4.lft, issue4.rgt]
225
  end
226
  
227
  def test_destroy_child_should_update_parent
228
    issue = create_issue!
229
    child1 = create_issue!(:parent_issue_id => issue.id)
230
    child2 = create_issue!(:parent_issue_id => issue.id)
231
    
232
    issue.reload
233
    assert_equal [issue.id, 1, 6], [issue.root_id, issue.lft, issue.rgt]
234
    
235
    child2.reload.destroy
236
    
237
    issue.reload
238
    assert_equal [issue.id, 1, 4], [issue.root_id, issue.lft, issue.rgt]
239
  end
240

    
241
  def test_destroy_parent_issue_updated_during_children_destroy
242
    parent = create_issue!
243
    create_issue!(:start_date => Date.today, :parent_issue_id => parent.id)
244
    create_issue!(:start_date => 2.days.from_now, :parent_issue_id => parent.id)
245

    
246
    assert_difference 'Issue.count', -3 do
247
      Issue.find(parent.id).destroy
248
    end
249
  end
250

    
251
  def test_destroy_child_issue_with_children
252
    root = Issue.create!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'root')
253
    child = Issue.create!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'child', :parent_issue_id => root.id)
254
    leaf = Issue.create!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'leaf', :parent_issue_id => child.id)
255
    leaf.init_journal(User.find(2))
256
    leaf.subject = 'leaf with journal'
257
    leaf.save!
258

    
259
    assert_difference 'Issue.count', -2 do
260
      assert_difference 'Journal.count', -1 do
261
        assert_difference 'JournalDetail.count', -1 do
262
          Issue.find(child.id).destroy
263
        end
264
      end
265
    end
266

    
267
    root = Issue.find(root.id)
268
    assert root.leaf?, "Root issue is not a leaf (lft: #{root.lft}, rgt: #{root.rgt})"
269
  end
270

    
271
  def test_destroy_issue_with_grand_child
272
    parent = create_issue!
273
    issue = create_issue!(:parent_issue_id => parent.id)
274
    child = create_issue!(:parent_issue_id => issue.id)
275
    grandchild1 = create_issue!(:parent_issue_id => child.id)
276
    grandchild2 = create_issue!(:parent_issue_id => child.id)
277

    
278
    assert_difference 'Issue.count', -4 do
279
      Issue.find(issue.id).destroy
280
      parent.reload
281
      assert_equal [1, 2], [parent.lft, parent.rgt]
282
    end
283
  end
284

    
285
  def test_parent_priority_should_be_the_highest_child_priority
286
    parent = create_issue!(:priority => IssuePriority.find_by_name('Normal'))
287
    # Create children
288
    child1 = create_issue!(:priority => IssuePriority.find_by_name('High'), :parent_issue_id => parent.id)
289
    assert_equal 'High', parent.reload.priority.name
290
    child2 = create_issue!(:priority => IssuePriority.find_by_name('Immediate'), :parent_issue_id => child1.id)
291
    assert_equal 'Immediate', child1.reload.priority.name
292
    assert_equal 'Immediate', parent.reload.priority.name
293
    child3 = create_issue!(:priority => IssuePriority.find_by_name('Low'), :parent_issue_id => parent.id)
294
    assert_equal 'Immediate', parent.reload.priority.name
295
    # Destroy a child
296
    child1.destroy
297
    assert_equal 'Low', parent.reload.priority.name
298
    # Update a child
299
    child3.reload.priority = IssuePriority.find_by_name('Normal')
300
    child3.save!
301
    assert_equal 'Normal', parent.reload.priority.name
302
  end
303

    
304
  def test_parent_dates_should_be_lowest_start_and_highest_due_dates
305
    parent = create_issue!
306
    create_issue!(:start_date => '2010-01-25', :due_date => '2010-02-15', :parent_issue_id => parent.id)
307
    create_issue!(                             :due_date => '2010-02-13', :parent_issue_id => parent.id)
308
    create_issue!(:start_date => '2010-02-01', :due_date => '2010-02-22', :parent_issue_id => parent.id)
309
    parent.reload
310
    assert_equal Date.parse('2010-01-25'), parent.start_date
311
    assert_equal Date.parse('2010-02-22'), parent.due_date
312
  end
313

    
314
  def test_parent_done_ratio_should_be_average_done_ratio_of_leaves
315
    parent = create_issue!
316
    create_issue!(:done_ratio => 20, :parent_issue_id => parent.id)
317
    assert_equal 20, parent.reload.done_ratio
318
    create_issue!(:done_ratio => 70, :parent_issue_id => parent.id)
319
    assert_equal 45, parent.reload.done_ratio
320

    
321
    child = create_issue!(:done_ratio => 0, :parent_issue_id => parent.id)
322
    assert_equal 30, parent.reload.done_ratio
323

    
324
    create_issue!(:done_ratio => 30, :parent_issue_id => child.id)
325
    assert_equal 30, child.reload.done_ratio
326
    assert_equal 40, parent.reload.done_ratio
327
  end
328

    
329
  def test_parent_done_ratio_should_be_weighted_by_estimated_times_if_any
330
    parent = create_issue!
331
    create_issue!(:estimated_hours => 10, :done_ratio => 20, :parent_issue_id => parent.id)
332
    assert_equal 20, parent.reload.done_ratio
333
    create_issue!(:estimated_hours => 20, :done_ratio => 50, :parent_issue_id => parent.id)
334
    assert_equal (50 * 20 + 20 * 10) / 30, parent.reload.done_ratio
335
  end
336

    
337
  def test_parent_estimate_should_be_sum_of_leaves
338
    parent = create_issue!
339
    create_issue!(:estimated_hours => nil, :parent_issue_id => parent.id)
340
    assert_equal nil, parent.reload.estimated_hours
341
    create_issue!(:estimated_hours => 5, :parent_issue_id => parent.id)
342
    assert_equal 5, parent.reload.estimated_hours
343
    create_issue!(:estimated_hours => 7, :parent_issue_id => parent.id)
344
    assert_equal 12, parent.reload.estimated_hours
345
  end
346

    
347
  def test_move_parent_updates_old_parent_attributes
348
    first_parent = create_issue!
349
    second_parent = create_issue!
350
    child = create_issue!(:estimated_hours => 5, :parent_issue_id => first_parent.id)
351
    assert_equal 5, first_parent.reload.estimated_hours
352
    child.update_attributes(:estimated_hours => 7, :parent_issue_id => second_parent.id)
353
    assert_equal 7, second_parent.reload.estimated_hours
354
    assert_nil first_parent.reload.estimated_hours
355
  end
356

    
357
  def test_reschuling_a_parent_should_reschedule_subtasks
358
    parent = create_issue!
359
    c1 = create_issue!(:start_date => '2010-05-12', :due_date => '2010-05-18', :parent_issue_id => parent.id)
360
    c2 = create_issue!(:start_date => '2010-06-03', :due_date => '2010-06-10', :parent_issue_id => parent.id)
361
    parent.reload
362
    parent.reschedule_after(Date.parse('2010-06-02'))
363
    c1.reload
364
    assert_equal [Date.parse('2010-06-02'), Date.parse('2010-06-08')], [c1.start_date, c1.due_date]
365
    c2.reload
366
    assert_equal [Date.parse('2010-06-03'), Date.parse('2010-06-10')], [c2.start_date, c2.due_date] # no change
367
    parent.reload
368
    assert_equal [Date.parse('2010-06-02'), Date.parse('2010-06-10')], [parent.start_date, parent.due_date]
369
  end
370

    
371
  def test_project_copy_should_copy_issue_tree
372
    p = Project.create!(:name => 'Tree copy', :identifier => 'tree-copy', :tracker_ids => [1, 2])
373
    i1 = create_issue!(:project_id => p.id, :subject => 'i1')
374
    i2 = create_issue!(:project_id => p.id, :subject => 'i2', :parent_issue_id => i1.id)
375
    i3 = create_issue!(:project_id => p.id, :subject => 'i3', :parent_issue_id => i1.id)
376
    i4 = create_issue!(:project_id => p.id, :subject => 'i4', :parent_issue_id => i2.id)
377
    i5 = create_issue!(:project_id => p.id, :subject => 'i5')
378
    c = Project.new(:name => 'Copy', :identifier => 'copy', :tracker_ids => [1, 2])
379
    c.copy(p, :only => 'issues')
380
    c.reload
381

    
382
    assert_equal 5, c.issues.count
383
    ic1, ic2, ic3, ic4, ic5 = c.issues.find(:all, :order => 'subject')
384
    assert ic1.root?
385
    assert_equal ic1, ic2.parent
386
    assert_equal ic1, ic3.parent
387
    assert_equal ic2, ic4.parent
388
    assert ic5.root?
389
  end
390

    
391
  # Helper that creates an issue with default attributes
392
  def create_issue!(attributes={})
393
    Issue.create!({:project_id => 1, :tracker_id => 1, :author_id => 1, :subject => 'test'}.merge(attributes))
394
  end
395
end