comparison .svn/pristine/4b/4b6ad4ee97c77f142f2ea07d73404f963b296d82.svn-base @ 1296:038ba2d95de8 redmine-2.2

Fix redmine-2.2 branch update (add missing svn files)
author Chris Cannam
date Fri, 14 Jun 2013 09:05:06 +0100
parents
children
comparison
equal deleted inserted replaced
1294:3e4c3460b6ca 1296:038ba2d95de8
1 # Redmine - project management software
2 # Copyright (C) 2006-2012 Jean-Philippe Lang
3 #
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
18 require File.expand_path('../../test_helper', __FILE__)
19
20 class IssueTest < ActiveSupport::TestCase
21 fixtures :projects, :users, :members, :member_roles, :roles,
22 :groups_users,
23 :trackers, :projects_trackers,
24 :enabled_modules,
25 :versions,
26 :issue_statuses, :issue_categories, :issue_relations, :workflows,
27 :enumerations,
28 :issues, :journals, :journal_details,
29 :custom_fields, :custom_fields_projects, :custom_fields_trackers, :custom_values,
30 :time_entries
31
32 include Redmine::I18n
33
34 def teardown
35 User.current = nil
36 end
37
38 def test_create
39 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3,
40 :status_id => 1, :priority => IssuePriority.all.first,
41 :subject => 'test_create',
42 :description => 'IssueTest#test_create', :estimated_hours => '1:30')
43 assert issue.save
44 issue.reload
45 assert_equal 1.5, issue.estimated_hours
46 end
47
48 def test_create_minimal
49 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3,
50 :status_id => 1, :priority => IssuePriority.all.first,
51 :subject => 'test_create')
52 assert issue.save
53 assert issue.description.nil?
54 assert_nil issue.estimated_hours
55 end
56
57 def test_start_date_format_should_be_validated
58 set_language_if_valid 'en'
59 ['2012', 'ABC', '2012-15-20'].each do |invalid_date|
60 issue = Issue.new(:start_date => invalid_date)
61 assert !issue.valid?
62 assert_include 'Start date is not a valid date', issue.errors.full_messages, "No error found for invalid date #{invalid_date}"
63 end
64 end
65
66 def test_due_date_format_should_be_validated
67 set_language_if_valid 'en'
68 ['2012', 'ABC', '2012-15-20'].each do |invalid_date|
69 issue = Issue.new(:due_date => invalid_date)
70 assert !issue.valid?
71 assert_include 'Due date is not a valid date', issue.errors.full_messages, "No error found for invalid date #{invalid_date}"
72 end
73 end
74
75 def test_due_date_lesser_than_start_date_should_not_validate
76 set_language_if_valid 'en'
77 issue = Issue.new(:start_date => '2012-10-06', :due_date => '2012-10-02')
78 assert !issue.valid?
79 assert_include 'Due date must be greater than start date', issue.errors.full_messages
80 end
81
82 def test_create_with_required_custom_field
83 set_language_if_valid 'en'
84 field = IssueCustomField.find_by_name('Database')
85 field.update_attribute(:is_required, true)
86
87 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
88 :status_id => 1, :subject => 'test_create',
89 :description => 'IssueTest#test_create_with_required_custom_field')
90 assert issue.available_custom_fields.include?(field)
91 # No value for the custom field
92 assert !issue.save
93 assert_equal ["Database can't be blank"], issue.errors.full_messages
94 # Blank value
95 issue.custom_field_values = { field.id => '' }
96 assert !issue.save
97 assert_equal ["Database can't be blank"], issue.errors.full_messages
98 # Invalid value
99 issue.custom_field_values = { field.id => 'SQLServer' }
100 assert !issue.save
101 assert_equal ["Database is not included in the list"], issue.errors.full_messages
102 # Valid value
103 issue.custom_field_values = { field.id => 'PostgreSQL' }
104 assert issue.save
105 issue.reload
106 assert_equal 'PostgreSQL', issue.custom_value_for(field).value
107 end
108
109 def test_create_with_group_assignment
110 with_settings :issue_group_assignment => '1' do
111 assert Issue.new(:project_id => 2, :tracker_id => 1, :author_id => 1,
112 :subject => 'Group assignment',
113 :assigned_to_id => 11).save
114 issue = Issue.first(:order => 'id DESC')
115 assert_kind_of Group, issue.assigned_to
116 assert_equal Group.find(11), issue.assigned_to
117 end
118 end
119
120 def test_create_with_parent_issue_id
121 issue = Issue.new(:project_id => 1, :tracker_id => 1,
122 :author_id => 1, :subject => 'Group assignment',
123 :parent_issue_id => 1)
124 assert_save issue
125 assert_equal 1, issue.parent_issue_id
126 assert_equal Issue.find(1), issue.parent
127 end
128
129 def test_create_with_sharp_parent_issue_id
130 issue = Issue.new(:project_id => 1, :tracker_id => 1,
131 :author_id => 1, :subject => 'Group assignment',
132 :parent_issue_id => "#1")
133 assert_save issue
134 assert_equal 1, issue.parent_issue_id
135 assert_equal Issue.find(1), issue.parent
136 end
137
138 def test_create_with_invalid_parent_issue_id
139 set_language_if_valid 'en'
140 issue = Issue.new(:project_id => 1, :tracker_id => 1,
141 :author_id => 1, :subject => 'Group assignment',
142 :parent_issue_id => '01ABC')
143 assert !issue.save
144 assert_equal '01ABC', issue.parent_issue_id
145 assert_include 'Parent task is invalid', issue.errors.full_messages
146 end
147
148 def test_create_with_invalid_sharp_parent_issue_id
149 set_language_if_valid 'en'
150 issue = Issue.new(:project_id => 1, :tracker_id => 1,
151 :author_id => 1, :subject => 'Group assignment',
152 :parent_issue_id => '#01ABC')
153 assert !issue.save
154 assert_equal '#01ABC', issue.parent_issue_id
155 assert_include 'Parent task is invalid', issue.errors.full_messages
156 end
157
158 def assert_visibility_match(user, issues)
159 assert_equal issues.collect(&:id).sort, Issue.all.select {|issue| issue.visible?(user)}.collect(&:id).sort
160 end
161
162 def test_visible_scope_for_anonymous
163 # Anonymous user should see issues of public projects only
164 issues = Issue.visible(User.anonymous).all
165 assert issues.any?
166 assert_nil issues.detect {|issue| !issue.project.is_public?}
167 assert_nil issues.detect {|issue| issue.is_private?}
168 assert_visibility_match User.anonymous, issues
169 end
170
171 def test_visible_scope_for_anonymous_without_view_issues_permissions
172 # Anonymous user should not see issues without permission
173 Role.anonymous.remove_permission!(:view_issues)
174 issues = Issue.visible(User.anonymous).all
175 assert issues.empty?
176 assert_visibility_match User.anonymous, issues
177 end
178
179 def test_anonymous_should_not_see_private_issues_with_issues_visibility_set_to_default
180 assert Role.anonymous.update_attribute(:issues_visibility, 'default')
181 issue = Issue.generate!(:author => User.anonymous, :assigned_to => User.anonymous, :is_private => true)
182 assert_nil Issue.where(:id => issue.id).visible(User.anonymous).first
183 assert !issue.visible?(User.anonymous)
184 end
185
186 def test_anonymous_should_not_see_private_issues_with_issues_visibility_set_to_own
187 assert Role.anonymous.update_attribute(:issues_visibility, 'own')
188 issue = Issue.generate!(:author => User.anonymous, :assigned_to => User.anonymous, :is_private => true)
189 assert_nil Issue.where(:id => issue.id).visible(User.anonymous).first
190 assert !issue.visible?(User.anonymous)
191 end
192
193 def test_visible_scope_for_non_member
194 user = User.find(9)
195 assert user.projects.empty?
196 # Non member user should see issues of public projects only
197 issues = Issue.visible(user).all
198 assert issues.any?
199 assert_nil issues.detect {|issue| !issue.project.is_public?}
200 assert_nil issues.detect {|issue| issue.is_private?}
201 assert_visibility_match user, issues
202 end
203
204 def test_visible_scope_for_non_member_with_own_issues_visibility
205 Role.non_member.update_attribute :issues_visibility, 'own'
206 Issue.create!(:project_id => 1, :tracker_id => 1, :author_id => 9, :subject => 'Issue by non member')
207 user = User.find(9)
208
209 issues = Issue.visible(user).all
210 assert issues.any?
211 assert_nil issues.detect {|issue| issue.author != user}
212 assert_visibility_match user, issues
213 end
214
215 def test_visible_scope_for_non_member_without_view_issues_permissions
216 # Non member user should not see issues without permission
217 Role.non_member.remove_permission!(:view_issues)
218 user = User.find(9)
219 assert user.projects.empty?
220 issues = Issue.visible(user).all
221 assert issues.empty?
222 assert_visibility_match user, issues
223 end
224
225 def test_visible_scope_for_member
226 user = User.find(9)
227 # User should see issues of projects for which he has view_issues permissions only
228 Role.non_member.remove_permission!(:view_issues)
229 Member.create!(:principal => user, :project_id => 3, :role_ids => [2])
230 issues = Issue.visible(user).all
231 assert issues.any?
232 assert_nil issues.detect {|issue| issue.project_id != 3}
233 assert_nil issues.detect {|issue| issue.is_private?}
234 assert_visibility_match user, issues
235 end
236
237 def test_visible_scope_for_member_with_groups_should_return_assigned_issues
238 user = User.find(8)
239 assert user.groups.any?
240 Member.create!(:principal => user.groups.first, :project_id => 1, :role_ids => [2])
241 Role.non_member.remove_permission!(:view_issues)
242
243 issue = Issue.create(:project_id => 1, :tracker_id => 1, :author_id => 3,
244 :status_id => 1, :priority => IssuePriority.all.first,
245 :subject => 'Assignment test',
246 :assigned_to => user.groups.first,
247 :is_private => true)
248
249 Role.find(2).update_attribute :issues_visibility, 'default'
250 issues = Issue.visible(User.find(8)).all
251 assert issues.any?
252 assert issues.include?(issue)
253
254 Role.find(2).update_attribute :issues_visibility, 'own'
255 issues = Issue.visible(User.find(8)).all
256 assert issues.any?
257 assert issues.include?(issue)
258 end
259
260 def test_visible_scope_for_admin
261 user = User.find(1)
262 user.members.each(&:destroy)
263 assert user.projects.empty?
264 issues = Issue.visible(user).all
265 assert issues.any?
266 # Admin should see issues on private projects that he does not belong to
267 assert issues.detect {|issue| !issue.project.is_public?}
268 # Admin should see private issues of other users
269 assert issues.detect {|issue| issue.is_private? && issue.author != user}
270 assert_visibility_match user, issues
271 end
272
273 def test_visible_scope_with_project
274 project = Project.find(1)
275 issues = Issue.visible(User.find(2), :project => project).all
276 projects = issues.collect(&:project).uniq
277 assert_equal 1, projects.size
278 assert_equal project, projects.first
279 end
280
281 def test_visible_scope_with_project_and_subprojects
282 project = Project.find(1)
283 issues = Issue.visible(User.find(2), :project => project, :with_subprojects => true).all
284 projects = issues.collect(&:project).uniq
285 assert projects.size > 1
286 assert_equal [], projects.select {|p| !p.is_or_is_descendant_of?(project)}
287 end
288
289 def test_visible_and_nested_set_scopes
290 assert_equal 0, Issue.find(1).descendants.visible.all.size
291 end
292
293 def test_open_scope
294 issues = Issue.open.all
295 assert_nil issues.detect(&:closed?)
296 end
297
298 def test_open_scope_with_arg
299 issues = Issue.open(false).all
300 assert_equal issues, issues.select(&:closed?)
301 end
302
303 def test_errors_full_messages_should_include_custom_fields_errors
304 field = IssueCustomField.find_by_name('Database')
305
306 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
307 :status_id => 1, :subject => 'test_create',
308 :description => 'IssueTest#test_create_with_required_custom_field')
309 assert issue.available_custom_fields.include?(field)
310 # Invalid value
311 issue.custom_field_values = { field.id => 'SQLServer' }
312
313 assert !issue.valid?
314 assert_equal 1, issue.errors.full_messages.size
315 assert_equal "Database #{I18n.translate('activerecord.errors.messages.inclusion')}",
316 issue.errors.full_messages.first
317 end
318
319 def test_update_issue_with_required_custom_field
320 field = IssueCustomField.find_by_name('Database')
321 field.update_attribute(:is_required, true)
322
323 issue = Issue.find(1)
324 assert_nil issue.custom_value_for(field)
325 assert issue.available_custom_fields.include?(field)
326 # No change to custom values, issue can be saved
327 assert issue.save
328 # Blank value
329 issue.custom_field_values = { field.id => '' }
330 assert !issue.save
331 # Valid value
332 issue.custom_field_values = { field.id => 'PostgreSQL' }
333 assert issue.save
334 issue.reload
335 assert_equal 'PostgreSQL', issue.custom_value_for(field).value
336 end
337
338 def test_should_not_update_attributes_if_custom_fields_validation_fails
339 issue = Issue.find(1)
340 field = IssueCustomField.find_by_name('Database')
341 assert issue.available_custom_fields.include?(field)
342
343 issue.custom_field_values = { field.id => 'Invalid' }
344 issue.subject = 'Should be not be saved'
345 assert !issue.save
346
347 issue.reload
348 assert_equal "Can't print recipes", issue.subject
349 end
350
351 def test_should_not_recreate_custom_values_objects_on_update
352 field = IssueCustomField.find_by_name('Database')
353
354 issue = Issue.find(1)
355 issue.custom_field_values = { field.id => 'PostgreSQL' }
356 assert issue.save
357 custom_value = issue.custom_value_for(field)
358 issue.reload
359 issue.custom_field_values = { field.id => 'MySQL' }
360 assert issue.save
361 issue.reload
362 assert_equal custom_value.id, issue.custom_value_for(field).id
363 end
364
365 def test_should_not_update_custom_fields_on_changing_tracker_with_different_custom_fields
366 issue = Issue.create!(:project_id => 1, :tracker_id => 1, :author_id => 1,
367 :status_id => 1, :subject => 'Test',
368 :custom_field_values => {'2' => 'Test'})
369 assert !Tracker.find(2).custom_field_ids.include?(2)
370
371 issue = Issue.find(issue.id)
372 issue.attributes = {:tracker_id => 2, :custom_field_values => {'1' => ''}}
373
374 issue = Issue.find(issue.id)
375 custom_value = issue.custom_value_for(2)
376 assert_not_nil custom_value
377 assert_equal 'Test', custom_value.value
378 end
379
380 def test_assigning_tracker_id_should_reload_custom_fields_values
381 issue = Issue.new(:project => Project.find(1))
382 assert issue.custom_field_values.empty?
383 issue.tracker_id = 1
384 assert issue.custom_field_values.any?
385 end
386
387 def test_assigning_attributes_should_assign_project_and_tracker_first
388 seq = sequence('seq')
389 issue = Issue.new
390 issue.expects(:project_id=).in_sequence(seq)
391 issue.expects(:tracker_id=).in_sequence(seq)
392 issue.expects(:subject=).in_sequence(seq)
393 issue.attributes = {:tracker_id => 2, :project_id => 1, :subject => 'Test'}
394 end
395
396 def test_assigning_tracker_and_custom_fields_should_assign_custom_fields
397 attributes = ActiveSupport::OrderedHash.new
398 attributes['custom_field_values'] = { '1' => 'MySQL' }
399 attributes['tracker_id'] = '1'
400 issue = Issue.new(:project => Project.find(1))
401 issue.attributes = attributes
402 assert_equal 'MySQL', issue.custom_field_value(1)
403 end
404
405 def test_should_update_issue_with_disabled_tracker
406 p = Project.find(1)
407 issue = Issue.find(1)
408
409 p.trackers.delete(issue.tracker)
410 assert !p.trackers.include?(issue.tracker)
411
412 issue.reload
413 issue.subject = 'New subject'
414 assert issue.save
415 end
416
417 def test_should_not_set_a_disabled_tracker
418 p = Project.find(1)
419 p.trackers.delete(Tracker.find(2))
420
421 issue = Issue.find(1)
422 issue.tracker_id = 2
423 issue.subject = 'New subject'
424 assert !issue.save
425 assert_not_nil issue.errors[:tracker_id]
426 end
427
428 def test_category_based_assignment
429 issue = Issue.create(:project_id => 1, :tracker_id => 1, :author_id => 3,
430 :status_id => 1, :priority => IssuePriority.all.first,
431 :subject => 'Assignment test',
432 :description => 'Assignment test', :category_id => 1)
433 assert_equal IssueCategory.find(1).assigned_to, issue.assigned_to
434 end
435
436 def test_new_statuses_allowed_to
437 WorkflowTransition.delete_all
438 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
439 :old_status_id => 1, :new_status_id => 2,
440 :author => false, :assignee => false)
441 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
442 :old_status_id => 1, :new_status_id => 3,
443 :author => true, :assignee => false)
444 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1,
445 :new_status_id => 4, :author => false,
446 :assignee => true)
447 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
448 :old_status_id => 1, :new_status_id => 5,
449 :author => true, :assignee => true)
450 status = IssueStatus.find(1)
451 role = Role.find(1)
452 tracker = Tracker.find(1)
453 user = User.find(2)
454
455 issue = Issue.generate!(:tracker => tracker, :status => status,
456 :project_id => 1, :author_id => 1)
457 assert_equal [1, 2], issue.new_statuses_allowed_to(user).map(&:id)
458
459 issue = Issue.generate!(:tracker => tracker, :status => status,
460 :project_id => 1, :author => user)
461 assert_equal [1, 2, 3, 5], issue.new_statuses_allowed_to(user).map(&:id)
462
463 issue = Issue.generate!(:tracker => tracker, :status => status,
464 :project_id => 1, :author_id => 1,
465 :assigned_to => user)
466 assert_equal [1, 2, 4, 5], issue.new_statuses_allowed_to(user).map(&:id)
467
468 issue = Issue.generate!(:tracker => tracker, :status => status,
469 :project_id => 1, :author => user,
470 :assigned_to => user)
471 assert_equal [1, 2, 3, 4, 5], issue.new_statuses_allowed_to(user).map(&:id)
472 end
473
474 def test_new_statuses_allowed_to_should_return_all_transitions_for_admin
475 admin = User.find(1)
476 issue = Issue.find(1)
477 assert !admin.member_of?(issue.project)
478 expected_statuses = [issue.status] +
479 WorkflowTransition.find_all_by_old_status_id(
480 issue.status_id).map(&:new_status).uniq.sort
481 assert_equal expected_statuses, issue.new_statuses_allowed_to(admin)
482 end
483
484 def test_new_statuses_allowed_to_should_return_default_and_current_status_when_copying
485 issue = Issue.find(1).copy
486 assert_equal [1], issue.new_statuses_allowed_to(User.find(2)).map(&:id)
487
488 issue = Issue.find(2).copy
489 assert_equal [1, 2], issue.new_statuses_allowed_to(User.find(2)).map(&:id)
490 end
491
492 def test_safe_attributes_names_should_not_include_disabled_field
493 tracker = Tracker.new(:core_fields => %w(assigned_to_id fixed_version_id))
494
495 issue = Issue.new(:tracker => tracker)
496 assert_include 'tracker_id', issue.safe_attribute_names
497 assert_include 'status_id', issue.safe_attribute_names
498 assert_include 'subject', issue.safe_attribute_names
499 assert_include 'description', issue.safe_attribute_names
500 assert_include 'custom_field_values', issue.safe_attribute_names
501 assert_include 'custom_fields', issue.safe_attribute_names
502 assert_include 'lock_version', issue.safe_attribute_names
503
504 tracker.core_fields.each do |field|
505 assert_include field, issue.safe_attribute_names
506 end
507
508 tracker.disabled_core_fields.each do |field|
509 assert_not_include field, issue.safe_attribute_names
510 end
511 end
512
513 def test_safe_attributes_should_ignore_disabled_fields
514 tracker = Tracker.find(1)
515 tracker.core_fields = %w(assigned_to_id due_date)
516 tracker.save!
517
518 issue = Issue.new(:tracker => tracker)
519 issue.safe_attributes = {'start_date' => '2012-07-14', 'due_date' => '2012-07-14'}
520 assert_nil issue.start_date
521 assert_equal Date.parse('2012-07-14'), issue.due_date
522 end
523
524 def test_safe_attributes_should_accept_target_tracker_enabled_fields
525 source = Tracker.find(1)
526 source.core_fields = []
527 source.save!
528 target = Tracker.find(2)
529 target.core_fields = %w(assigned_to_id due_date)
530 target.save!
531
532 issue = Issue.new(:tracker => source)
533 issue.safe_attributes = {'tracker_id' => 2, 'due_date' => '2012-07-14'}
534 assert_equal target, issue.tracker
535 assert_equal Date.parse('2012-07-14'), issue.due_date
536 end
537
538 def test_safe_attributes_should_not_include_readonly_fields
539 WorkflowPermission.delete_all
540 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
541 :role_id => 1, :field_name => 'due_date',
542 :rule => 'readonly')
543 user = User.find(2)
544
545 issue = Issue.new(:project_id => 1, :tracker_id => 1)
546 assert_equal %w(due_date), issue.read_only_attribute_names(user)
547 assert_not_include 'due_date', issue.safe_attribute_names(user)
548
549 issue.send :safe_attributes=, {'start_date' => '2012-07-14', 'due_date' => '2012-07-14'}, user
550 assert_equal Date.parse('2012-07-14'), issue.start_date
551 assert_nil issue.due_date
552 end
553
554 def test_safe_attributes_should_not_include_readonly_custom_fields
555 cf1 = IssueCustomField.create!(:name => 'Writable field',
556 :field_format => 'string',
557 :is_for_all => true, :tracker_ids => [1])
558 cf2 = IssueCustomField.create!(:name => 'Readonly field',
559 :field_format => 'string',
560 :is_for_all => true, :tracker_ids => [1])
561 WorkflowPermission.delete_all
562 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
563 :role_id => 1, :field_name => cf2.id.to_s,
564 :rule => 'readonly')
565 user = User.find(2)
566 issue = Issue.new(:project_id => 1, :tracker_id => 1)
567 assert_equal [cf2.id.to_s], issue.read_only_attribute_names(user)
568 assert_not_include cf2.id.to_s, issue.safe_attribute_names(user)
569
570 issue.send :safe_attributes=, {'custom_field_values' => {
571 cf1.id.to_s => 'value1', cf2.id.to_s => 'value2'
572 }}, user
573 assert_equal 'value1', issue.custom_field_value(cf1)
574 assert_nil issue.custom_field_value(cf2)
575
576 issue.send :safe_attributes=, {'custom_fields' => [
577 {'id' => cf1.id.to_s, 'value' => 'valuea'},
578 {'id' => cf2.id.to_s, 'value' => 'valueb'}
579 ]}, user
580 assert_equal 'valuea', issue.custom_field_value(cf1)
581 assert_nil issue.custom_field_value(cf2)
582 end
583
584 def test_editable_custom_field_values_should_return_non_readonly_custom_values
585 cf1 = IssueCustomField.create!(:name => 'Writable field', :field_format => 'string',
586 :is_for_all => true, :tracker_ids => [1, 2])
587 cf2 = IssueCustomField.create!(:name => 'Readonly field', :field_format => 'string',
588 :is_for_all => true, :tracker_ids => [1, 2])
589 WorkflowPermission.delete_all
590 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, :role_id => 1,
591 :field_name => cf2.id.to_s, :rule => 'readonly')
592 user = User.find(2)
593
594 issue = Issue.new(:project_id => 1, :tracker_id => 1)
595 values = issue.editable_custom_field_values(user)
596 assert values.detect {|value| value.custom_field == cf1}
597 assert_nil values.detect {|value| value.custom_field == cf2}
598
599 issue.tracker_id = 2
600 values = issue.editable_custom_field_values(user)
601 assert values.detect {|value| value.custom_field == cf1}
602 assert values.detect {|value| value.custom_field == cf2}
603 end
604
605 def test_safe_attributes_should_accept_target_tracker_writable_fields
606 WorkflowPermission.delete_all
607 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
608 :role_id => 1, :field_name => 'due_date',
609 :rule => 'readonly')
610 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2,
611 :role_id => 1, :field_name => 'start_date',
612 :rule => 'readonly')
613 user = User.find(2)
614
615 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1)
616
617 issue.send :safe_attributes=, {'start_date' => '2012-07-12',
618 'due_date' => '2012-07-14'}, user
619 assert_equal Date.parse('2012-07-12'), issue.start_date
620 assert_nil issue.due_date
621
622 issue.send :safe_attributes=, {'start_date' => '2012-07-15',
623 'due_date' => '2012-07-16',
624 'tracker_id' => 2}, user
625 assert_equal Date.parse('2012-07-12'), issue.start_date
626 assert_equal Date.parse('2012-07-16'), issue.due_date
627 end
628
629 def test_safe_attributes_should_accept_target_status_writable_fields
630 WorkflowPermission.delete_all
631 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
632 :role_id => 1, :field_name => 'due_date',
633 :rule => 'readonly')
634 WorkflowPermission.create!(:old_status_id => 2, :tracker_id => 1,
635 :role_id => 1, :field_name => 'start_date',
636 :rule => 'readonly')
637 user = User.find(2)
638
639 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1)
640
641 issue.send :safe_attributes=, {'start_date' => '2012-07-12',
642 'due_date' => '2012-07-14'},
643 user
644 assert_equal Date.parse('2012-07-12'), issue.start_date
645 assert_nil issue.due_date
646
647 issue.send :safe_attributes=, {'start_date' => '2012-07-15',
648 'due_date' => '2012-07-16',
649 'status_id' => 2},
650 user
651 assert_equal Date.parse('2012-07-12'), issue.start_date
652 assert_equal Date.parse('2012-07-16'), issue.due_date
653 end
654
655 def test_required_attributes_should_be_validated
656 cf = IssueCustomField.create!(:name => 'Foo', :field_format => 'string',
657 :is_for_all => true, :tracker_ids => [1, 2])
658
659 WorkflowPermission.delete_all
660 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
661 :role_id => 1, :field_name => 'due_date',
662 :rule => 'required')
663 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
664 :role_id => 1, :field_name => 'category_id',
665 :rule => 'required')
666 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
667 :role_id => 1, :field_name => cf.id.to_s,
668 :rule => 'required')
669
670 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2,
671 :role_id => 1, :field_name => 'start_date',
672 :rule => 'required')
673 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2,
674 :role_id => 1, :field_name => cf.id.to_s,
675 :rule => 'required')
676 user = User.find(2)
677
678 issue = Issue.new(:project_id => 1, :tracker_id => 1,
679 :status_id => 1, :subject => 'Required fields',
680 :author => user)
681 assert_equal [cf.id.to_s, "category_id", "due_date"],
682 issue.required_attribute_names(user).sort
683 assert !issue.save, "Issue was saved"
684 assert_equal ["Category can't be blank", "Due date can't be blank", "Foo can't be blank"],
685 issue.errors.full_messages.sort
686
687 issue.tracker_id = 2
688 assert_equal [cf.id.to_s, "start_date"], issue.required_attribute_names(user).sort
689 assert !issue.save, "Issue was saved"
690 assert_equal ["Foo can't be blank", "Start date can't be blank"],
691 issue.errors.full_messages.sort
692
693 issue.start_date = Date.today
694 issue.custom_field_values = {cf.id.to_s => 'bar'}
695 assert issue.save
696 end
697
698 def test_required_attribute_names_for_multiple_roles_should_intersect_rules
699 WorkflowPermission.delete_all
700 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
701 :role_id => 1, :field_name => 'due_date',
702 :rule => 'required')
703 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
704 :role_id => 1, :field_name => 'start_date',
705 :rule => 'required')
706 user = User.find(2)
707 member = Member.find(1)
708 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1)
709
710 assert_equal %w(due_date start_date), issue.required_attribute_names(user).sort
711
712 member.role_ids = [1, 2]
713 member.save!
714 assert_equal [], issue.required_attribute_names(user.reload)
715
716 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
717 :role_id => 2, :field_name => 'due_date',
718 :rule => 'required')
719 assert_equal %w(due_date), issue.required_attribute_names(user)
720
721 member.role_ids = [1, 2, 3]
722 member.save!
723 assert_equal [], issue.required_attribute_names(user.reload)
724
725 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
726 :role_id => 2, :field_name => 'due_date',
727 :rule => 'readonly')
728 # required + readonly => required
729 assert_equal %w(due_date), issue.required_attribute_names(user)
730 end
731
732 def test_read_only_attribute_names_for_multiple_roles_should_intersect_rules
733 WorkflowPermission.delete_all
734 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
735 :role_id => 1, :field_name => 'due_date',
736 :rule => 'readonly')
737 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
738 :role_id => 1, :field_name => 'start_date',
739 :rule => 'readonly')
740 user = User.find(2)
741 member = Member.find(1)
742 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1)
743
744 assert_equal %w(due_date start_date), issue.read_only_attribute_names(user).sort
745
746 member.role_ids = [1, 2]
747 member.save!
748 assert_equal [], issue.read_only_attribute_names(user.reload)
749
750 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
751 :role_id => 2, :field_name => 'due_date',
752 :rule => 'readonly')
753 assert_equal %w(due_date), issue.read_only_attribute_names(user)
754 end
755
756 def test_copy
757 issue = Issue.new.copy_from(1)
758 assert issue.copy?
759 assert issue.save
760 issue.reload
761 orig = Issue.find(1)
762 assert_equal orig.subject, issue.subject
763 assert_equal orig.tracker, issue.tracker
764 assert_equal "125", issue.custom_value_for(2).value
765 end
766
767 def test_copy_should_copy_status
768 orig = Issue.find(8)
769 assert orig.status != IssueStatus.default
770
771 issue = Issue.new.copy_from(orig)
772 assert issue.save
773 issue.reload
774 assert_equal orig.status, issue.status
775 end
776
777 def test_copy_should_add_relation_with_copied_issue
778 copied = Issue.find(1)
779 issue = Issue.new.copy_from(copied)
780 assert issue.save
781 issue.reload
782
783 assert_equal 1, issue.relations.size
784 relation = issue.relations.first
785 assert_equal 'copied_to', relation.relation_type
786 assert_equal copied, relation.issue_from
787 assert_equal issue, relation.issue_to
788 end
789
790 def test_copy_should_copy_subtasks
791 issue = Issue.generate_with_descendants!
792
793 copy = issue.reload.copy
794 copy.author = User.find(7)
795 assert_difference 'Issue.count', 1+issue.descendants.count do
796 assert copy.save
797 end
798 copy.reload
799 assert_equal %w(Child1 Child2), copy.children.map(&:subject).sort
800 child_copy = copy.children.detect {|c| c.subject == 'Child1'}
801 assert_equal %w(Child11), child_copy.children.map(&:subject).sort
802 assert_equal copy.author, child_copy.author
803 end
804
805 def test_copy_should_copy_subtasks_to_target_project
806 issue = Issue.generate_with_descendants!
807
808 copy = issue.copy(:project_id => 3)
809 assert_difference 'Issue.count', 1+issue.descendants.count do
810 assert copy.save
811 end
812 assert_equal [3], copy.reload.descendants.map(&:project_id).uniq
813 end
814
815 def test_copy_should_not_copy_subtasks_twice_when_saving_twice
816 issue = Issue.generate_with_descendants!
817
818 copy = issue.reload.copy
819 assert_difference 'Issue.count', 1+issue.descendants.count do
820 assert copy.save
821 assert copy.save
822 end
823 end
824
825 def test_should_not_call_after_project_change_on_creation
826 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1,
827 :subject => 'Test', :author_id => 1)
828 issue.expects(:after_project_change).never
829 issue.save!
830 end
831
832 def test_should_not_call_after_project_change_on_update
833 issue = Issue.find(1)
834 issue.project = Project.find(1)
835 issue.subject = 'No project change'
836 issue.expects(:after_project_change).never
837 issue.save!
838 end
839
840 def test_should_call_after_project_change_on_project_change
841 issue = Issue.find(1)
842 issue.project = Project.find(2)
843 issue.expects(:after_project_change).once
844 issue.save!
845 end
846
847 def test_adding_journal_should_update_timestamp
848 issue = Issue.find(1)
849 updated_on_was = issue.updated_on
850
851 issue.init_journal(User.first, "Adding notes")
852 assert_difference 'Journal.count' do
853 assert issue.save
854 end
855 issue.reload
856
857 assert_not_equal updated_on_was, issue.updated_on
858 end
859
860 def test_should_close_duplicates
861 # Create 3 issues
862 issue1 = Issue.generate!
863 issue2 = Issue.generate!
864 issue3 = Issue.generate!
865
866 # 2 is a dupe of 1
867 IssueRelation.create!(:issue_from => issue2, :issue_to => issue1,
868 :relation_type => IssueRelation::TYPE_DUPLICATES)
869 # And 3 is a dupe of 2
870 IssueRelation.create!(:issue_from => issue3, :issue_to => issue2,
871 :relation_type => IssueRelation::TYPE_DUPLICATES)
872 # And 3 is a dupe of 1 (circular duplicates)
873 IssueRelation.create!(:issue_from => issue3, :issue_to => issue1,
874 :relation_type => IssueRelation::TYPE_DUPLICATES)
875
876 assert issue1.reload.duplicates.include?(issue2)
877
878 # Closing issue 1
879 issue1.init_journal(User.find(:first), "Closing issue1")
880 issue1.status = IssueStatus.find :first, :conditions => {:is_closed => true}
881 assert issue1.save
882 # 2 and 3 should be also closed
883 assert issue2.reload.closed?
884 assert issue3.reload.closed?
885 end
886
887 def test_should_not_close_duplicated_issue
888 issue1 = Issue.generate!
889 issue2 = Issue.generate!
890
891 # 2 is a dupe of 1
892 IssueRelation.create(:issue_from => issue2, :issue_to => issue1,
893 :relation_type => IssueRelation::TYPE_DUPLICATES)
894 # 2 is a dup of 1 but 1 is not a duplicate of 2
895 assert !issue2.reload.duplicates.include?(issue1)
896
897 # Closing issue 2
898 issue2.init_journal(User.find(:first), "Closing issue2")
899 issue2.status = IssueStatus.find :first, :conditions => {:is_closed => true}
900 assert issue2.save
901 # 1 should not be also closed
902 assert !issue1.reload.closed?
903 end
904
905 def test_assignable_versions
906 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
907 :status_id => 1, :fixed_version_id => 1,
908 :subject => 'New issue')
909 assert_equal ['open'], issue.assignable_versions.collect(&:status).uniq
910 end
911
912 def test_should_not_be_able_to_assign_a_new_issue_to_a_closed_version
913 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
914 :status_id => 1, :fixed_version_id => 1,
915 :subject => 'New issue')
916 assert !issue.save
917 assert_not_nil issue.errors[:fixed_version_id]
918 end
919
920 def test_should_not_be_able_to_assign_a_new_issue_to_a_locked_version
921 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
922 :status_id => 1, :fixed_version_id => 2,
923 :subject => 'New issue')
924 assert !issue.save
925 assert_not_nil issue.errors[:fixed_version_id]
926 end
927
928 def test_should_be_able_to_assign_a_new_issue_to_an_open_version
929 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
930 :status_id => 1, :fixed_version_id => 3,
931 :subject => 'New issue')
932 assert issue.save
933 end
934
935 def test_should_be_able_to_update_an_issue_assigned_to_a_closed_version
936 issue = Issue.find(11)
937 assert_equal 'closed', issue.fixed_version.status
938 issue.subject = 'Subject changed'
939 assert issue.save
940 end
941
942 def test_should_not_be_able_to_reopen_an_issue_assigned_to_a_closed_version
943 issue = Issue.find(11)
944 issue.status_id = 1
945 assert !issue.save
946 assert_not_nil issue.errors[:base]
947 end
948
949 def test_should_be_able_to_reopen_and_reassign_an_issue_assigned_to_a_closed_version
950 issue = Issue.find(11)
951 issue.status_id = 1
952 issue.fixed_version_id = 3
953 assert issue.save
954 end
955
956 def test_should_be_able_to_reopen_an_issue_assigned_to_a_locked_version
957 issue = Issue.find(12)
958 assert_equal 'locked', issue.fixed_version.status
959 issue.status_id = 1
960 assert issue.save
961 end
962
963 def test_should_not_be_able_to_keep_unshared_version_when_changing_project
964 issue = Issue.find(2)
965 assert_equal 2, issue.fixed_version_id
966 issue.project_id = 3
967 assert_nil issue.fixed_version_id
968 issue.fixed_version_id = 2
969 assert !issue.save
970 assert_include 'Target version is not included in the list', issue.errors.full_messages
971 end
972
973 def test_should_keep_shared_version_when_changing_project
974 Version.find(2).update_attribute :sharing, 'tree'
975
976 issue = Issue.find(2)
977 assert_equal 2, issue.fixed_version_id
978 issue.project_id = 3
979 assert_equal 2, issue.fixed_version_id
980 assert issue.save
981 end
982
983 def test_allowed_target_projects_on_move_should_include_projects_with_issue_tracking_enabled
984 assert_include Project.find(2), Issue.allowed_target_projects_on_move(User.find(2))
985 end
986
987 def test_allowed_target_projects_on_move_should_not_include_projects_with_issue_tracking_disabled
988 Project.find(2).disable_module! :issue_tracking
989 assert_not_include Project.find(2), Issue.allowed_target_projects_on_move(User.find(2))
990 end
991
992 def test_move_to_another_project_with_same_category
993 issue = Issue.find(1)
994 issue.project = Project.find(2)
995 assert issue.save
996 issue.reload
997 assert_equal 2, issue.project_id
998 # Category changes
999 assert_equal 4, issue.category_id
1000 # Make sure time entries were move to the target project
1001 assert_equal 2, issue.time_entries.first.project_id
1002 end
1003
1004 def test_move_to_another_project_without_same_category
1005 issue = Issue.find(2)
1006 issue.project = Project.find(2)
1007 assert issue.save
1008 issue.reload
1009 assert_equal 2, issue.project_id
1010 # Category cleared
1011 assert_nil issue.category_id
1012 end
1013
1014 def test_move_to_another_project_should_clear_fixed_version_when_not_shared
1015 issue = Issue.find(1)
1016 issue.update_attribute(:fixed_version_id, 1)
1017 issue.project = Project.find(2)
1018 assert issue.save
1019 issue.reload
1020 assert_equal 2, issue.project_id
1021 # Cleared fixed_version
1022 assert_equal nil, issue.fixed_version
1023 end
1024
1025 def test_move_to_another_project_should_keep_fixed_version_when_shared_with_the_target_project
1026 issue = Issue.find(1)
1027 issue.update_attribute(:fixed_version_id, 4)
1028 issue.project = Project.find(5)
1029 assert issue.save
1030 issue.reload
1031 assert_equal 5, issue.project_id
1032 # Keep fixed_version
1033 assert_equal 4, issue.fixed_version_id
1034 end
1035
1036 def test_move_to_another_project_should_clear_fixed_version_when_not_shared_with_the_target_project
1037 issue = Issue.find(1)
1038 issue.update_attribute(:fixed_version_id, 1)
1039 issue.project = Project.find(5)
1040 assert issue.save
1041 issue.reload
1042 assert_equal 5, issue.project_id
1043 # Cleared fixed_version
1044 assert_equal nil, issue.fixed_version
1045 end
1046
1047 def test_move_to_another_project_should_keep_fixed_version_when_shared_systemwide
1048 issue = Issue.find(1)
1049 issue.update_attribute(:fixed_version_id, 7)
1050 issue.project = Project.find(2)
1051 assert issue.save
1052 issue.reload
1053 assert_equal 2, issue.project_id
1054 # Keep fixed_version
1055 assert_equal 7, issue.fixed_version_id
1056 end
1057
1058 def test_move_to_another_project_should_keep_parent_if_valid
1059 issue = Issue.find(1)
1060 issue.update_attribute(:parent_issue_id, 2)
1061 issue.project = Project.find(3)
1062 assert issue.save
1063 issue.reload
1064 assert_equal 2, issue.parent_id
1065 end
1066
1067 def test_move_to_another_project_should_clear_parent_if_not_valid
1068 issue = Issue.find(1)
1069 issue.update_attribute(:parent_issue_id, 2)
1070 issue.project = Project.find(2)
1071 assert issue.save
1072 issue.reload
1073 assert_nil issue.parent_id
1074 end
1075
1076 def test_move_to_another_project_with_disabled_tracker
1077 issue = Issue.find(1)
1078 target = Project.find(2)
1079 target.tracker_ids = [3]
1080 target.save
1081 issue.project = target
1082 assert issue.save
1083 issue.reload
1084 assert_equal 2, issue.project_id
1085 assert_equal 3, issue.tracker_id
1086 end
1087
1088 def test_copy_to_the_same_project
1089 issue = Issue.find(1)
1090 copy = issue.copy
1091 assert_difference 'Issue.count' do
1092 copy.save!
1093 end
1094 assert_kind_of Issue, copy
1095 assert_equal issue.project, copy.project
1096 assert_equal "125", copy.custom_value_for(2).value
1097 end
1098
1099 def test_copy_to_another_project_and_tracker
1100 issue = Issue.find(1)
1101 copy = issue.copy(:project_id => 3, :tracker_id => 2)
1102 assert_difference 'Issue.count' do
1103 copy.save!
1104 end
1105 copy.reload
1106 assert_kind_of Issue, copy
1107 assert_equal Project.find(3), copy.project
1108 assert_equal Tracker.find(2), copy.tracker
1109 # Custom field #2 is not associated with target tracker
1110 assert_nil copy.custom_value_for(2)
1111 end
1112
1113 context "#copy" do
1114 setup do
1115 @issue = Issue.find(1)
1116 end
1117
1118 should "not create a journal" do
1119 copy = @issue.copy(:project_id => 3, :tracker_id => 2, :assigned_to_id => 3)
1120 copy.save!
1121 assert_equal 0, copy.reload.journals.size
1122 end
1123
1124 should "allow assigned_to changes" do
1125 copy = @issue.copy(:project_id => 3, :tracker_id => 2, :assigned_to_id => 3)
1126 assert_equal 3, copy.assigned_to_id
1127 end
1128
1129 should "allow status changes" do
1130 copy = @issue.copy(:project_id => 3, :tracker_id => 2, :status_id => 2)
1131 assert_equal 2, copy.status_id
1132 end
1133
1134 should "allow start date changes" do
1135 date = Date.today
1136 copy = @issue.copy(:project_id => 3, :tracker_id => 2, :start_date => date)
1137 assert_equal date, copy.start_date
1138 end
1139
1140 should "allow due date changes" do
1141 date = Date.today
1142 copy = @issue.copy(:project_id => 3, :tracker_id => 2, :due_date => date)
1143 assert_equal date, copy.due_date
1144 end
1145
1146 should "set current user as author" do
1147 User.current = User.find(9)
1148 copy = @issue.copy(:project_id => 3, :tracker_id => 2)
1149 assert_equal User.current, copy.author
1150 end
1151
1152 should "create a journal with notes" do
1153 date = Date.today
1154 notes = "Notes added when copying"
1155 copy = @issue.copy(:project_id => 3, :tracker_id => 2, :start_date => date)
1156 copy.init_journal(User.current, notes)
1157 copy.save!
1158
1159 assert_equal 1, copy.journals.size
1160 journal = copy.journals.first
1161 assert_equal 0, journal.details.size
1162 assert_equal notes, journal.notes
1163 end
1164 end
1165
1166 def test_valid_parent_project
1167 issue = Issue.find(1)
1168 issue_in_same_project = Issue.find(2)
1169 issue_in_child_project = Issue.find(5)
1170 issue_in_grandchild_project = Issue.generate!(:project_id => 6, :tracker_id => 1)
1171 issue_in_other_child_project = Issue.find(6)
1172 issue_in_different_tree = Issue.find(4)
1173
1174 with_settings :cross_project_subtasks => '' do
1175 assert_equal true, issue.valid_parent_project?(issue_in_same_project)
1176 assert_equal false, issue.valid_parent_project?(issue_in_child_project)
1177 assert_equal false, issue.valid_parent_project?(issue_in_grandchild_project)
1178 assert_equal false, issue.valid_parent_project?(issue_in_different_tree)
1179 end
1180
1181 with_settings :cross_project_subtasks => 'system' do
1182 assert_equal true, issue.valid_parent_project?(issue_in_same_project)
1183 assert_equal true, issue.valid_parent_project?(issue_in_child_project)
1184 assert_equal true, issue.valid_parent_project?(issue_in_different_tree)
1185 end
1186
1187 with_settings :cross_project_subtasks => 'tree' do
1188 assert_equal true, issue.valid_parent_project?(issue_in_same_project)
1189 assert_equal true, issue.valid_parent_project?(issue_in_child_project)
1190 assert_equal true, issue.valid_parent_project?(issue_in_grandchild_project)
1191 assert_equal false, issue.valid_parent_project?(issue_in_different_tree)
1192
1193 assert_equal true, issue_in_child_project.valid_parent_project?(issue_in_same_project)
1194 assert_equal true, issue_in_child_project.valid_parent_project?(issue_in_other_child_project)
1195 end
1196
1197 with_settings :cross_project_subtasks => 'descendants' do
1198 assert_equal true, issue.valid_parent_project?(issue_in_same_project)
1199 assert_equal false, issue.valid_parent_project?(issue_in_child_project)
1200 assert_equal false, issue.valid_parent_project?(issue_in_grandchild_project)
1201 assert_equal false, issue.valid_parent_project?(issue_in_different_tree)
1202
1203 assert_equal true, issue_in_child_project.valid_parent_project?(issue)
1204 assert_equal false, issue_in_child_project.valid_parent_project?(issue_in_other_child_project)
1205 end
1206 end
1207
1208 def test_recipients_should_include_previous_assignee
1209 user = User.find(3)
1210 user.members.update_all ["mail_notification = ?", false]
1211 user.update_attribute :mail_notification, 'only_assigned'
1212
1213 issue = Issue.find(2)
1214 issue.assigned_to = nil
1215 assert_include user.mail, issue.recipients
1216 issue.save!
1217 assert !issue.recipients.include?(user.mail)
1218 end
1219
1220 def test_recipients_should_not_include_users_that_cannot_view_the_issue
1221 issue = Issue.find(12)
1222 assert issue.recipients.include?(issue.author.mail)
1223 # copy the issue to a private project
1224 copy = issue.copy(:project_id => 5, :tracker_id => 2)
1225 # author is not a member of project anymore
1226 assert !copy.recipients.include?(copy.author.mail)
1227 end
1228
1229 def test_recipients_should_include_the_assigned_group_members
1230 group_member = User.generate!
1231 group = Group.generate!
1232 group.users << group_member
1233
1234 issue = Issue.find(12)
1235 issue.assigned_to = group
1236 assert issue.recipients.include?(group_member.mail)
1237 end
1238
1239 def test_watcher_recipients_should_not_include_users_that_cannot_view_the_issue
1240 user = User.find(3)
1241 issue = Issue.find(9)
1242 Watcher.create!(:user => user, :watchable => issue)
1243 assert issue.watched_by?(user)
1244 assert !issue.watcher_recipients.include?(user.mail)
1245 end
1246
1247 def test_issue_destroy
1248 Issue.find(1).destroy
1249 assert_nil Issue.find_by_id(1)
1250 assert_nil TimeEntry.find_by_issue_id(1)
1251 end
1252
1253 def test_destroying_a_deleted_issue_should_not_raise_an_error
1254 issue = Issue.find(1)
1255 Issue.find(1).destroy
1256
1257 assert_nothing_raised do
1258 assert_no_difference 'Issue.count' do
1259 issue.destroy
1260 end
1261 assert issue.destroyed?
1262 end
1263 end
1264
1265 def test_destroying_a_stale_issue_should_not_raise_an_error
1266 issue = Issue.find(1)
1267 Issue.find(1).update_attribute :subject, "Updated"
1268
1269 assert_nothing_raised do
1270 assert_difference 'Issue.count', -1 do
1271 issue.destroy
1272 end
1273 assert issue.destroyed?
1274 end
1275 end
1276
1277 def test_blocked
1278 blocked_issue = Issue.find(9)
1279 blocking_issue = Issue.find(10)
1280
1281 assert blocked_issue.blocked?
1282 assert !blocking_issue.blocked?
1283 end
1284
1285 def test_blocked_issues_dont_allow_closed_statuses
1286 blocked_issue = Issue.find(9)
1287
1288 allowed_statuses = blocked_issue.new_statuses_allowed_to(users(:users_002))
1289 assert !allowed_statuses.empty?
1290 closed_statuses = allowed_statuses.select {|st| st.is_closed?}
1291 assert closed_statuses.empty?
1292 end
1293
1294 def test_unblocked_issues_allow_closed_statuses
1295 blocking_issue = Issue.find(10)
1296
1297 allowed_statuses = blocking_issue.new_statuses_allowed_to(users(:users_002))
1298 assert !allowed_statuses.empty?
1299 closed_statuses = allowed_statuses.select {|st| st.is_closed?}
1300 assert !closed_statuses.empty?
1301 end
1302
1303 def test_reschedule_an_issue_without_dates
1304 with_settings :non_working_week_days => [] do
1305 issue = Issue.new(:start_date => nil, :due_date => nil)
1306 issue.reschedule_on '2012-10-09'.to_date
1307 assert_equal '2012-10-09'.to_date, issue.start_date
1308 assert_equal '2012-10-09'.to_date, issue.due_date
1309 end
1310
1311 with_settings :non_working_week_days => %w(6 7) do
1312 issue = Issue.new(:start_date => nil, :due_date => nil)
1313 issue.reschedule_on '2012-10-09'.to_date
1314 assert_equal '2012-10-09'.to_date, issue.start_date
1315 assert_equal '2012-10-09'.to_date, issue.due_date
1316
1317 issue = Issue.new(:start_date => nil, :due_date => nil)
1318 issue.reschedule_on '2012-10-13'.to_date
1319 assert_equal '2012-10-15'.to_date, issue.start_date
1320 assert_equal '2012-10-15'.to_date, issue.due_date
1321 end
1322 end
1323
1324 def test_reschedule_an_issue_with_start_date
1325 with_settings :non_working_week_days => [] do
1326 issue = Issue.new(:start_date => '2012-10-09', :due_date => nil)
1327 issue.reschedule_on '2012-10-13'.to_date
1328 assert_equal '2012-10-13'.to_date, issue.start_date
1329 assert_equal '2012-10-13'.to_date, issue.due_date
1330 end
1331
1332 with_settings :non_working_week_days => %w(6 7) do
1333 issue = Issue.new(:start_date => '2012-10-09', :due_date => nil)
1334 issue.reschedule_on '2012-10-11'.to_date
1335 assert_equal '2012-10-11'.to_date, issue.start_date
1336 assert_equal '2012-10-11'.to_date, issue.due_date
1337
1338 issue = Issue.new(:start_date => '2012-10-09', :due_date => nil)
1339 issue.reschedule_on '2012-10-13'.to_date
1340 assert_equal '2012-10-15'.to_date, issue.start_date
1341 assert_equal '2012-10-15'.to_date, issue.due_date
1342 end
1343 end
1344
1345 def test_reschedule_an_issue_with_start_and_due_dates
1346 with_settings :non_working_week_days => [] do
1347 issue = Issue.new(:start_date => '2012-10-09', :due_date => '2012-10-15')
1348 issue.reschedule_on '2012-10-13'.to_date
1349 assert_equal '2012-10-13'.to_date, issue.start_date
1350 assert_equal '2012-10-19'.to_date, issue.due_date
1351 end
1352
1353 with_settings :non_working_week_days => %w(6 7) do
1354 issue = Issue.new(:start_date => '2012-10-09', :due_date => '2012-10-19') # 8 working days
1355 issue.reschedule_on '2012-10-11'.to_date
1356 assert_equal '2012-10-11'.to_date, issue.start_date
1357 assert_equal '2012-10-23'.to_date, issue.due_date
1358
1359 issue = Issue.new(:start_date => '2012-10-09', :due_date => '2012-10-19')
1360 issue.reschedule_on '2012-10-13'.to_date
1361 assert_equal '2012-10-15'.to_date, issue.start_date
1362 assert_equal '2012-10-25'.to_date, issue.due_date
1363 end
1364 end
1365
1366 def test_rescheduling_an_issue_to_a_later_due_date_should_reschedule_following_issue
1367 issue1 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1368 issue2 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1369 IssueRelation.create!(:issue_from => issue1, :issue_to => issue2,
1370 :relation_type => IssueRelation::TYPE_PRECEDES)
1371 assert_equal Date.parse('2012-10-18'), issue2.reload.start_date
1372
1373 issue1.due_date = '2012-10-23'
1374 issue1.save!
1375 issue2.reload
1376 assert_equal Date.parse('2012-10-24'), issue2.start_date
1377 assert_equal Date.parse('2012-10-26'), issue2.due_date
1378 end
1379
1380 def test_rescheduling_an_issue_to_an_earlier_due_date_should_reschedule_following_issue
1381 issue1 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1382 issue2 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1383 IssueRelation.create!(:issue_from => issue1, :issue_to => issue2,
1384 :relation_type => IssueRelation::TYPE_PRECEDES)
1385 assert_equal Date.parse('2012-10-18'), issue2.reload.start_date
1386
1387 issue1.start_date = '2012-09-17'
1388 issue1.due_date = '2012-09-18'
1389 issue1.save!
1390 issue2.reload
1391 assert_equal Date.parse('2012-09-19'), issue2.start_date
1392 assert_equal Date.parse('2012-09-21'), issue2.due_date
1393 end
1394
1395 def test_rescheduling_reschedule_following_issue_earlier_should_consider_other_preceding_issues
1396 issue1 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1397 issue2 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1398 issue3 = Issue.generate!(:start_date => '2012-10-01', :due_date => '2012-10-02')
1399 IssueRelation.create!(:issue_from => issue1, :issue_to => issue2,
1400 :relation_type => IssueRelation::TYPE_PRECEDES)
1401 IssueRelation.create!(:issue_from => issue3, :issue_to => issue2,
1402 :relation_type => IssueRelation::TYPE_PRECEDES)
1403 assert_equal Date.parse('2012-10-18'), issue2.reload.start_date
1404
1405 issue1.start_date = '2012-09-17'
1406 issue1.due_date = '2012-09-18'
1407 issue1.save!
1408 issue2.reload
1409 # Issue 2 must start after Issue 3
1410 assert_equal Date.parse('2012-10-03'), issue2.start_date
1411 assert_equal Date.parse('2012-10-05'), issue2.due_date
1412 end
1413
1414 def test_rescheduling_a_stale_issue_should_not_raise_an_error
1415 with_settings :non_working_week_days => [] do
1416 stale = Issue.find(1)
1417 issue = Issue.find(1)
1418 issue.subject = "Updated"
1419 issue.save!
1420 date = 10.days.from_now.to_date
1421 assert_nothing_raised do
1422 stale.reschedule_on!(date)
1423 end
1424 assert_equal date, stale.reload.start_date
1425 end
1426 end
1427
1428 def test_overdue
1429 assert Issue.new(:due_date => 1.day.ago.to_date).overdue?
1430 assert !Issue.new(:due_date => Date.today).overdue?
1431 assert !Issue.new(:due_date => 1.day.from_now.to_date).overdue?
1432 assert !Issue.new(:due_date => nil).overdue?
1433 assert !Issue.new(:due_date => 1.day.ago.to_date,
1434 :status => IssueStatus.find(:first,
1435 :conditions => {:is_closed => true})
1436 ).overdue?
1437 end
1438
1439 context "#behind_schedule?" do
1440 should "be false if the issue has no start_date" do
1441 assert !Issue.new(:start_date => nil,
1442 :due_date => 1.day.from_now.to_date,
1443 :done_ratio => 0).behind_schedule?
1444 end
1445
1446 should "be false if the issue has no end_date" do
1447 assert !Issue.new(:start_date => 1.day.from_now.to_date,
1448 :due_date => nil,
1449 :done_ratio => 0).behind_schedule?
1450 end
1451
1452 should "be false if the issue has more done than it's calendar time" do
1453 assert !Issue.new(:start_date => 50.days.ago.to_date,
1454 :due_date => 50.days.from_now.to_date,
1455 :done_ratio => 90).behind_schedule?
1456 end
1457
1458 should "be true if the issue hasn't been started at all" do
1459 assert Issue.new(:start_date => 1.day.ago.to_date,
1460 :due_date => 1.day.from_now.to_date,
1461 :done_ratio => 0).behind_schedule?
1462 end
1463
1464 should "be true if the issue has used more calendar time than it's done ratio" do
1465 assert Issue.new(:start_date => 100.days.ago.to_date,
1466 :due_date => Date.today,
1467 :done_ratio => 90).behind_schedule?
1468 end
1469 end
1470
1471 context "#assignable_users" do
1472 should "be Users" do
1473 assert_kind_of User, Issue.find(1).assignable_users.first
1474 end
1475
1476 should "include the issue author" do
1477 non_project_member = User.generate!
1478 issue = Issue.generate!(:author => non_project_member)
1479
1480 assert issue.assignable_users.include?(non_project_member)
1481 end
1482
1483 should "include the current assignee" do
1484 user = User.generate!
1485 issue = Issue.generate!(:assigned_to => user)
1486 user.lock!
1487
1488 assert Issue.find(issue.id).assignable_users.include?(user)
1489 end
1490
1491 should "not show the issue author twice" do
1492 assignable_user_ids = Issue.find(1).assignable_users.collect(&:id)
1493 assert_equal 2, assignable_user_ids.length
1494
1495 assignable_user_ids.each do |user_id|
1496 assert_equal 1, assignable_user_ids.select {|i| i == user_id}.length,
1497 "User #{user_id} appears more or less than once"
1498 end
1499 end
1500
1501 context "with issue_group_assignment" do
1502 should "include groups" do
1503 issue = Issue.new(:project => Project.find(2))
1504
1505 with_settings :issue_group_assignment => '1' do
1506 assert_equal %w(Group User), issue.assignable_users.map {|a| a.class.name}.uniq.sort
1507 assert issue.assignable_users.include?(Group.find(11))
1508 end
1509 end
1510 end
1511
1512 context "without issue_group_assignment" do
1513 should "not include groups" do
1514 issue = Issue.new(:project => Project.find(2))
1515
1516 with_settings :issue_group_assignment => '0' do
1517 assert_equal %w(User), issue.assignable_users.map {|a| a.class.name}.uniq.sort
1518 assert !issue.assignable_users.include?(Group.find(11))
1519 end
1520 end
1521 end
1522 end
1523
1524 def test_create_should_send_email_notification
1525 ActionMailer::Base.deliveries.clear
1526 issue = Issue.new(:project_id => 1, :tracker_id => 1,
1527 :author_id => 3, :status_id => 1,
1528 :priority => IssuePriority.all.first,
1529 :subject => 'test_create', :estimated_hours => '1:30')
1530
1531 assert issue.save
1532 assert_equal 1, ActionMailer::Base.deliveries.size
1533 end
1534
1535 def test_stale_issue_should_not_send_email_notification
1536 ActionMailer::Base.deliveries.clear
1537 issue = Issue.find(1)
1538 stale = Issue.find(1)
1539
1540 issue.init_journal(User.find(1))
1541 issue.subject = 'Subjet update'
1542 assert issue.save
1543 assert_equal 1, ActionMailer::Base.deliveries.size
1544 ActionMailer::Base.deliveries.clear
1545
1546 stale.init_journal(User.find(1))
1547 stale.subject = 'Another subjet update'
1548 assert_raise ActiveRecord::StaleObjectError do
1549 stale.save
1550 end
1551 assert ActionMailer::Base.deliveries.empty?
1552 end
1553
1554 def test_journalized_description
1555 IssueCustomField.delete_all
1556
1557 i = Issue.first
1558 old_description = i.description
1559 new_description = "This is the new description"
1560
1561 i.init_journal(User.find(2))
1562 i.description = new_description
1563 assert_difference 'Journal.count', 1 do
1564 assert_difference 'JournalDetail.count', 1 do
1565 i.save!
1566 end
1567 end
1568
1569 detail = JournalDetail.first(:order => 'id DESC')
1570 assert_equal i, detail.journal.journalized
1571 assert_equal 'attr', detail.property
1572 assert_equal 'description', detail.prop_key
1573 assert_equal old_description, detail.old_value
1574 assert_equal new_description, detail.value
1575 end
1576
1577 def test_blank_descriptions_should_not_be_journalized
1578 IssueCustomField.delete_all
1579 Issue.update_all("description = NULL", "id=1")
1580
1581 i = Issue.find(1)
1582 i.init_journal(User.find(2))
1583 i.subject = "blank description"
1584 i.description = "\r\n"
1585
1586 assert_difference 'Journal.count', 1 do
1587 assert_difference 'JournalDetail.count', 1 do
1588 i.save!
1589 end
1590 end
1591 end
1592
1593 def test_journalized_multi_custom_field
1594 field = IssueCustomField.create!(:name => 'filter', :field_format => 'list',
1595 :is_filter => true, :is_for_all => true,
1596 :tracker_ids => [1],
1597 :possible_values => ['value1', 'value2', 'value3'],
1598 :multiple => true)
1599
1600 issue = Issue.create!(:project_id => 1, :tracker_id => 1,
1601 :subject => 'Test', :author_id => 1)
1602
1603 assert_difference 'Journal.count' do
1604 assert_difference 'JournalDetail.count' do
1605 issue.init_journal(User.first)
1606 issue.custom_field_values = {field.id => ['value1']}
1607 issue.save!
1608 end
1609 assert_difference 'JournalDetail.count' do
1610 issue.init_journal(User.first)
1611 issue.custom_field_values = {field.id => ['value1', 'value2']}
1612 issue.save!
1613 end
1614 assert_difference 'JournalDetail.count', 2 do
1615 issue.init_journal(User.first)
1616 issue.custom_field_values = {field.id => ['value3', 'value2']}
1617 issue.save!
1618 end
1619 assert_difference 'JournalDetail.count', 2 do
1620 issue.init_journal(User.first)
1621 issue.custom_field_values = {field.id => nil}
1622 issue.save!
1623 end
1624 end
1625 end
1626
1627 def test_description_eol_should_be_normalized
1628 i = Issue.new(:description => "CR \r LF \n CRLF \r\n")
1629 assert_equal "CR \r\n LF \r\n CRLF \r\n", i.description
1630 end
1631
1632 def test_saving_twice_should_not_duplicate_journal_details
1633 i = Issue.find(:first)
1634 i.init_journal(User.find(2), 'Some notes')
1635 # initial changes
1636 i.subject = 'New subject'
1637 i.done_ratio = i.done_ratio + 10
1638 assert_difference 'Journal.count' do
1639 assert i.save
1640 end
1641 # 1 more change
1642 i.priority = IssuePriority.find(:first, :conditions => ["id <> ?", i.priority_id])
1643 assert_no_difference 'Journal.count' do
1644 assert_difference 'JournalDetail.count', 1 do
1645 i.save
1646 end
1647 end
1648 # no more change
1649 assert_no_difference 'Journal.count' do
1650 assert_no_difference 'JournalDetail.count' do
1651 i.save
1652 end
1653 end
1654 end
1655
1656 def test_all_dependent_issues
1657 IssueRelation.delete_all
1658 assert IssueRelation.create!(:issue_from => Issue.find(1),
1659 :issue_to => Issue.find(2),
1660 :relation_type => IssueRelation::TYPE_PRECEDES)
1661 assert IssueRelation.create!(:issue_from => Issue.find(2),
1662 :issue_to => Issue.find(3),
1663 :relation_type => IssueRelation::TYPE_PRECEDES)
1664 assert IssueRelation.create!(:issue_from => Issue.find(3),
1665 :issue_to => Issue.find(8),
1666 :relation_type => IssueRelation::TYPE_PRECEDES)
1667
1668 assert_equal [2, 3, 8], Issue.find(1).all_dependent_issues.collect(&:id).sort
1669 end
1670
1671 def test_all_dependent_issues_with_persistent_circular_dependency
1672 IssueRelation.delete_all
1673 assert IssueRelation.create!(:issue_from => Issue.find(1),
1674 :issue_to => Issue.find(2),
1675 :relation_type => IssueRelation::TYPE_PRECEDES)
1676 assert IssueRelation.create!(:issue_from => Issue.find(2),
1677 :issue_to => Issue.find(3),
1678 :relation_type => IssueRelation::TYPE_PRECEDES)
1679
1680 r = IssueRelation.create!(:issue_from => Issue.find(3),
1681 :issue_to => Issue.find(7),
1682 :relation_type => IssueRelation::TYPE_PRECEDES)
1683 IssueRelation.update_all("issue_to_id = 1", ["id = ?", r.id])
1684
1685 assert_equal [2, 3], Issue.find(1).all_dependent_issues.collect(&:id).sort
1686 end
1687
1688 def test_all_dependent_issues_with_persistent_multiple_circular_dependencies
1689 IssueRelation.delete_all
1690 assert IssueRelation.create!(:issue_from => Issue.find(1),
1691 :issue_to => Issue.find(2),
1692 :relation_type => IssueRelation::TYPE_RELATES)
1693 assert IssueRelation.create!(:issue_from => Issue.find(2),
1694 :issue_to => Issue.find(3),
1695 :relation_type => IssueRelation::TYPE_RELATES)
1696 assert IssueRelation.create!(:issue_from => Issue.find(3),
1697 :issue_to => Issue.find(8),
1698 :relation_type => IssueRelation::TYPE_RELATES)
1699
1700 r = IssueRelation.create!(:issue_from => Issue.find(8),
1701 :issue_to => Issue.find(7),
1702 :relation_type => IssueRelation::TYPE_RELATES)
1703 IssueRelation.update_all("issue_to_id = 2", ["id = ?", r.id])
1704
1705 r = IssueRelation.create!(:issue_from => Issue.find(3),
1706 :issue_to => Issue.find(7),
1707 :relation_type => IssueRelation::TYPE_RELATES)
1708 IssueRelation.update_all("issue_to_id = 1", ["id = ?", r.id])
1709
1710 assert_equal [2, 3, 8], Issue.find(1).all_dependent_issues.collect(&:id).sort
1711 end
1712
1713 context "#done_ratio" do
1714 setup do
1715 @issue = Issue.find(1)
1716 @issue_status = IssueStatus.find(1)
1717 @issue_status.update_attribute(:default_done_ratio, 50)
1718 @issue2 = Issue.find(2)
1719 @issue_status2 = IssueStatus.find(2)
1720 @issue_status2.update_attribute(:default_done_ratio, 0)
1721 end
1722
1723 teardown do
1724 Setting.issue_done_ratio = 'issue_field'
1725 end
1726
1727 context "with Setting.issue_done_ratio using the issue_field" do
1728 setup do
1729 Setting.issue_done_ratio = 'issue_field'
1730 end
1731
1732 should "read the issue's field" do
1733 assert_equal 0, @issue.done_ratio
1734 assert_equal 30, @issue2.done_ratio
1735 end
1736 end
1737
1738 context "with Setting.issue_done_ratio using the issue_status" do
1739 setup do
1740 Setting.issue_done_ratio = 'issue_status'
1741 end
1742
1743 should "read the Issue Status's default done ratio" do
1744 assert_equal 50, @issue.done_ratio
1745 assert_equal 0, @issue2.done_ratio
1746 end
1747 end
1748 end
1749
1750 context "#update_done_ratio_from_issue_status" do
1751 setup do
1752 @issue = Issue.find(1)
1753 @issue_status = IssueStatus.find(1)
1754 @issue_status.update_attribute(:default_done_ratio, 50)
1755 @issue2 = Issue.find(2)
1756 @issue_status2 = IssueStatus.find(2)
1757 @issue_status2.update_attribute(:default_done_ratio, 0)
1758 end
1759
1760 context "with Setting.issue_done_ratio using the issue_field" do
1761 setup do
1762 Setting.issue_done_ratio = 'issue_field'
1763 end
1764
1765 should "not change the issue" do
1766 @issue.update_done_ratio_from_issue_status
1767 @issue2.update_done_ratio_from_issue_status
1768
1769 assert_equal 0, @issue.read_attribute(:done_ratio)
1770 assert_equal 30, @issue2.read_attribute(:done_ratio)
1771 end
1772 end
1773
1774 context "with Setting.issue_done_ratio using the issue_status" do
1775 setup do
1776 Setting.issue_done_ratio = 'issue_status'
1777 end
1778
1779 should "change the issue's done ratio" do
1780 @issue.update_done_ratio_from_issue_status
1781 @issue2.update_done_ratio_from_issue_status
1782
1783 assert_equal 50, @issue.read_attribute(:done_ratio)
1784 assert_equal 0, @issue2.read_attribute(:done_ratio)
1785 end
1786 end
1787 end
1788
1789 test "#by_tracker" do
1790 User.current = User.anonymous
1791 groups = Issue.by_tracker(Project.find(1))
1792 assert_equal 3, groups.size
1793 assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i}
1794 end
1795
1796 test "#by_version" do
1797 User.current = User.anonymous
1798 groups = Issue.by_version(Project.find(1))
1799 assert_equal 3, groups.size
1800 assert_equal 3, groups.inject(0) {|sum, group| sum + group['total'].to_i}
1801 end
1802
1803 test "#by_priority" do
1804 User.current = User.anonymous
1805 groups = Issue.by_priority(Project.find(1))
1806 assert_equal 4, groups.size
1807 assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i}
1808 end
1809
1810 test "#by_category" do
1811 User.current = User.anonymous
1812 groups = Issue.by_category(Project.find(1))
1813 assert_equal 2, groups.size
1814 assert_equal 3, groups.inject(0) {|sum, group| sum + group['total'].to_i}
1815 end
1816
1817 test "#by_assigned_to" do
1818 User.current = User.anonymous
1819 groups = Issue.by_assigned_to(Project.find(1))
1820 assert_equal 2, groups.size
1821 assert_equal 2, groups.inject(0) {|sum, group| sum + group['total'].to_i}
1822 end
1823
1824 test "#by_author" do
1825 User.current = User.anonymous
1826 groups = Issue.by_author(Project.find(1))
1827 assert_equal 4, groups.size
1828 assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i}
1829 end
1830
1831 test "#by_subproject" do
1832 User.current = User.anonymous
1833 groups = Issue.by_subproject(Project.find(1))
1834 # Private descendant not visible
1835 assert_equal 1, groups.size
1836 assert_equal 2, groups.inject(0) {|sum, group| sum + group['total'].to_i}
1837 end
1838
1839 def test_recently_updated_scope
1840 #should return the last updated issue
1841 assert_equal Issue.reorder("updated_on DESC").first, Issue.recently_updated.limit(1).first
1842 end
1843
1844 def test_on_active_projects_scope
1845 assert Project.find(2).archive
1846
1847 before = Issue.on_active_project.length
1848 # test inclusion to results
1849 issue = Issue.generate!(:tracker => Project.find(2).trackers.first)
1850 assert_equal before + 1, Issue.on_active_project.length
1851
1852 # Move to an archived project
1853 issue.project = Project.find(2)
1854 assert issue.save
1855 assert_equal before, Issue.on_active_project.length
1856 end
1857
1858 context "Issue#recipients" do
1859 setup do
1860 @project = Project.find(1)
1861 @author = User.generate!
1862 @assignee = User.generate!
1863 @issue = Issue.generate!(:project => @project, :assigned_to => @assignee, :author => @author)
1864 end
1865
1866 should "include project recipients" do
1867 assert @project.recipients.present?
1868 @project.recipients.each do |project_recipient|
1869 assert @issue.recipients.include?(project_recipient)
1870 end
1871 end
1872
1873 should "include the author if the author is active" do
1874 assert @issue.author, "No author set for Issue"
1875 assert @issue.recipients.include?(@issue.author.mail)
1876 end
1877
1878 should "include the assigned to user if the assigned to user is active" do
1879 assert @issue.assigned_to, "No assigned_to set for Issue"
1880 assert @issue.recipients.include?(@issue.assigned_to.mail)
1881 end
1882
1883 should "not include users who opt out of all email" do
1884 @author.update_attribute(:mail_notification, :none)
1885
1886 assert !@issue.recipients.include?(@issue.author.mail)
1887 end
1888
1889 should "not include the issue author if they are only notified of assigned issues" do
1890 @author.update_attribute(:mail_notification, :only_assigned)
1891
1892 assert !@issue.recipients.include?(@issue.author.mail)
1893 end
1894
1895 should "not include the assigned user if they are only notified of owned issues" do
1896 @assignee.update_attribute(:mail_notification, :only_owner)
1897
1898 assert !@issue.recipients.include?(@issue.assigned_to.mail)
1899 end
1900 end
1901
1902 def test_last_journal_id_with_journals_should_return_the_journal_id
1903 assert_equal 2, Issue.find(1).last_journal_id
1904 end
1905
1906 def test_last_journal_id_without_journals_should_return_nil
1907 assert_nil Issue.find(3).last_journal_id
1908 end
1909
1910 def test_journals_after_should_return_journals_with_greater_id
1911 assert_equal [Journal.find(2)], Issue.find(1).journals_after('1')
1912 assert_equal [], Issue.find(1).journals_after('2')
1913 end
1914
1915 def test_journals_after_with_blank_arg_should_return_all_journals
1916 assert_equal [Journal.find(1), Journal.find(2)], Issue.find(1).journals_after('')
1917 end
1918
1919 def test_css_classes_should_include_priority
1920 issue = Issue.new(:priority => IssuePriority.find(8))
1921 classes = issue.css_classes.split(' ')
1922 assert_include 'priority-8', classes
1923 assert_include 'priority-highest', classes
1924 end
1925
1926 def test_save_attachments_with_hash_should_save_attachments_in_keys_order
1927 set_tmp_attachments_directory
1928 issue = Issue.generate!
1929 issue.save_attachments({
1930 'p0' => {'file' => mock_file_with_options(:original_filename => 'upload')},
1931 '3' => {'file' => mock_file_with_options(:original_filename => 'bar')},
1932 '1' => {'file' => mock_file_with_options(:original_filename => 'foo')}
1933 })
1934 issue.attach_saved_attachments
1935
1936 assert_equal 3, issue.reload.attachments.count
1937 assert_equal %w(upload foo bar), issue.attachments.map(&:filename)
1938 end
1939 end