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