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 / test / unit / issue_test.rb @ 442:753f1380d6bc

History | View | Annotate | Download (36.6 KB)

1 245:051f544170fe Chris
# Redmine - project management software
2
# Copyright (C) 2006-2011  Jean-Philippe Lang
3 0:513646585e45 Chris
#
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 441:cbce1fd3b1b7 Chris
#
9 0:513646585e45 Chris
# 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 441:cbce1fd3b1b7 Chris
#
14 0:513646585e45 Chris
# 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 119:8661b858af72 Chris
require File.expand_path('../../test_helper', __FILE__)
19 0:513646585e45 Chris
20
class IssueTest < ActiveSupport::TestCase
21
  fixtures :projects, :users, :members, :member_roles, :roles,
22
           :trackers, :projects_trackers,
23
           :enabled_modules,
24
           :versions,
25 441:cbce1fd3b1b7 Chris
           :issue_statuses, :issue_categories, :issue_relations, :workflows,
26 0:513646585e45 Chris
           :enumerations,
27
           :issues,
28
           :custom_fields, :custom_fields_projects, :custom_fields_trackers, :custom_values,
29
           :time_entries
30
31
  def test_create
32
    issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3, :status_id => 1, :priority => IssuePriority.all.first, :subject => 'test_create', :description => 'IssueTest#test_create', :estimated_hours => '1:30')
33
    assert issue.save
34
    issue.reload
35
    assert_equal 1.5, issue.estimated_hours
36
  end
37 441:cbce1fd3b1b7 Chris
38 0:513646585e45 Chris
  def test_create_minimal
39
    issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3, :status_id => 1, :priority => IssuePriority.all.first, :subject => 'test_create')
40
    assert issue.save
41
    assert issue.description.nil?
42
  end
43 441:cbce1fd3b1b7 Chris
44 0:513646585e45 Chris
  def test_create_with_required_custom_field
45
    field = IssueCustomField.find_by_name('Database')
46
    field.update_attribute(:is_required, true)
47 441:cbce1fd3b1b7 Chris
48 0:513646585e45 Chris
    issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :subject => 'test_create', :description => 'IssueTest#test_create_with_required_custom_field')
49
    assert issue.available_custom_fields.include?(field)
50
    # No value for the custom field
51
    assert !issue.save
52
    assert_equal I18n.translate('activerecord.errors.messages.invalid'), issue.errors.on(:custom_values)
53
    # Blank value
54
    issue.custom_field_values = { field.id => '' }
55
    assert !issue.save
56
    assert_equal I18n.translate('activerecord.errors.messages.invalid'), issue.errors.on(:custom_values)
57
    # Invalid value
58
    issue.custom_field_values = { field.id => 'SQLServer' }
59
    assert !issue.save
60
    assert_equal I18n.translate('activerecord.errors.messages.invalid'), issue.errors.on(:custom_values)
61
    # Valid value
62
    issue.custom_field_values = { field.id => 'PostgreSQL' }
63
    assert issue.save
64
    issue.reload
65
    assert_equal 'PostgreSQL', issue.custom_value_for(field).value
66
  end
67 441:cbce1fd3b1b7 Chris
68
  def assert_visibility_match(user, issues)
69
    assert_equal issues.collect(&:id).sort, Issue.all.select {|issue| issue.visible?(user)}.collect(&:id).sort
70
  end
71
72 0:513646585e45 Chris
  def test_visible_scope_for_anonymous
73
    # Anonymous user should see issues of public projects only
74
    issues = Issue.visible(User.anonymous).all
75
    assert issues.any?
76
    assert_nil issues.detect {|issue| !issue.project.is_public?}
77 441:cbce1fd3b1b7 Chris
    assert_nil issues.detect {|issue| issue.is_private?}
78
    assert_visibility_match User.anonymous, issues
79
  end
80
81
  def test_visible_scope_for_anonymous_with_own_issues_visibility
82
    Role.anonymous.update_attribute :issues_visibility, 'own'
83
    Issue.create!(:project_id => 1, :tracker_id => 1, :author_id => User.anonymous.id, :subject => 'Issue by anonymous')
84
85
    issues = Issue.visible(User.anonymous).all
86
    assert issues.any?
87
    assert_nil issues.detect {|issue| issue.author != User.anonymous}
88
    assert_visibility_match User.anonymous, issues
89
  end
90
91
  def test_visible_scope_for_anonymous_without_view_issues_permissions
92 0:513646585e45 Chris
    # Anonymous user should not see issues without permission
93
    Role.anonymous.remove_permission!(:view_issues)
94
    issues = Issue.visible(User.anonymous).all
95
    assert issues.empty?
96 441:cbce1fd3b1b7 Chris
    assert_visibility_match User.anonymous, issues
97 0:513646585e45 Chris
  end
98 441:cbce1fd3b1b7 Chris
99
  def test_visible_scope_for_non_member
100 0:513646585e45 Chris
    user = User.find(9)
101
    assert user.projects.empty?
102
    # Non member user should see issues of public projects only
103
    issues = Issue.visible(user).all
104
    assert issues.any?
105
    assert_nil issues.detect {|issue| !issue.project.is_public?}
106 441:cbce1fd3b1b7 Chris
    assert_nil issues.detect {|issue| issue.is_private?}
107
    assert_visibility_match user, issues
108
  end
109
110
  def test_visible_scope_for_non_member_with_own_issues_visibility
111
    Role.non_member.update_attribute :issues_visibility, 'own'
112
    Issue.create!(:project_id => 1, :tracker_id => 1, :author_id => 9, :subject => 'Issue by non member')
113
    user = User.find(9)
114
115
    issues = Issue.visible(user).all
116
    assert issues.any?
117
    assert_nil issues.detect {|issue| issue.author != user}
118
    assert_visibility_match user, issues
119
  end
120
121
  def test_visible_scope_for_non_member_without_view_issues_permissions
122 0:513646585e45 Chris
    # Non member user should not see issues without permission
123
    Role.non_member.remove_permission!(:view_issues)
124 441:cbce1fd3b1b7 Chris
    user = User.find(9)
125
    assert user.projects.empty?
126 0:513646585e45 Chris
    issues = Issue.visible(user).all
127
    assert issues.empty?
128 441:cbce1fd3b1b7 Chris
    assert_visibility_match user, issues
129
  end
130
131
  def test_visible_scope_for_member
132
    user = User.find(9)
133 0:513646585e45 Chris
    # User should see issues of projects for which he has view_issues permissions only
134 441:cbce1fd3b1b7 Chris
    Role.non_member.remove_permission!(:view_issues)
135
    Member.create!(:principal => user, :project_id => 3, :role_ids => [2])
136 0:513646585e45 Chris
    issues = Issue.visible(user).all
137
    assert issues.any?
138 441:cbce1fd3b1b7 Chris
    assert_nil issues.detect {|issue| issue.project_id != 3}
139
    assert_nil issues.detect {|issue| issue.is_private?}
140
    assert_visibility_match user, issues
141 0:513646585e45 Chris
  end
142 441:cbce1fd3b1b7 Chris
143 0:513646585e45 Chris
  def test_visible_scope_for_admin
144
    user = User.find(1)
145
    user.members.each(&:destroy)
146
    assert user.projects.empty?
147
    issues = Issue.visible(user).all
148
    assert issues.any?
149
    # Admin should see issues on private projects that he does not belong to
150
    assert issues.detect {|issue| !issue.project.is_public?}
151 441:cbce1fd3b1b7 Chris
    # Admin should see private issues of other users
152
    assert issues.detect {|issue| issue.is_private? && issue.author != user}
153
    assert_visibility_match user, issues
154 0:513646585e45 Chris
  end
155 441:cbce1fd3b1b7 Chris
156
  def test_visible_scope_with_project
157
    project = Project.find(1)
158
    issues = Issue.visible(User.find(2), :project => project).all
159
    projects = issues.collect(&:project).uniq
160
    assert_equal 1, projects.size
161
    assert_equal project, projects.first
162
  end
163
164
  def test_visible_scope_with_project_and_subprojects
165
    project = Project.find(1)
166
    issues = Issue.visible(User.find(2), :project => project, :with_subprojects => true).all
167
    projects = issues.collect(&:project).uniq
168
    assert projects.size > 1
169
    assert_equal [], projects.select {|p| !p.is_or_is_descendant_of?(project)}
170
  end
171
172
  def test_visible_and_nested_set_scopes
173
    assert_equal 0, Issue.find(1).descendants.visible.all.size
174
  end
175
176 0:513646585e45 Chris
  def test_errors_full_messages_should_include_custom_fields_errors
177
    field = IssueCustomField.find_by_name('Database')
178 441:cbce1fd3b1b7 Chris
179 0:513646585e45 Chris
    issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :subject => 'test_create', :description => 'IssueTest#test_create_with_required_custom_field')
180
    assert issue.available_custom_fields.include?(field)
181
    # Invalid value
182
    issue.custom_field_values = { field.id => 'SQLServer' }
183 441:cbce1fd3b1b7 Chris
184 0:513646585e45 Chris
    assert !issue.valid?
185
    assert_equal 1, issue.errors.full_messages.size
186
    assert_equal "Database #{I18n.translate('activerecord.errors.messages.inclusion')}", issue.errors.full_messages.first
187
  end
188 441:cbce1fd3b1b7 Chris
189 0:513646585e45 Chris
  def test_update_issue_with_required_custom_field
190
    field = IssueCustomField.find_by_name('Database')
191
    field.update_attribute(:is_required, true)
192 441:cbce1fd3b1b7 Chris
193 0:513646585e45 Chris
    issue = Issue.find(1)
194
    assert_nil issue.custom_value_for(field)
195
    assert issue.available_custom_fields.include?(field)
196
    # No change to custom values, issue can be saved
197
    assert issue.save
198
    # Blank value
199
    issue.custom_field_values = { field.id => '' }
200
    assert !issue.save
201
    # Valid value
202
    issue.custom_field_values = { field.id => 'PostgreSQL' }
203
    assert issue.save
204
    issue.reload
205
    assert_equal 'PostgreSQL', issue.custom_value_for(field).value
206
  end
207 441:cbce1fd3b1b7 Chris
208 0:513646585e45 Chris
  def test_should_not_update_attributes_if_custom_fields_validation_fails
209
    issue = Issue.find(1)
210
    field = IssueCustomField.find_by_name('Database')
211
    assert issue.available_custom_fields.include?(field)
212 441:cbce1fd3b1b7 Chris
213 0:513646585e45 Chris
    issue.custom_field_values = { field.id => 'Invalid' }
214
    issue.subject = 'Should be not be saved'
215
    assert !issue.save
216 441:cbce1fd3b1b7 Chris
217 0:513646585e45 Chris
    issue.reload
218
    assert_equal "Can't print recipes", issue.subject
219
  end
220 441:cbce1fd3b1b7 Chris
221 0:513646585e45 Chris
  def test_should_not_recreate_custom_values_objects_on_update
222
    field = IssueCustomField.find_by_name('Database')
223 441:cbce1fd3b1b7 Chris
224 0:513646585e45 Chris
    issue = Issue.find(1)
225
    issue.custom_field_values = { field.id => 'PostgreSQL' }
226
    assert issue.save
227
    custom_value = issue.custom_value_for(field)
228
    issue.reload
229
    issue.custom_field_values = { field.id => 'MySQL' }
230
    assert issue.save
231
    issue.reload
232
    assert_equal custom_value.id, issue.custom_value_for(field).id
233
  end
234 441:cbce1fd3b1b7 Chris
235 0:513646585e45 Chris
  def test_assigning_tracker_id_should_reload_custom_fields_values
236
    issue = Issue.new(:project => Project.find(1))
237
    assert issue.custom_field_values.empty?
238
    issue.tracker_id = 1
239
    assert issue.custom_field_values.any?
240
  end
241 441:cbce1fd3b1b7 Chris
242 0:513646585e45 Chris
  def test_assigning_attributes_should_assign_tracker_id_first
243
    attributes = ActiveSupport::OrderedHash.new
244
    attributes['custom_field_values'] = { '1' => 'MySQL' }
245
    attributes['tracker_id'] = '1'
246
    issue = Issue.new(:project => Project.find(1))
247
    issue.attributes = attributes
248
    assert_not_nil issue.custom_value_for(1)
249
    assert_equal 'MySQL', issue.custom_value_for(1).value
250
  end
251 441:cbce1fd3b1b7 Chris
252 0:513646585e45 Chris
  def test_should_update_issue_with_disabled_tracker
253
    p = Project.find(1)
254
    issue = Issue.find(1)
255 441:cbce1fd3b1b7 Chris
256 0:513646585e45 Chris
    p.trackers.delete(issue.tracker)
257
    assert !p.trackers.include?(issue.tracker)
258 441:cbce1fd3b1b7 Chris
259 0:513646585e45 Chris
    issue.reload
260
    issue.subject = 'New subject'
261
    assert issue.save
262
  end
263 441:cbce1fd3b1b7 Chris
264 0:513646585e45 Chris
  def test_should_not_set_a_disabled_tracker
265
    p = Project.find(1)
266
    p.trackers.delete(Tracker.find(2))
267 441:cbce1fd3b1b7 Chris
268 0:513646585e45 Chris
    issue = Issue.find(1)
269
    issue.tracker_id = 2
270
    issue.subject = 'New subject'
271
    assert !issue.save
272
    assert_not_nil issue.errors.on(:tracker_id)
273
  end
274 441:cbce1fd3b1b7 Chris
275 0:513646585e45 Chris
  def test_category_based_assignment
276
    issue = Issue.create(:project_id => 1, :tracker_id => 1, :author_id => 3, :status_id => 1, :priority => IssuePriority.all.first, :subject => 'Assignment test', :description => 'Assignment test', :category_id => 1)
277
    assert_equal IssueCategory.find(1).assigned_to, issue.assigned_to
278
  end
279 441:cbce1fd3b1b7 Chris
280 245:051f544170fe Chris
  def test_new_statuses_allowed_to
281
    Workflow.delete_all
282 441:cbce1fd3b1b7 Chris
283 245:051f544170fe Chris
    Workflow.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 2, :author => false, :assignee => false)
284
    Workflow.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 3, :author => true, :assignee => false)
285
    Workflow.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 4, :author => false, :assignee => true)
286
    Workflow.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 5, :author => true, :assignee => true)
287
    status = IssueStatus.find(1)
288
    role = Role.find(1)
289
    tracker = Tracker.find(1)
290
    user = User.find(2)
291 441:cbce1fd3b1b7 Chris
292 245:051f544170fe Chris
    issue = Issue.generate!(:tracker => tracker, :status => status, :project_id => 1)
293
    assert_equal [1, 2], issue.new_statuses_allowed_to(user).map(&:id)
294 441:cbce1fd3b1b7 Chris
295 245:051f544170fe Chris
    issue = Issue.generate!(:tracker => tracker, :status => status, :project_id => 1, :author => user)
296
    assert_equal [1, 2, 3], issue.new_statuses_allowed_to(user).map(&:id)
297 441:cbce1fd3b1b7 Chris
298 245:051f544170fe Chris
    issue = Issue.generate!(:tracker => tracker, :status => status, :project_id => 1, :assigned_to => user)
299
    assert_equal [1, 2, 4], issue.new_statuses_allowed_to(user).map(&:id)
300 441:cbce1fd3b1b7 Chris
301 245:051f544170fe Chris
    issue = Issue.generate!(:tracker => tracker, :status => status, :project_id => 1, :author => user, :assigned_to => user)
302
    assert_equal [1, 2, 3, 4, 5], issue.new_statuses_allowed_to(user).map(&:id)
303
  end
304 441:cbce1fd3b1b7 Chris
305 0:513646585e45 Chris
  def test_copy
306
    issue = Issue.new.copy_from(1)
307
    assert issue.save
308
    issue.reload
309
    orig = Issue.find(1)
310
    assert_equal orig.subject, issue.subject
311
    assert_equal orig.tracker, issue.tracker
312
    assert_equal "125", issue.custom_value_for(2).value
313
  end
314
315
  def test_copy_should_copy_status
316
    orig = Issue.find(8)
317
    assert orig.status != IssueStatus.default
318 441:cbce1fd3b1b7 Chris
319 0:513646585e45 Chris
    issue = Issue.new.copy_from(orig)
320
    assert issue.save
321
    issue.reload
322
    assert_equal orig.status, issue.status
323
  end
324 441:cbce1fd3b1b7 Chris
325 0:513646585e45 Chris
  def test_should_close_duplicates
326
    # Create 3 issues
327
    issue1 = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :priority => IssuePriority.all.first, :subject => 'Duplicates test', :description => 'Duplicates test')
328
    assert issue1.save
329
    issue2 = issue1.clone
330
    assert issue2.save
331
    issue3 = issue1.clone
332
    assert issue3.save
333 441:cbce1fd3b1b7 Chris
334 0:513646585e45 Chris
    # 2 is a dupe of 1
335
    IssueRelation.create(:issue_from => issue2, :issue_to => issue1, :relation_type => IssueRelation::TYPE_DUPLICATES)
336
    # And 3 is a dupe of 2
337
    IssueRelation.create(:issue_from => issue3, :issue_to => issue2, :relation_type => IssueRelation::TYPE_DUPLICATES)
338
    # And 3 is a dupe of 1 (circular duplicates)
339
    IssueRelation.create(:issue_from => issue3, :issue_to => issue1, :relation_type => IssueRelation::TYPE_DUPLICATES)
340 441:cbce1fd3b1b7 Chris
341 0:513646585e45 Chris
    assert issue1.reload.duplicates.include?(issue2)
342 441:cbce1fd3b1b7 Chris
343 0:513646585e45 Chris
    # Closing issue 1
344
    issue1.init_journal(User.find(:first), "Closing issue1")
345
    issue1.status = IssueStatus.find :first, :conditions => {:is_closed => true}
346
    assert issue1.save
347
    # 2 and 3 should be also closed
348
    assert issue2.reload.closed?
349 441:cbce1fd3b1b7 Chris
    assert issue3.reload.closed?
350 0:513646585e45 Chris
  end
351 441:cbce1fd3b1b7 Chris
352 0:513646585e45 Chris
  def test_should_not_close_duplicated_issue
353
    # Create 3 issues
354
    issue1 = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :priority => IssuePriority.all.first, :subject => 'Duplicates test', :description => 'Duplicates test')
355
    assert issue1.save
356
    issue2 = issue1.clone
357
    assert issue2.save
358 441:cbce1fd3b1b7 Chris
359 0:513646585e45 Chris
    # 2 is a dupe of 1
360
    IssueRelation.create(:issue_from => issue2, :issue_to => issue1, :relation_type => IssueRelation::TYPE_DUPLICATES)
361
    # 2 is a dup of 1 but 1 is not a duplicate of 2
362
    assert !issue2.reload.duplicates.include?(issue1)
363 441:cbce1fd3b1b7 Chris
364 0:513646585e45 Chris
    # Closing issue 2
365
    issue2.init_journal(User.find(:first), "Closing issue2")
366
    issue2.status = IssueStatus.find :first, :conditions => {:is_closed => true}
367
    assert issue2.save
368
    # 1 should not be also closed
369
    assert !issue1.reload.closed?
370
  end
371 441:cbce1fd3b1b7 Chris
372 0:513646585e45 Chris
  def test_assignable_versions
373
    issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :fixed_version_id => 1, :subject => 'New issue')
374
    assert_equal ['open'], issue.assignable_versions.collect(&:status).uniq
375
  end
376 441:cbce1fd3b1b7 Chris
377 0:513646585e45 Chris
  def test_should_not_be_able_to_assign_a_new_issue_to_a_closed_version
378
    issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :fixed_version_id => 1, :subject => 'New issue')
379
    assert !issue.save
380
    assert_not_nil issue.errors.on(:fixed_version_id)
381
  end
382 441:cbce1fd3b1b7 Chris
383 0:513646585e45 Chris
  def test_should_not_be_able_to_assign_a_new_issue_to_a_locked_version
384
    issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :fixed_version_id => 2, :subject => 'New issue')
385
    assert !issue.save
386
    assert_not_nil issue.errors.on(:fixed_version_id)
387
  end
388 441:cbce1fd3b1b7 Chris
389 0:513646585e45 Chris
  def test_should_be_able_to_assign_a_new_issue_to_an_open_version
390
    issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :fixed_version_id => 3, :subject => 'New issue')
391
    assert issue.save
392
  end
393 441:cbce1fd3b1b7 Chris
394 0:513646585e45 Chris
  def test_should_be_able_to_update_an_issue_assigned_to_a_closed_version
395
    issue = Issue.find(11)
396
    assert_equal 'closed', issue.fixed_version.status
397
    issue.subject = 'Subject changed'
398
    assert issue.save
399
  end
400 441:cbce1fd3b1b7 Chris
401 0:513646585e45 Chris
  def test_should_not_be_able_to_reopen_an_issue_assigned_to_a_closed_version
402
    issue = Issue.find(11)
403
    issue.status_id = 1
404
    assert !issue.save
405
    assert_not_nil issue.errors.on_base
406
  end
407 441:cbce1fd3b1b7 Chris
408 0:513646585e45 Chris
  def test_should_be_able_to_reopen_and_reassign_an_issue_assigned_to_a_closed_version
409
    issue = Issue.find(11)
410
    issue.status_id = 1
411
    issue.fixed_version_id = 3
412
    assert issue.save
413
  end
414 441:cbce1fd3b1b7 Chris
415 0:513646585e45 Chris
  def test_should_be_able_to_reopen_an_issue_assigned_to_a_locked_version
416
    issue = Issue.find(12)
417
    assert_equal 'locked', issue.fixed_version.status
418
    issue.status_id = 1
419
    assert issue.save
420
  end
421 441:cbce1fd3b1b7 Chris
422 0:513646585e45 Chris
  def test_move_to_another_project_with_same_category
423
    issue = Issue.find(1)
424
    assert issue.move_to_project(Project.find(2))
425
    issue.reload
426
    assert_equal 2, issue.project_id
427
    # Category changes
428
    assert_equal 4, issue.category_id
429
    # Make sure time entries were move to the target project
430
    assert_equal 2, issue.time_entries.first.project_id
431
  end
432 441:cbce1fd3b1b7 Chris
433 0:513646585e45 Chris
  def test_move_to_another_project_without_same_category
434
    issue = Issue.find(2)
435
    assert issue.move_to_project(Project.find(2))
436
    issue.reload
437
    assert_equal 2, issue.project_id
438
    # Category cleared
439
    assert_nil issue.category_id
440
  end
441 441:cbce1fd3b1b7 Chris
442 0:513646585e45 Chris
  def test_move_to_another_project_should_clear_fixed_version_when_not_shared
443
    issue = Issue.find(1)
444
    issue.update_attribute(:fixed_version_id, 1)
445
    assert issue.move_to_project(Project.find(2))
446
    issue.reload
447
    assert_equal 2, issue.project_id
448
    # Cleared fixed_version
449
    assert_equal nil, issue.fixed_version
450
  end
451 441:cbce1fd3b1b7 Chris
452 0:513646585e45 Chris
  def test_move_to_another_project_should_keep_fixed_version_when_shared_with_the_target_project
453
    issue = Issue.find(1)
454
    issue.update_attribute(:fixed_version_id, 4)
455
    assert issue.move_to_project(Project.find(5))
456
    issue.reload
457
    assert_equal 5, issue.project_id
458
    # Keep fixed_version
459
    assert_equal 4, issue.fixed_version_id
460
  end
461 441:cbce1fd3b1b7 Chris
462 0:513646585e45 Chris
  def test_move_to_another_project_should_clear_fixed_version_when_not_shared_with_the_target_project
463
    issue = Issue.find(1)
464
    issue.update_attribute(:fixed_version_id, 1)
465
    assert issue.move_to_project(Project.find(5))
466
    issue.reload
467
    assert_equal 5, issue.project_id
468
    # Cleared fixed_version
469
    assert_equal nil, issue.fixed_version
470
  end
471 441:cbce1fd3b1b7 Chris
472 0:513646585e45 Chris
  def test_move_to_another_project_should_keep_fixed_version_when_shared_systemwide
473
    issue = Issue.find(1)
474
    issue.update_attribute(:fixed_version_id, 7)
475
    assert issue.move_to_project(Project.find(2))
476
    issue.reload
477
    assert_equal 2, issue.project_id
478
    # Keep fixed_version
479
    assert_equal 7, issue.fixed_version_id
480
  end
481 441:cbce1fd3b1b7 Chris
482 0:513646585e45 Chris
  def test_move_to_another_project_with_disabled_tracker
483
    issue = Issue.find(1)
484
    target = Project.find(2)
485
    target.tracker_ids = [3]
486
    target.save
487
    assert_equal false, issue.move_to_project(target)
488
    issue.reload
489
    assert_equal 1, issue.project_id
490
  end
491 441:cbce1fd3b1b7 Chris
492 0:513646585e45 Chris
  def test_copy_to_the_same_project
493
    issue = Issue.find(1)
494
    copy = nil
495
    assert_difference 'Issue.count' do
496
      copy = issue.move_to_project(issue.project, nil, :copy => true)
497
    end
498
    assert_kind_of Issue, copy
499
    assert_equal issue.project, copy.project
500
    assert_equal "125", copy.custom_value_for(2).value
501
  end
502 441:cbce1fd3b1b7 Chris
503 0:513646585e45 Chris
  def test_copy_to_another_project_and_tracker
504
    issue = Issue.find(1)
505
    copy = nil
506
    assert_difference 'Issue.count' do
507
      copy = issue.move_to_project(Project.find(3), Tracker.find(2), :copy => true)
508
    end
509
    copy.reload
510
    assert_kind_of Issue, copy
511
    assert_equal Project.find(3), copy.project
512
    assert_equal Tracker.find(2), copy.tracker
513
    # Custom field #2 is not associated with target tracker
514
    assert_nil copy.custom_value_for(2)
515
  end
516
517
  context "#move_to_project" do
518
    context "as a copy" do
519
      setup do
520
        @issue = Issue.find(1)
521
        @copy = nil
522
      end
523
524 441:cbce1fd3b1b7 Chris
      should "not create a journal" do
525
        @copy = @issue.move_to_project(Project.find(3), Tracker.find(2), {:copy => true, :attributes => {:assigned_to_id => 3}})
526
        assert_equal 0, @copy.reload.journals.size
527
      end
528
529 0:513646585e45 Chris
      should "allow assigned_to changes" do
530
        @copy = @issue.move_to_project(Project.find(3), Tracker.find(2), {:copy => true, :attributes => {:assigned_to_id => 3}})
531
        assert_equal 3, @copy.assigned_to_id
532
      end
533
534
      should "allow status changes" do
535
        @copy = @issue.move_to_project(Project.find(3), Tracker.find(2), {:copy => true, :attributes => {:status_id => 2}})
536
        assert_equal 2, @copy.status_id
537
      end
538
539
      should "allow start date changes" do
540
        date = Date.today
541
        @copy = @issue.move_to_project(Project.find(3), Tracker.find(2), {:copy => true, :attributes => {:start_date => date}})
542
        assert_equal date, @copy.start_date
543
      end
544
545
      should "allow due date changes" do
546
        date = Date.today
547
        @copy = @issue.move_to_project(Project.find(3), Tracker.find(2), {:copy => true, :attributes => {:due_date => date}})
548
549
        assert_equal date, @copy.due_date
550
      end
551 441:cbce1fd3b1b7 Chris
552
      should "set current user as author" do
553
        User.current = User.find(9)
554
        @copy = @issue.move_to_project(Project.find(3), Tracker.find(2), {:copy => true, :attributes => {}})
555
556
        assert_equal User.current, @copy.author
557
      end
558
559
      should "keep journal notes" do
560
        date = Date.today
561
        notes = "Notes added when copying"
562
        User.current = User.find(9)
563
        @issue.init_journal(User.current, notes)
564
        @copy = @issue.move_to_project(Project.find(3), Tracker.find(2), {:copy => true, :attributes => {:start_date => date}})
565
566
        assert_equal 1, @copy.journals.size
567
        journal = @copy.journals.first
568
        assert_equal 0, journal.details.size
569
        assert_equal notes, journal.notes
570
      end
571 0:513646585e45 Chris
    end
572
  end
573 441:cbce1fd3b1b7 Chris
574 0:513646585e45 Chris
  def test_recipients_should_not_include_users_that_cannot_view_the_issue
575
    issue = Issue.find(12)
576
    assert issue.recipients.include?(issue.author.mail)
577
    # move the issue to a private project
578
    copy  = issue.move_to_project(Project.find(5), Tracker.find(2), :copy => true)
579
    # author is not a member of project anymore
580
    assert !copy.recipients.include?(copy.author.mail)
581
  end
582
583
  def test_watcher_recipients_should_not_include_users_that_cannot_view_the_issue
584
    user = User.find(3)
585
    issue = Issue.find(9)
586
    Watcher.create!(:user => user, :watchable => issue)
587
    assert issue.watched_by?(user)
588
    assert !issue.watcher_recipients.include?(user.mail)
589
  end
590 441:cbce1fd3b1b7 Chris
591 0:513646585e45 Chris
  def test_issue_destroy
592
    Issue.find(1).destroy
593
    assert_nil Issue.find_by_id(1)
594
    assert_nil TimeEntry.find_by_issue_id(1)
595
  end
596 441:cbce1fd3b1b7 Chris
597 0:513646585e45 Chris
  def test_blocked
598
    blocked_issue = Issue.find(9)
599
    blocking_issue = Issue.find(10)
600 441:cbce1fd3b1b7 Chris
601 0:513646585e45 Chris
    assert blocked_issue.blocked?
602
    assert !blocking_issue.blocked?
603
  end
604 441:cbce1fd3b1b7 Chris
605 0:513646585e45 Chris
  def test_blocked_issues_dont_allow_closed_statuses
606
    blocked_issue = Issue.find(9)
607 441:cbce1fd3b1b7 Chris
608 0:513646585e45 Chris
    allowed_statuses = blocked_issue.new_statuses_allowed_to(users(:users_002))
609
    assert !allowed_statuses.empty?
610
    closed_statuses = allowed_statuses.select {|st| st.is_closed?}
611
    assert closed_statuses.empty?
612
  end
613 441:cbce1fd3b1b7 Chris
614 0:513646585e45 Chris
  def test_unblocked_issues_allow_closed_statuses
615
    blocking_issue = Issue.find(10)
616 441:cbce1fd3b1b7 Chris
617 0:513646585e45 Chris
    allowed_statuses = blocking_issue.new_statuses_allowed_to(users(:users_002))
618
    assert !allowed_statuses.empty?
619
    closed_statuses = allowed_statuses.select {|st| st.is_closed?}
620
    assert !closed_statuses.empty?
621
  end
622 441:cbce1fd3b1b7 Chris
623 37:94944d00e43c chris
  def test_rescheduling_an_issue_should_reschedule_following_issue
624
    issue1 = Issue.create!(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :subject => '-', :start_date => Date.today, :due_date => Date.today + 2)
625
    issue2 = Issue.create!(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :subject => '-', :start_date => Date.today, :due_date => Date.today + 2)
626
    IssueRelation.create!(:issue_from => issue1, :issue_to => issue2, :relation_type => IssueRelation::TYPE_PRECEDES)
627
    assert_equal issue1.due_date + 1, issue2.reload.start_date
628 441:cbce1fd3b1b7 Chris
629 37:94944d00e43c chris
    issue1.due_date = Date.today + 5
630
    issue1.save!
631
    assert_equal issue1.due_date + 1, issue2.reload.start_date
632
  end
633 441:cbce1fd3b1b7 Chris
634 0:513646585e45 Chris
  def test_overdue
635
    assert Issue.new(:due_date => 1.day.ago.to_date).overdue?
636
    assert !Issue.new(:due_date => Date.today).overdue?
637
    assert !Issue.new(:due_date => 1.day.from_now.to_date).overdue?
638
    assert !Issue.new(:due_date => nil).overdue?
639
    assert !Issue.new(:due_date => 1.day.ago.to_date, :status => IssueStatus.find(:first, :conditions => {:is_closed => true})).overdue?
640
  end
641 22:40f7cfd4df19 chris
642
  context "#behind_schedule?" do
643
    should "be false if the issue has no start_date" do
644
      assert !Issue.new(:start_date => nil, :due_date => 1.day.from_now.to_date, :done_ratio => 0).behind_schedule?
645
    end
646
647
    should "be false if the issue has no end_date" do
648
      assert !Issue.new(:start_date => 1.day.from_now.to_date, :due_date => nil, :done_ratio => 0).behind_schedule?
649
    end
650
651
    should "be false if the issue has more done than it's calendar time" do
652
      assert !Issue.new(:start_date => 50.days.ago.to_date, :due_date => 50.days.from_now.to_date, :done_ratio => 90).behind_schedule?
653
    end
654
655
    should "be true if the issue hasn't been started at all" do
656
      assert Issue.new(:start_date => 1.day.ago.to_date, :due_date => 1.day.from_now.to_date, :done_ratio => 0).behind_schedule?
657
    end
658
659
    should "be true if the issue has used more calendar time than it's done ratio" do
660
      assert Issue.new(:start_date => 100.days.ago.to_date, :due_date => Date.today, :done_ratio => 90).behind_schedule?
661
    end
662
  end
663 37:94944d00e43c chris
664
  context "#assignable_users" do
665
    should "be Users" do
666
      assert_kind_of User, Issue.find(1).assignable_users.first
667
    end
668
669
    should "include the issue author" do
670
      project = Project.find(1)
671
      non_project_member = User.generate!
672
      issue = Issue.generate_for_project!(project, :author => non_project_member)
673
674
      assert issue.assignable_users.include?(non_project_member)
675
    end
676
677
    should "not show the issue author twice" do
678
      assignable_user_ids = Issue.find(1).assignable_users.collect(&:id)
679
      assert_equal 2, assignable_user_ids.length
680 441:cbce1fd3b1b7 Chris
681 37:94944d00e43c chris
      assignable_user_ids.each do |user_id|
682
        assert_equal 1, assignable_user_ids.select {|i| i == user_id}.length, "User #{user_id} appears more or less than once"
683
      end
684
    end
685 0:513646585e45 Chris
  end
686 441:cbce1fd3b1b7 Chris
687 0:513646585e45 Chris
  def test_create_should_send_email_notification
688
    ActionMailer::Base.deliveries.clear
689
    issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3, :status_id => 1, :priority => IssuePriority.all.first, :subject => 'test_create', :estimated_hours => '1:30')
690
691
    assert issue.save
692
    assert_equal 1, ActionMailer::Base.deliveries.size
693
  end
694 37:94944d00e43c chris
695 0:513646585e45 Chris
  def test_stale_issue_should_not_send_email_notification
696
    ActionMailer::Base.deliveries.clear
697
    issue = Issue.find(1)
698
    stale = Issue.find(1)
699 441:cbce1fd3b1b7 Chris
700 0:513646585e45 Chris
    issue.init_journal(User.find(1))
701
    issue.subject = 'Subjet update'
702
    assert issue.save
703
    assert_equal 1, ActionMailer::Base.deliveries.size
704
    ActionMailer::Base.deliveries.clear
705 441:cbce1fd3b1b7 Chris
706 0:513646585e45 Chris
    stale.init_journal(User.find(1))
707
    stale.subject = 'Another subjet update'
708
    assert_raise ActiveRecord::StaleObjectError do
709
      stale.save
710
    end
711
    assert ActionMailer::Base.deliveries.empty?
712
  end
713 441:cbce1fd3b1b7 Chris
714 245:051f544170fe Chris
  def test_journalized_description
715
    IssueCustomField.delete_all
716 441:cbce1fd3b1b7 Chris
717 245:051f544170fe Chris
    i = Issue.first
718
    old_description = i.description
719
    new_description = "This is the new description"
720 441:cbce1fd3b1b7 Chris
721 245:051f544170fe Chris
    i.init_journal(User.find(2))
722
    i.description = new_description
723
    assert_difference 'Journal.count', 1 do
724
      assert_difference 'JournalDetail.count', 1 do
725
        i.save!
726
      end
727
    end
728 441:cbce1fd3b1b7 Chris
729 245:051f544170fe Chris
    detail = JournalDetail.first(:order => 'id DESC')
730
    assert_equal i, detail.journal.journalized
731
    assert_equal 'attr', detail.property
732
    assert_equal 'description', detail.prop_key
733
    assert_equal old_description, detail.old_value
734
    assert_equal new_description, detail.value
735
  end
736 441:cbce1fd3b1b7 Chris
737 0:513646585e45 Chris
  def test_saving_twice_should_not_duplicate_journal_details
738
    i = Issue.find(:first)
739
    i.init_journal(User.find(2), 'Some notes')
740
    # initial changes
741
    i.subject = 'New subject'
742
    i.done_ratio = i.done_ratio + 10
743
    assert_difference 'Journal.count' do
744
      assert i.save
745
    end
746
    # 1 more change
747
    i.priority = IssuePriority.find(:first, :conditions => ["id <> ?", i.priority_id])
748
    assert_no_difference 'Journal.count' do
749
      assert_difference 'JournalDetail.count', 1 do
750
        i.save
751
      end
752
    end
753
    # no more change
754
    assert_no_difference 'Journal.count' do
755
      assert_no_difference 'JournalDetail.count' do
756
        i.save
757
      end
758
    end
759
  end
760
761 128:07fa8a8b56a8 Chris
  def test_all_dependent_issues
762
    IssueRelation.delete_all
763
    assert IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(2), :relation_type => IssueRelation::TYPE_PRECEDES)
764
    assert IssueRelation.create!(:issue_from => Issue.find(2), :issue_to => Issue.find(3), :relation_type => IssueRelation::TYPE_PRECEDES)
765
    assert IssueRelation.create!(:issue_from => Issue.find(3), :issue_to => Issue.find(8), :relation_type => IssueRelation::TYPE_PRECEDES)
766 441:cbce1fd3b1b7 Chris
767 128:07fa8a8b56a8 Chris
    assert_equal [2, 3, 8], Issue.find(1).all_dependent_issues.collect(&:id).sort
768
  end
769
770
  def test_all_dependent_issues_with_persistent_circular_dependency
771
    IssueRelation.delete_all
772
    assert IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(2), :relation_type => IssueRelation::TYPE_PRECEDES)
773
    assert IssueRelation.create!(:issue_from => Issue.find(2), :issue_to => Issue.find(3), :relation_type => IssueRelation::TYPE_PRECEDES)
774
    # Validation skipping
775
    assert IssueRelation.new(:issue_from => Issue.find(3), :issue_to => Issue.find(1), :relation_type => IssueRelation::TYPE_PRECEDES).save(false)
776 441:cbce1fd3b1b7 Chris
777 128:07fa8a8b56a8 Chris
    assert_equal [2, 3], Issue.find(1).all_dependent_issues.collect(&:id).sort
778
  end
779 441:cbce1fd3b1b7 Chris
780
  def test_all_dependent_issues_with_persistent_multiple_circular_dependencies
781
    IssueRelation.delete_all
782
    assert IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(2), :relation_type => IssueRelation::TYPE_RELATES)
783
    assert IssueRelation.create!(:issue_from => Issue.find(2), :issue_to => Issue.find(3), :relation_type => IssueRelation::TYPE_RELATES)
784
    assert IssueRelation.create!(:issue_from => Issue.find(3), :issue_to => Issue.find(8), :relation_type => IssueRelation::TYPE_RELATES)
785
    # Validation skipping
786
    assert IssueRelation.new(:issue_from => Issue.find(8), :issue_to => Issue.find(2), :relation_type => IssueRelation::TYPE_RELATES).save(false)
787
    assert IssueRelation.new(:issue_from => Issue.find(3), :issue_to => Issue.find(1), :relation_type => IssueRelation::TYPE_RELATES).save(false)
788
789
    assert_equal [2, 3, 8], Issue.find(1).all_dependent_issues.collect(&:id).sort
790
  end
791
792 0:513646585e45 Chris
  context "#done_ratio" do
793
    setup do
794
      @issue = Issue.find(1)
795
      @issue_status = IssueStatus.find(1)
796
      @issue_status.update_attribute(:default_done_ratio, 50)
797 37:94944d00e43c chris
      @issue2 = Issue.find(2)
798
      @issue_status2 = IssueStatus.find(2)
799
      @issue_status2.update_attribute(:default_done_ratio, 0)
800 0:513646585e45 Chris
    end
801 441:cbce1fd3b1b7 Chris
802 0:513646585e45 Chris
    context "with Setting.issue_done_ratio using the issue_field" do
803
      setup do
804
        Setting.issue_done_ratio = 'issue_field'
805
      end
806 441:cbce1fd3b1b7 Chris
807 0:513646585e45 Chris
      should "read the issue's field" do
808
        assert_equal 0, @issue.done_ratio
809 37:94944d00e43c chris
        assert_equal 30, @issue2.done_ratio
810 0:513646585e45 Chris
      end
811
    end
812
813
    context "with Setting.issue_done_ratio using the issue_status" do
814
      setup do
815
        Setting.issue_done_ratio = 'issue_status'
816
      end
817 441:cbce1fd3b1b7 Chris
818 0:513646585e45 Chris
      should "read the Issue Status's default done ratio" do
819
        assert_equal 50, @issue.done_ratio
820 37:94944d00e43c chris
        assert_equal 0, @issue2.done_ratio
821 0:513646585e45 Chris
      end
822
    end
823
  end
824
825
  context "#update_done_ratio_from_issue_status" do
826
    setup do
827
      @issue = Issue.find(1)
828
      @issue_status = IssueStatus.find(1)
829
      @issue_status.update_attribute(:default_done_ratio, 50)
830 37:94944d00e43c chris
      @issue2 = Issue.find(2)
831
      @issue_status2 = IssueStatus.find(2)
832
      @issue_status2.update_attribute(:default_done_ratio, 0)
833 0:513646585e45 Chris
    end
834 441:cbce1fd3b1b7 Chris
835 0:513646585e45 Chris
    context "with Setting.issue_done_ratio using the issue_field" do
836
      setup do
837
        Setting.issue_done_ratio = 'issue_field'
838
      end
839 441:cbce1fd3b1b7 Chris
840 0:513646585e45 Chris
      should "not change the issue" do
841
        @issue.update_done_ratio_from_issue_status
842 37:94944d00e43c chris
        @issue2.update_done_ratio_from_issue_status
843 0:513646585e45 Chris
844 37:94944d00e43c chris
        assert_equal 0, @issue.read_attribute(:done_ratio)
845
        assert_equal 30, @issue2.read_attribute(:done_ratio)
846 0:513646585e45 Chris
      end
847
    end
848
849
    context "with Setting.issue_done_ratio using the issue_status" do
850
      setup do
851
        Setting.issue_done_ratio = 'issue_status'
852
      end
853 441:cbce1fd3b1b7 Chris
854 37:94944d00e43c chris
      should "change the issue's done ratio" do
855 0:513646585e45 Chris
        @issue.update_done_ratio_from_issue_status
856 37:94944d00e43c chris
        @issue2.update_done_ratio_from_issue_status
857 0:513646585e45 Chris
858 37:94944d00e43c chris
        assert_equal 50, @issue.read_attribute(:done_ratio)
859
        assert_equal 0, @issue2.read_attribute(:done_ratio)
860 0:513646585e45 Chris
      end
861
    end
862
  end
863
864
  test "#by_tracker" do
865 441:cbce1fd3b1b7 Chris
    User.current = User.anonymous
866 0:513646585e45 Chris
    groups = Issue.by_tracker(Project.find(1))
867
    assert_equal 3, groups.size
868
    assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i}
869
  end
870
871
  test "#by_version" do
872 441:cbce1fd3b1b7 Chris
    User.current = User.anonymous
873 0:513646585e45 Chris
    groups = Issue.by_version(Project.find(1))
874
    assert_equal 3, groups.size
875
    assert_equal 3, groups.inject(0) {|sum, group| sum + group['total'].to_i}
876
  end
877
878
  test "#by_priority" do
879 441:cbce1fd3b1b7 Chris
    User.current = User.anonymous
880 0:513646585e45 Chris
    groups = Issue.by_priority(Project.find(1))
881
    assert_equal 4, groups.size
882
    assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i}
883
  end
884
885
  test "#by_category" do
886 441:cbce1fd3b1b7 Chris
    User.current = User.anonymous
887 0:513646585e45 Chris
    groups = Issue.by_category(Project.find(1))
888
    assert_equal 2, groups.size
889
    assert_equal 3, groups.inject(0) {|sum, group| sum + group['total'].to_i}
890
  end
891
892
  test "#by_assigned_to" do
893 441:cbce1fd3b1b7 Chris
    User.current = User.anonymous
894 0:513646585e45 Chris
    groups = Issue.by_assigned_to(Project.find(1))
895
    assert_equal 2, groups.size
896
    assert_equal 2, groups.inject(0) {|sum, group| sum + group['total'].to_i}
897
  end
898
899
  test "#by_author" do
900 441:cbce1fd3b1b7 Chris
    User.current = User.anonymous
901 0:513646585e45 Chris
    groups = Issue.by_author(Project.find(1))
902
    assert_equal 4, groups.size
903
    assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i}
904
  end
905
906
  test "#by_subproject" do
907 441:cbce1fd3b1b7 Chris
    User.current = User.anonymous
908 0:513646585e45 Chris
    groups = Issue.by_subproject(Project.find(1))
909 441:cbce1fd3b1b7 Chris
    # Private descendant not visible
910
    assert_equal 1, groups.size
911
    assert_equal 2, groups.inject(0) {|sum, group| sum + group['total'].to_i}
912 0:513646585e45 Chris
  end
913 441:cbce1fd3b1b7 Chris
914 0:513646585e45 Chris
  context ".allowed_target_projects_on_move" do
915
    should "return all active projects for admin users" do
916
      User.current = User.find(1)
917
      assert_equal Project.active.count, Issue.allowed_target_projects_on_move.size
918
    end
919 441:cbce1fd3b1b7 Chris
920 0:513646585e45 Chris
    should "return allowed projects for non admin users" do
921
      User.current = User.find(2)
922
      Role.non_member.remove_permission! :move_issues
923
      assert_equal 3, Issue.allowed_target_projects_on_move.size
924 441:cbce1fd3b1b7 Chris
925 0:513646585e45 Chris
      Role.non_member.add_permission! :move_issues
926
      assert_equal Project.active.count, Issue.allowed_target_projects_on_move.size
927
    end
928
  end
929
930
  def test_recently_updated_with_limit_scopes
931
    #should return the last updated issue
932
    assert_equal 1, Issue.recently_updated.with_limit(1).length
933
    assert_equal Issue.find(:first, :order => "updated_on DESC"), Issue.recently_updated.with_limit(1).first
934
  end
935
936
  def test_on_active_projects_scope
937
    assert Project.find(2).archive
938 441:cbce1fd3b1b7 Chris
939 0:513646585e45 Chris
    before = Issue.on_active_project.length
940
    # test inclusion to results
941
    issue = Issue.generate_for_project!(Project.find(1), :tracker => Project.find(2).trackers.first)
942
    assert_equal before + 1, Issue.on_active_project.length
943
944
    # Move to an archived project
945
    issue.project = Project.find(2)
946
    assert issue.save
947
    assert_equal before, Issue.on_active_project.length
948
  end
949 37:94944d00e43c chris
950
  context "Issue#recipients" do
951
    setup do
952
      @project = Project.find(1)
953
      @author = User.generate_with_protected!
954
      @assignee = User.generate_with_protected!
955
      @issue = Issue.generate_for_project!(@project, :assigned_to => @assignee, :author => @author)
956
    end
957 441:cbce1fd3b1b7 Chris
958 37:94944d00e43c chris
    should "include project recipients" do
959
      assert @project.recipients.present?
960
      @project.recipients.each do |project_recipient|
961
        assert @issue.recipients.include?(project_recipient)
962
      end
963
    end
964
965
    should "include the author if the author is active" do
966
      assert @issue.author, "No author set for Issue"
967
      assert @issue.recipients.include?(@issue.author.mail)
968
    end
969 441:cbce1fd3b1b7 Chris
970 37:94944d00e43c chris
    should "include the assigned to user if the assigned to user is active" do
971
      assert @issue.assigned_to, "No assigned_to set for Issue"
972
      assert @issue.recipients.include?(@issue.assigned_to.mail)
973
    end
974
975
    should "not include users who opt out of all email" do
976
      @author.update_attribute(:mail_notification, :none)
977
978
      assert !@issue.recipients.include?(@issue.author.mail)
979
    end
980
981
    should "not include the issue author if they are only notified of assigned issues" do
982
      @author.update_attribute(:mail_notification, :only_assigned)
983
984
      assert !@issue.recipients.include?(@issue.author.mail)
985
    end
986
987
    should "not include the assigned user if they are only notified of owned issues" do
988
      @assignee.update_attribute(:mail_notification, :only_owner)
989
990
      assert !@issue.recipients.include?(@issue.assigned_to.mail)
991
    end
992
993
  end
994 0:513646585e45 Chris
end