comparison test/unit/issue_test.rb @ 1115:433d4f72a19b redmine-2.2

Update to Redmine SVN revision 11137 on 2.2-stable branch
author Chris Cannam
date Mon, 07 Jan 2013 12:01:42 +0000
parents cbb26bc654de
children 622f24f53b42 261b3d9a4903
comparison
equal deleted inserted replaced
929:5f33065ddc4b 1115:433d4f72a19b
1 # Redmine - project management software 1 # Redmine - project management software
2 # Copyright (C) 2006-2011 Jean-Philippe Lang 2 # Copyright (C) 2006-2012 Jean-Philippe Lang
3 # 3 #
4 # This program is free software; you can redistribute it and/or 4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License 5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2 6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version. 7 # of the License, or (at your option) any later version.
17 17
18 require File.expand_path('../../test_helper', __FILE__) 18 require File.expand_path('../../test_helper', __FILE__)
19 19
20 class IssueTest < ActiveSupport::TestCase 20 class IssueTest < ActiveSupport::TestCase
21 fixtures :projects, :users, :members, :member_roles, :roles, 21 fixtures :projects, :users, :members, :member_roles, :roles,
22 :groups_users,
22 :trackers, :projects_trackers, 23 :trackers, :projects_trackers,
23 :enabled_modules, 24 :enabled_modules,
24 :versions, 25 :versions,
25 :issue_statuses, :issue_categories, :issue_relations, :workflows, 26 :issue_statuses, :issue_categories, :issue_relations, :workflows,
26 :enumerations, 27 :enumerations,
27 :issues, 28 :issues, :journals, :journal_details,
28 :custom_fields, :custom_fields_projects, :custom_fields_trackers, :custom_values, 29 :custom_fields, :custom_fields_projects, :custom_fields_trackers, :custom_values,
29 :time_entries 30 :time_entries
31
32 include Redmine::I18n
33
34 def teardown
35 User.current = nil
36 end
30 37
31 def test_create 38 def test_create
32 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3, 39 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3,
33 :status_id => 1, :priority => IssuePriority.all.first, 40 :status_id => 1, :priority => IssuePriority.all.first,
34 :subject => 'test_create', 41 :subject => 'test_create',
42 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3, 49 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3,
43 :status_id => 1, :priority => IssuePriority.all.first, 50 :status_id => 1, :priority => IssuePriority.all.first,
44 :subject => 'test_create') 51 :subject => 'test_create')
45 assert issue.save 52 assert issue.save
46 assert issue.description.nil? 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
47 end 80 end
48 81
49 def test_create_with_required_custom_field 82 def test_create_with_required_custom_field
83 set_language_if_valid 'en'
50 field = IssueCustomField.find_by_name('Database') 84 field = IssueCustomField.find_by_name('Database')
51 field.update_attribute(:is_required, true) 85 field.update_attribute(:is_required, true)
52 86
53 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, 87 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
54 :status_id => 1, :subject => 'test_create', 88 :status_id => 1, :subject => 'test_create',
55 :description => 'IssueTest#test_create_with_required_custom_field') 89 :description => 'IssueTest#test_create_with_required_custom_field')
56 assert issue.available_custom_fields.include?(field) 90 assert issue.available_custom_fields.include?(field)
57 # No value for the custom field 91 # No value for the custom field
58 assert !issue.save 92 assert !issue.save
59 assert_equal I18n.translate('activerecord.errors.messages.invalid'), issue.errors.on(:custom_values) 93 assert_equal ["Database can't be blank"], issue.errors.full_messages
60 # Blank value 94 # Blank value
61 issue.custom_field_values = { field.id => '' } 95 issue.custom_field_values = { field.id => '' }
62 assert !issue.save 96 assert !issue.save
63 assert_equal I18n.translate('activerecord.errors.messages.invalid'), issue.errors.on(:custom_values) 97 assert_equal ["Database can't be blank"], issue.errors.full_messages
64 # Invalid value 98 # Invalid value
65 issue.custom_field_values = { field.id => 'SQLServer' } 99 issue.custom_field_values = { field.id => 'SQLServer' }
66 assert !issue.save 100 assert !issue.save
67 assert_equal I18n.translate('activerecord.errors.messages.invalid'), issue.errors.on(:custom_values) 101 assert_equal ["Database is not included in the list"], issue.errors.full_messages
68 # Valid value 102 # Valid value
69 issue.custom_field_values = { field.id => 'PostgreSQL' } 103 issue.custom_field_values = { field.id => 'PostgreSQL' }
70 assert issue.save 104 assert issue.save
71 issue.reload 105 issue.reload
72 assert_equal 'PostgreSQL', issue.custom_value_for(field).value 106 assert_equal 'PostgreSQL', issue.custom_value_for(field).value
81 assert_kind_of Group, issue.assigned_to 115 assert_kind_of Group, issue.assigned_to
82 assert_equal Group.find(11), issue.assigned_to 116 assert_equal Group.find(11), issue.assigned_to
83 end 117 end
84 end 118 end
85 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
86 def assert_visibility_match(user, issues) 158 def assert_visibility_match(user, issues)
87 assert_equal issues.collect(&:id).sort, Issue.all.select {|issue| issue.visible?(user)}.collect(&:id).sort 159 assert_equal issues.collect(&:id).sort, Issue.all.select {|issue| issue.visible?(user)}.collect(&:id).sort
88 end 160 end
89 161
90 def test_visible_scope_for_anonymous 162 def test_visible_scope_for_anonymous
94 assert_nil issues.detect {|issue| !issue.project.is_public?} 166 assert_nil issues.detect {|issue| !issue.project.is_public?}
95 assert_nil issues.detect {|issue| issue.is_private?} 167 assert_nil issues.detect {|issue| issue.is_private?}
96 assert_visibility_match User.anonymous, issues 168 assert_visibility_match User.anonymous, issues
97 end 169 end
98 170
99 def test_visible_scope_for_anonymous_with_own_issues_visibility
100 Role.anonymous.update_attribute :issues_visibility, 'own'
101 Issue.create!(:project_id => 1, :tracker_id => 1,
102 :author_id => User.anonymous.id,
103 :subject => 'Issue by anonymous')
104
105 issues = Issue.visible(User.anonymous).all
106 assert issues.any?
107 assert_nil issues.detect {|issue| issue.author != User.anonymous}
108 assert_visibility_match User.anonymous, issues
109 end
110
111 def test_visible_scope_for_anonymous_without_view_issues_permissions 171 def test_visible_scope_for_anonymous_without_view_issues_permissions
112 # Anonymous user should not see issues without permission 172 # Anonymous user should not see issues without permission
113 Role.anonymous.remove_permission!(:view_issues) 173 Role.anonymous.remove_permission!(:view_issues)
114 issues = Issue.visible(User.anonymous).all 174 issues = Issue.visible(User.anonymous).all
115 assert issues.empty? 175 assert issues.empty?
116 assert_visibility_match User.anonymous, issues 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)
117 end 191 end
118 192
119 def test_visible_scope_for_non_member 193 def test_visible_scope_for_non_member
120 user = User.find(9) 194 user = User.find(9)
121 assert user.projects.empty? 195 assert user.projects.empty?
214 288
215 def test_visible_and_nested_set_scopes 289 def test_visible_and_nested_set_scopes
216 assert_equal 0, Issue.find(1).descendants.visible.all.size 290 assert_equal 0, Issue.find(1).descendants.visible.all.size
217 end 291 end
218 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
219 def test_errors_full_messages_should_include_custom_fields_errors 303 def test_errors_full_messages_should_include_custom_fields_errors
220 field = IssueCustomField.find_by_name('Database') 304 field = IssueCustomField.find_by_name('Database')
221 305
222 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, 306 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
223 :status_id => 1, :subject => 'test_create', 307 :status_id => 1, :subject => 'test_create',
277 issue.reload 361 issue.reload
278 assert_equal custom_value.id, issue.custom_value_for(field).id 362 assert_equal custom_value.id, issue.custom_value_for(field).id
279 end 363 end
280 364
281 def test_should_not_update_custom_fields_on_changing_tracker_with_different_custom_fields 365 def test_should_not_update_custom_fields_on_changing_tracker_with_different_custom_fields
282 issue = Issue.new(:project_id => 1) 366 issue = Issue.create!(:project_id => 1, :tracker_id => 1, :author_id => 1,
283 issue.attributes = {:tracker_id => 1, :author_id => 1, :status_id => 1, :subject => 'Test', :custom_field_values => {'2' => 'Test'}} 367 :status_id => 1, :subject => 'Test',
284 issue.save! 368 :custom_field_values => {'2' => 'Test'})
285
286 assert !Tracker.find(2).custom_field_ids.include?(2) 369 assert !Tracker.find(2).custom_field_ids.include?(2)
287 370
288 issue = Issue.find(issue.id) 371 issue = Issue.find(issue.id)
289 issue.attributes = {:tracker_id => 2, :custom_field_values => {'1' => ''}} 372 issue.attributes = {:tracker_id => 2, :custom_field_values => {'1' => ''}}
290 373
299 assert issue.custom_field_values.empty? 382 assert issue.custom_field_values.empty?
300 issue.tracker_id = 1 383 issue.tracker_id = 1
301 assert issue.custom_field_values.any? 384 assert issue.custom_field_values.any?
302 end 385 end
303 386
304 def test_assigning_attributes_should_assign_tracker_id_first 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
305 attributes = ActiveSupport::OrderedHash.new 397 attributes = ActiveSupport::OrderedHash.new
306 attributes['custom_field_values'] = { '1' => 'MySQL' } 398 attributes['custom_field_values'] = { '1' => 'MySQL' }
307 attributes['tracker_id'] = '1' 399 attributes['tracker_id'] = '1'
308 issue = Issue.new(:project => Project.find(1)) 400 issue = Issue.new(:project => Project.find(1))
309 issue.attributes = attributes 401 issue.attributes = attributes
310 assert_not_nil issue.custom_value_for(1) 402 assert_equal 'MySQL', issue.custom_field_value(1)
311 assert_equal 'MySQL', issue.custom_value_for(1).value
312 end 403 end
313 404
314 def test_should_update_issue_with_disabled_tracker 405 def test_should_update_issue_with_disabled_tracker
315 p = Project.find(1) 406 p = Project.find(1)
316 issue = Issue.find(1) 407 issue = Issue.find(1)
341 :description => 'Assignment test', :category_id => 1) 432 :description => 'Assignment test', :category_id => 1)
342 assert_equal IssueCategory.find(1).assigned_to, issue.assigned_to 433 assert_equal IssueCategory.find(1).assigned_to, issue.assigned_to
343 end 434 end
344 435
345 def test_new_statuses_allowed_to 436 def test_new_statuses_allowed_to
346 Workflow.delete_all 437 WorkflowTransition.delete_all
347 438 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
348 Workflow.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 2, :author => false, :assignee => false) 439 :old_status_id => 1, :new_status_id => 2,
349 Workflow.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 3, :author => true, :assignee => false) 440 :author => false, :assignee => false)
350 Workflow.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 4, :author => false, :assignee => true) 441 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
351 Workflow.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 5, :author => true, :assignee => true) 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)
352 status = IssueStatus.find(1) 450 status = IssueStatus.find(1)
353 role = Role.find(1) 451 role = Role.find(1)
354 tracker = Tracker.find(1) 452 tracker = Tracker.find(1)
355 user = User.find(2) 453 user = User.find(2)
356 454
357 issue = Issue.generate!(:tracker => tracker, :status => status, :project_id => 1) 455 issue = Issue.generate!(:tracker => tracker, :status => status,
456 :project_id => 1, :author_id => 1)
358 assert_equal [1, 2], issue.new_statuses_allowed_to(user).map(&:id) 457 assert_equal [1, 2], issue.new_statuses_allowed_to(user).map(&:id)
359 458
360 issue = Issue.generate!(:tracker => tracker, :status => status, :project_id => 1, :author => user) 459 issue = Issue.generate!(:tracker => tracker, :status => status,
460 :project_id => 1, :author => user)
361 assert_equal [1, 2, 3, 5], issue.new_statuses_allowed_to(user).map(&:id) 461 assert_equal [1, 2, 3, 5], issue.new_statuses_allowed_to(user).map(&:id)
362 462
363 issue = Issue.generate!(:tracker => tracker, :status => status, :project_id => 1, :assigned_to => user) 463 issue = Issue.generate!(:tracker => tracker, :status => status,
464 :project_id => 1, :author_id => 1,
465 :assigned_to => user)
364 assert_equal [1, 2, 4, 5], issue.new_statuses_allowed_to(user).map(&:id) 466 assert_equal [1, 2, 4, 5], issue.new_statuses_allowed_to(user).map(&:id)
365 467
366 issue = Issue.generate!(:tracker => tracker, :status => status, :project_id => 1, :author => user, :assigned_to => user) 468 issue = Issue.generate!(:tracker => tracker, :status => status,
469 :project_id => 1, :author => user,
470 :assigned_to => user)
367 assert_equal [1, 2, 3, 4, 5], issue.new_statuses_allowed_to(user).map(&:id) 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)
368 end 754 end
369 755
370 def test_copy 756 def test_copy
371 issue = Issue.new.copy_from(1) 757 issue = Issue.new.copy_from(1)
758 assert issue.copy?
372 assert issue.save 759 assert issue.save
373 issue.reload 760 issue.reload
374 orig = Issue.find(1) 761 orig = Issue.find(1)
375 assert_equal orig.subject, issue.subject 762 assert_equal orig.subject, issue.subject
376 assert_equal orig.tracker, issue.tracker 763 assert_equal orig.tracker, issue.tracker
385 assert issue.save 772 assert issue.save
386 issue.reload 773 issue.reload
387 assert_equal orig.status, issue.status 774 assert_equal orig.status, issue.status
388 end 775 end
389 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
390 def test_should_close_duplicates 860 def test_should_close_duplicates
391 # Create 3 issues 861 # Create 3 issues
392 issue1 = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, 862 issue1 = Issue.generate!
393 :status_id => 1, :priority => IssuePriority.all.first, 863 issue2 = Issue.generate!
394 :subject => 'Duplicates test', :description => 'Duplicates test') 864 issue3 = Issue.generate!
395 assert issue1.save
396 issue2 = issue1.clone
397 assert issue2.save
398 issue3 = issue1.clone
399 assert issue3.save
400 865
401 # 2 is a dupe of 1 866 # 2 is a dupe of 1
402 IssueRelation.create(:issue_from => issue2, :issue_to => issue1, :relation_type => IssueRelation::TYPE_DUPLICATES) 867 IssueRelation.create!(:issue_from => issue2, :issue_to => issue1,
868 :relation_type => IssueRelation::TYPE_DUPLICATES)
403 # And 3 is a dupe of 2 869 # And 3 is a dupe of 2
404 IssueRelation.create(:issue_from => issue3, :issue_to => issue2, :relation_type => IssueRelation::TYPE_DUPLICATES) 870 IssueRelation.create!(:issue_from => issue3, :issue_to => issue2,
871 :relation_type => IssueRelation::TYPE_DUPLICATES)
405 # And 3 is a dupe of 1 (circular duplicates) 872 # And 3 is a dupe of 1 (circular duplicates)
406 IssueRelation.create(:issue_from => issue3, :issue_to => issue1, :relation_type => IssueRelation::TYPE_DUPLICATES) 873 IssueRelation.create!(:issue_from => issue3, :issue_to => issue1,
874 :relation_type => IssueRelation::TYPE_DUPLICATES)
407 875
408 assert issue1.reload.duplicates.include?(issue2) 876 assert issue1.reload.duplicates.include?(issue2)
409 877
410 # Closing issue 1 878 # Closing issue 1
411 issue1.init_journal(User.find(:first), "Closing issue1") 879 issue1.init_journal(User.find(:first), "Closing issue1")
415 assert issue2.reload.closed? 883 assert issue2.reload.closed?
416 assert issue3.reload.closed? 884 assert issue3.reload.closed?
417 end 885 end
418 886
419 def test_should_not_close_duplicated_issue 887 def test_should_not_close_duplicated_issue
420 # Create 3 issues 888 issue1 = Issue.generate!
421 issue1 = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, 889 issue2 = Issue.generate!
422 :status_id => 1, :priority => IssuePriority.all.first,
423 :subject => 'Duplicates test', :description => 'Duplicates test')
424 assert issue1.save
425 issue2 = issue1.clone
426 assert issue2.save
427 890
428 # 2 is a dupe of 1 891 # 2 is a dupe of 1
429 IssueRelation.create(:issue_from => issue2, :issue_to => issue1, :relation_type => IssueRelation::TYPE_DUPLICATES) 892 IssueRelation.create(:issue_from => issue2, :issue_to => issue1,
893 :relation_type => IssueRelation::TYPE_DUPLICATES)
430 # 2 is a dup of 1 but 1 is not a duplicate of 2 894 # 2 is a dup of 1 but 1 is not a duplicate of 2
431 assert !issue2.reload.duplicates.include?(issue1) 895 assert !issue2.reload.duplicates.include?(issue1)
432 896
433 # Closing issue 2 897 # Closing issue 2
434 issue2.init_journal(User.find(:first), "Closing issue2") 898 issue2.init_journal(User.find(:first), "Closing issue2")
437 # 1 should not be also closed 901 # 1 should not be also closed
438 assert !issue1.reload.closed? 902 assert !issue1.reload.closed?
439 end 903 end
440 904
441 def test_assignable_versions 905 def test_assignable_versions
442 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :fixed_version_id => 1, :subject => 'New issue') 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')
443 assert_equal ['open'], issue.assignable_versions.collect(&:status).uniq 909 assert_equal ['open'], issue.assignable_versions.collect(&:status).uniq
444 end 910 end
445 911
446 def test_should_not_be_able_to_assign_a_new_issue_to_a_closed_version 912 def test_should_not_be_able_to_assign_a_new_issue_to_a_closed_version
447 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :fixed_version_id => 1, :subject => 'New issue') 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')
448 assert !issue.save 916 assert !issue.save
449 assert_not_nil issue.errors[:fixed_version_id] 917 assert_not_nil issue.errors[:fixed_version_id]
450 end 918 end
451 919
452 def test_should_not_be_able_to_assign_a_new_issue_to_a_locked_version 920 def test_should_not_be_able_to_assign_a_new_issue_to_a_locked_version
453 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :fixed_version_id => 2, :subject => 'New issue') 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')
454 assert !issue.save 924 assert !issue.save
455 assert_not_nil issue.errors[:fixed_version_id] 925 assert_not_nil issue.errors[:fixed_version_id]
456 end 926 end
457 927
458 def test_should_be_able_to_assign_a_new_issue_to_an_open_version 928 def test_should_be_able_to_assign_a_new_issue_to_an_open_version
459 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :fixed_version_id => 3, :subject => 'New issue') 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')
460 assert issue.save 932 assert issue.save
461 end 933 end
462 934
463 def test_should_be_able_to_update_an_issue_assigned_to_a_closed_version 935 def test_should_be_able_to_update_an_issue_assigned_to_a_closed_version
464 issue = Issue.find(11) 936 issue = Issue.find(11)
486 assert_equal 'locked', issue.fixed_version.status 958 assert_equal 'locked', issue.fixed_version.status
487 issue.status_id = 1 959 issue.status_id = 1
488 assert issue.save 960 assert issue.save
489 end 961 end
490 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
491 def test_move_to_another_project_with_same_category 992 def test_move_to_another_project_with_same_category
492 issue = Issue.find(1) 993 issue = Issue.find(1)
493 assert issue.move_to_project(Project.find(2)) 994 issue.project = Project.find(2)
995 assert issue.save
494 issue.reload 996 issue.reload
495 assert_equal 2, issue.project_id 997 assert_equal 2, issue.project_id
496 # Category changes 998 # Category changes
497 assert_equal 4, issue.category_id 999 assert_equal 4, issue.category_id
498 # Make sure time entries were move to the target project 1000 # Make sure time entries were move to the target project
499 assert_equal 2, issue.time_entries.first.project_id 1001 assert_equal 2, issue.time_entries.first.project_id
500 end 1002 end
501 1003
502 def test_move_to_another_project_without_same_category 1004 def test_move_to_another_project_without_same_category
503 issue = Issue.find(2) 1005 issue = Issue.find(2)
504 assert issue.move_to_project(Project.find(2)) 1006 issue.project = Project.find(2)
1007 assert issue.save
505 issue.reload 1008 issue.reload
506 assert_equal 2, issue.project_id 1009 assert_equal 2, issue.project_id
507 # Category cleared 1010 # Category cleared
508 assert_nil issue.category_id 1011 assert_nil issue.category_id
509 end 1012 end
510 1013
511 def test_move_to_another_project_should_clear_fixed_version_when_not_shared 1014 def test_move_to_another_project_should_clear_fixed_version_when_not_shared
512 issue = Issue.find(1) 1015 issue = Issue.find(1)
513 issue.update_attribute(:fixed_version_id, 1) 1016 issue.update_attribute(:fixed_version_id, 1)
514 assert issue.move_to_project(Project.find(2)) 1017 issue.project = Project.find(2)
1018 assert issue.save
515 issue.reload 1019 issue.reload
516 assert_equal 2, issue.project_id 1020 assert_equal 2, issue.project_id
517 # Cleared fixed_version 1021 # Cleared fixed_version
518 assert_equal nil, issue.fixed_version 1022 assert_equal nil, issue.fixed_version
519 end 1023 end
520 1024
521 def test_move_to_another_project_should_keep_fixed_version_when_shared_with_the_target_project 1025 def test_move_to_another_project_should_keep_fixed_version_when_shared_with_the_target_project
522 issue = Issue.find(1) 1026 issue = Issue.find(1)
523 issue.update_attribute(:fixed_version_id, 4) 1027 issue.update_attribute(:fixed_version_id, 4)
524 assert issue.move_to_project(Project.find(5)) 1028 issue.project = Project.find(5)
1029 assert issue.save
525 issue.reload 1030 issue.reload
526 assert_equal 5, issue.project_id 1031 assert_equal 5, issue.project_id
527 # Keep fixed_version 1032 # Keep fixed_version
528 assert_equal 4, issue.fixed_version_id 1033 assert_equal 4, issue.fixed_version_id
529 end 1034 end
530 1035
531 def test_move_to_another_project_should_clear_fixed_version_when_not_shared_with_the_target_project 1036 def test_move_to_another_project_should_clear_fixed_version_when_not_shared_with_the_target_project
532 issue = Issue.find(1) 1037 issue = Issue.find(1)
533 issue.update_attribute(:fixed_version_id, 1) 1038 issue.update_attribute(:fixed_version_id, 1)
534 assert issue.move_to_project(Project.find(5)) 1039 issue.project = Project.find(5)
1040 assert issue.save
535 issue.reload 1041 issue.reload
536 assert_equal 5, issue.project_id 1042 assert_equal 5, issue.project_id
537 # Cleared fixed_version 1043 # Cleared fixed_version
538 assert_equal nil, issue.fixed_version 1044 assert_equal nil, issue.fixed_version
539 end 1045 end
540 1046
541 def test_move_to_another_project_should_keep_fixed_version_when_shared_systemwide 1047 def test_move_to_another_project_should_keep_fixed_version_when_shared_systemwide
542 issue = Issue.find(1) 1048 issue = Issue.find(1)
543 issue.update_attribute(:fixed_version_id, 7) 1049 issue.update_attribute(:fixed_version_id, 7)
544 assert issue.move_to_project(Project.find(2)) 1050 issue.project = Project.find(2)
1051 assert issue.save
545 issue.reload 1052 issue.reload
546 assert_equal 2, issue.project_id 1053 assert_equal 2, issue.project_id
547 # Keep fixed_version 1054 # Keep fixed_version
548 assert_equal 7, issue.fixed_version_id 1055 assert_equal 7, issue.fixed_version_id
549 end 1056 end
550 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
551 def test_move_to_another_project_with_disabled_tracker 1076 def test_move_to_another_project_with_disabled_tracker
552 issue = Issue.find(1) 1077 issue = Issue.find(1)
553 target = Project.find(2) 1078 target = Project.find(2)
554 target.tracker_ids = [3] 1079 target.tracker_ids = [3]
555 target.save 1080 target.save
556 assert_equal false, issue.move_to_project(target) 1081 issue.project = target
1082 assert issue.save
557 issue.reload 1083 issue.reload
558 assert_equal 1, issue.project_id 1084 assert_equal 2, issue.project_id
1085 assert_equal 3, issue.tracker_id
559 end 1086 end
560 1087
561 def test_copy_to_the_same_project 1088 def test_copy_to_the_same_project
562 issue = Issue.find(1) 1089 issue = Issue.find(1)
563 copy = nil 1090 copy = issue.copy
564 assert_difference 'Issue.count' do 1091 assert_difference 'Issue.count' do
565 copy = issue.move_to_project(issue.project, nil, :copy => true) 1092 copy.save!
566 end 1093 end
567 assert_kind_of Issue, copy 1094 assert_kind_of Issue, copy
568 assert_equal issue.project, copy.project 1095 assert_equal issue.project, copy.project
569 assert_equal "125", copy.custom_value_for(2).value 1096 assert_equal "125", copy.custom_value_for(2).value
570 end 1097 end
571 1098
572 def test_copy_to_another_project_and_tracker 1099 def test_copy_to_another_project_and_tracker
573 issue = Issue.find(1) 1100 issue = Issue.find(1)
574 copy = nil 1101 copy = issue.copy(:project_id => 3, :tracker_id => 2)
575 assert_difference 'Issue.count' do 1102 assert_difference 'Issue.count' do
576 copy = issue.move_to_project(Project.find(3), Tracker.find(2), :copy => true) 1103 copy.save!
577 end 1104 end
578 copy.reload 1105 copy.reload
579 assert_kind_of Issue, copy 1106 assert_kind_of Issue, copy
580 assert_equal Project.find(3), copy.project 1107 assert_equal Project.find(3), copy.project
581 assert_equal Tracker.find(2), copy.tracker 1108 assert_equal Tracker.find(2), copy.tracker
582 # Custom field #2 is not associated with target tracker 1109 # Custom field #2 is not associated with target tracker
583 assert_nil copy.custom_value_for(2) 1110 assert_nil copy.custom_value_for(2)
584 end 1111 end
585 1112
586 context "#move_to_project" do 1113 context "#copy" do
587 context "as a copy" do 1114 setup do
588 setup do 1115 @issue = Issue.find(1)
589 @issue = Issue.find(1) 1116 end
590 @copy = nil 1117
591 end 1118 should "not create a journal" do
592 1119 copy = @issue.copy(:project_id => 3, :tracker_id => 2, :assigned_to_id => 3)
593 should "not create a journal" do 1120 copy.save!
594 @copy = @issue.move_to_project(Project.find(3), Tracker.find(2), {:copy => true, :attributes => {:assigned_to_id => 3}}) 1121 assert_equal 0, copy.reload.journals.size
595 assert_equal 0, @copy.reload.journals.size 1122 end
596 end 1123
597 1124 should "allow assigned_to changes" do
598 should "allow assigned_to changes" do 1125 copy = @issue.copy(:project_id => 3, :tracker_id => 2, :assigned_to_id => 3)
599 @copy = @issue.move_to_project(Project.find(3), Tracker.find(2), {:copy => true, :attributes => {:assigned_to_id => 3}}) 1126 assert_equal 3, copy.assigned_to_id
600 assert_equal 3, @copy.assigned_to_id 1127 end
601 end 1128
602 1129 should "allow status changes" do
603 should "allow status changes" do 1130 copy = @issue.copy(:project_id => 3, :tracker_id => 2, :status_id => 2)
604 @copy = @issue.move_to_project(Project.find(3), Tracker.find(2), {:copy => true, :attributes => {:status_id => 2}}) 1131 assert_equal 2, copy.status_id
605 assert_equal 2, @copy.status_id 1132 end
606 end 1133
607 1134 should "allow start date changes" do
608 should "allow start date changes" do 1135 date = Date.today
609 date = Date.today 1136 copy = @issue.copy(:project_id => 3, :tracker_id => 2, :start_date => date)
610 @copy = @issue.move_to_project(Project.find(3), Tracker.find(2), {:copy => true, :attributes => {:start_date => date}}) 1137 assert_equal date, copy.start_date
611 assert_equal date, @copy.start_date 1138 end
612 end 1139
613 1140 should "allow due date changes" do
614 should "allow due date changes" do 1141 date = Date.today
615 date = Date.today 1142 copy = @issue.copy(:project_id => 3, :tracker_id => 2, :due_date => date)
616 @copy = @issue.move_to_project(Project.find(3), Tracker.find(2), {:copy => true, :attributes => {:due_date => date}}) 1143 assert_equal date, copy.due_date
617 1144 end
618 assert_equal date, @copy.due_date 1145
619 end 1146 should "set current user as author" do
620 1147 User.current = User.find(9)
621 should "set current user as author" do 1148 copy = @issue.copy(:project_id => 3, :tracker_id => 2)
622 User.current = User.find(9) 1149 assert_equal User.current, copy.author
623 @copy = @issue.move_to_project(Project.find(3), Tracker.find(2), {:copy => true, :attributes => {}}) 1150 end
624 1151
625 assert_equal User.current, @copy.author 1152 should "create a journal with notes" do
626 end 1153 date = Date.today
627 1154 notes = "Notes added when copying"
628 should "keep journal notes" do 1155 copy = @issue.copy(:project_id => 3, :tracker_id => 2, :start_date => date)
629 date = Date.today 1156 copy.init_journal(User.current, notes)
630 notes = "Notes added when copying" 1157 copy.save!
631 User.current = User.find(9) 1158
632 @issue.init_journal(User.current, notes) 1159 assert_equal 1, copy.journals.size
633 @copy = @issue.move_to_project(Project.find(3), Tracker.find(2), {:copy => true, :attributes => {:start_date => date}}) 1160 journal = copy.journals.first
634 1161 assert_equal 0, journal.details.size
635 assert_equal 1, @copy.journals.size 1162 assert_equal notes, journal.notes
636 journal = @copy.journals.first 1163 end
637 assert_equal 0, journal.details.size 1164 end
638 assert_equal notes, journal.notes 1165
639 end 1166 def test_valid_parent_project
640 end 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)
641 end 1218 end
642 1219
643 def test_recipients_should_not_include_users_that_cannot_view_the_issue 1220 def test_recipients_should_not_include_users_that_cannot_view_the_issue
644 issue = Issue.find(12) 1221 issue = Issue.find(12)
645 assert issue.recipients.include?(issue.author.mail) 1222 assert issue.recipients.include?(issue.author.mail)
646 # move the issue to a private project 1223 # copy the issue to a private project
647 copy = issue.move_to_project(Project.find(5), Tracker.find(2), :copy => true) 1224 copy = issue.copy(:project_id => 5, :tracker_id => 2)
648 # author is not a member of project anymore 1225 # author is not a member of project anymore
649 assert !copy.recipients.include?(copy.author.mail) 1226 assert !copy.recipients.include?(copy.author.mail)
650 end 1227 end
651 1228
652 def test_recipients_should_include_the_assigned_group_members 1229 def test_recipients_should_include_the_assigned_group_members
653 group_member = User.generate_with_protected! 1230 group_member = User.generate!
654 group = Group.generate! 1231 group = Group.generate!
655 group.users << group_member 1232 group.users << group_member
656 1233
657 issue = Issue.find(12) 1234 issue = Issue.find(12)
658 issue.assigned_to = group 1235 issue.assigned_to = group
671 Issue.find(1).destroy 1248 Issue.find(1).destroy
672 assert_nil Issue.find_by_id(1) 1249 assert_nil Issue.find_by_id(1)
673 assert_nil TimeEntry.find_by_issue_id(1) 1250 assert_nil TimeEntry.find_by_issue_id(1)
674 end 1251 end
675 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
676 def test_blocked 1277 def test_blocked
677 blocked_issue = Issue.find(9) 1278 blocked_issue = Issue.find(9)
678 blocking_issue = Issue.find(10) 1279 blocking_issue = Issue.find(10)
679 1280
680 assert blocked_issue.blocked? 1281 assert blocked_issue.blocked?
697 assert !allowed_statuses.empty? 1298 assert !allowed_statuses.empty?
698 closed_statuses = allowed_statuses.select {|st| st.is_closed?} 1299 closed_statuses = allowed_statuses.select {|st| st.is_closed?}
699 assert !closed_statuses.empty? 1300 assert !closed_statuses.empty?
700 end 1301 end
701 1302
702 def test_rescheduling_an_issue_should_reschedule_following_issue 1303 def test_reschedule_an_issue_without_dates
703 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) 1304 with_settings :non_working_week_days => [] do
704 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) 1305 issue = Issue.new(:start_date => nil, :due_date => nil)
705 IssueRelation.create!(:issue_from => issue1, :issue_to => issue2, :relation_type => IssueRelation::TYPE_PRECEDES) 1306 issue.reschedule_on '2012-10-09'.to_date
706 assert_equal issue1.due_date + 1, issue2.reload.start_date 1307 assert_equal '2012-10-09'.to_date, issue.start_date
707 1308 assert_equal '2012-10-09'.to_date, issue.due_date
708 issue1.due_date = Date.today + 5 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'
709 issue1.save! 1374 issue1.save!
710 assert_equal issue1.due_date + 1, issue2.reload.start_date 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
711 end 1426 end
712 1427
713 def test_overdue 1428 def test_overdue
714 assert Issue.new(:due_date => 1.day.ago.to_date).overdue? 1429 assert Issue.new(:due_date => 1.day.ago.to_date).overdue?
715 assert !Issue.new(:due_date => Date.today).overdue? 1430 assert !Issue.new(:due_date => Date.today).overdue?
716 assert !Issue.new(:due_date => 1.day.from_now.to_date).overdue? 1431 assert !Issue.new(:due_date => 1.day.from_now.to_date).overdue?
717 assert !Issue.new(:due_date => nil).overdue? 1432 assert !Issue.new(:due_date => nil).overdue?
718 assert !Issue.new(:due_date => 1.day.ago.to_date, :status => IssueStatus.find(:first, :conditions => {:is_closed => true})).overdue? 1433 assert !Issue.new(:due_date => 1.day.ago.to_date,
1434 :status => IssueStatus.find(:first,
1435 :conditions => {:is_closed => true})
1436 ).overdue?
719 end 1437 end
720 1438
721 context "#behind_schedule?" do 1439 context "#behind_schedule?" do
722 should "be false if the issue has no start_date" do 1440 should "be false if the issue has no start_date" do
723 assert !Issue.new(:start_date => nil, :due_date => 1.day.from_now.to_date, :done_ratio => 0).behind_schedule? 1441 assert !Issue.new(:start_date => nil,
1442 :due_date => 1.day.from_now.to_date,
1443 :done_ratio => 0).behind_schedule?
724 end 1444 end
725 1445
726 should "be false if the issue has no end_date" do 1446 should "be false if the issue has no end_date" do
727 assert !Issue.new(:start_date => 1.day.from_now.to_date, :due_date => nil, :done_ratio => 0).behind_schedule? 1447 assert !Issue.new(:start_date => 1.day.from_now.to_date,
1448 :due_date => nil,
1449 :done_ratio => 0).behind_schedule?
728 end 1450 end
729 1451
730 should "be false if the issue has more done than it's calendar time" do 1452 should "be false if the issue has more done than it's calendar time" do
731 assert !Issue.new(:start_date => 50.days.ago.to_date, :due_date => 50.days.from_now.to_date, :done_ratio => 90).behind_schedule? 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?
732 end 1456 end
733 1457
734 should "be true if the issue hasn't been started at all" do 1458 should "be true if the issue hasn't been started at all" do
735 assert Issue.new(:start_date => 1.day.ago.to_date, :due_date => 1.day.from_now.to_date, :done_ratio => 0).behind_schedule? 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?
736 end 1462 end
737 1463
738 should "be true if the issue has used more calendar time than it's done ratio" do 1464 should "be true if the issue has used more calendar time than it's done ratio" do
739 assert Issue.new(:start_date => 100.days.ago.to_date, :due_date => Date.today, :done_ratio => 90).behind_schedule? 1465 assert Issue.new(:start_date => 100.days.ago.to_date,
1466 :due_date => Date.today,
1467 :done_ratio => 90).behind_schedule?
740 end 1468 end
741 end 1469 end
742 1470
743 context "#assignable_users" do 1471 context "#assignable_users" do
744 should "be Users" do 1472 should "be Users" do
745 assert_kind_of User, Issue.find(1).assignable_users.first 1473 assert_kind_of User, Issue.find(1).assignable_users.first
746 end 1474 end
747 1475
748 should "include the issue author" do 1476 should "include the issue author" do
749 project = Project.find(1)
750 non_project_member = User.generate! 1477 non_project_member = User.generate!
751 issue = Issue.generate_for_project!(project, :author => non_project_member) 1478 issue = Issue.generate!(:author => non_project_member)
752 1479
753 assert issue.assignable_users.include?(non_project_member) 1480 assert issue.assignable_users.include?(non_project_member)
754 end 1481 end
755 1482
756 should "include the current assignee" do 1483 should "include the current assignee" do
757 project = Project.find(1)
758 user = User.generate! 1484 user = User.generate!
759 issue = Issue.generate_for_project!(project, :assigned_to => user) 1485 issue = Issue.generate!(:assigned_to => user)
760 user.lock! 1486 user.lock!
761 1487
762 assert Issue.find(issue.id).assignable_users.include?(user) 1488 assert Issue.find(issue.id).assignable_users.include?(user)
763 end 1489 end
764 1490
765 should "not show the issue author twice" do 1491 should "not show the issue author twice" do
766 assignable_user_ids = Issue.find(1).assignable_users.collect(&:id) 1492 assignable_user_ids = Issue.find(1).assignable_users.collect(&:id)
767 assert_equal 2, assignable_user_ids.length 1493 assert_equal 2, assignable_user_ids.length
768 1494
769 assignable_user_ids.each do |user_id| 1495 assignable_user_ids.each do |user_id|
770 assert_equal 1, assignable_user_ids.select {|i| i == user_id}.length, "User #{user_id} appears more or less than once" 1496 assert_equal 1, assignable_user_ids.select {|i| i == user_id}.length,
1497 "User #{user_id} appears more or less than once"
771 end 1498 end
772 end 1499 end
773 1500
774 context "with issue_group_assignment" do 1501 context "with issue_group_assignment" do
775 should "include groups" do 1502 should "include groups" do
857 i.description = "\r\n" 1584 i.description = "\r\n"
858 1585
859 assert_difference 'Journal.count', 1 do 1586 assert_difference 'Journal.count', 1 do
860 assert_difference 'JournalDetail.count', 1 do 1587 assert_difference 'JournalDetail.count', 1 do
861 i.save! 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!
862 end 1623 end
863 end 1624 end
864 end 1625 end
865 1626
866 def test_description_eol_should_be_normalized 1627 def test_description_eol_should_be_normalized
913 :issue_to => Issue.find(2), 1674 :issue_to => Issue.find(2),
914 :relation_type => IssueRelation::TYPE_PRECEDES) 1675 :relation_type => IssueRelation::TYPE_PRECEDES)
915 assert IssueRelation.create!(:issue_from => Issue.find(2), 1676 assert IssueRelation.create!(:issue_from => Issue.find(2),
916 :issue_to => Issue.find(3), 1677 :issue_to => Issue.find(3),
917 :relation_type => IssueRelation::TYPE_PRECEDES) 1678 :relation_type => IssueRelation::TYPE_PRECEDES)
918 # Validation skipping 1679
919 assert IssueRelation.new(:issue_from => Issue.find(3), 1680 r = IssueRelation.create!(:issue_from => Issue.find(3),
920 :issue_to => Issue.find(1), 1681 :issue_to => Issue.find(7),
921 :relation_type => IssueRelation::TYPE_PRECEDES).save(false) 1682 :relation_type => IssueRelation::TYPE_PRECEDES)
922 1683 IssueRelation.update_all("issue_to_id = 1", ["id = ?", r.id])
1684
923 assert_equal [2, 3], Issue.find(1).all_dependent_issues.collect(&:id).sort 1685 assert_equal [2, 3], Issue.find(1).all_dependent_issues.collect(&:id).sort
924 end 1686 end
925 1687
926 def test_all_dependent_issues_with_persistent_multiple_circular_dependencies 1688 def test_all_dependent_issues_with_persistent_multiple_circular_dependencies
927 IssueRelation.delete_all 1689 IssueRelation.delete_all
932 :issue_to => Issue.find(3), 1694 :issue_to => Issue.find(3),
933 :relation_type => IssueRelation::TYPE_RELATES) 1695 :relation_type => IssueRelation::TYPE_RELATES)
934 assert IssueRelation.create!(:issue_from => Issue.find(3), 1696 assert IssueRelation.create!(:issue_from => Issue.find(3),
935 :issue_to => Issue.find(8), 1697 :issue_to => Issue.find(8),
936 :relation_type => IssueRelation::TYPE_RELATES) 1698 :relation_type => IssueRelation::TYPE_RELATES)
937 # Validation skipping 1699
938 assert IssueRelation.new(:issue_from => Issue.find(8), 1700 r = IssueRelation.create!(:issue_from => Issue.find(8),
939 :issue_to => Issue.find(2), 1701 :issue_to => Issue.find(7),
940 :relation_type => IssueRelation::TYPE_RELATES).save(false) 1702 :relation_type => IssueRelation::TYPE_RELATES)
941 assert IssueRelation.new(:issue_from => Issue.find(3), 1703 IssueRelation.update_all("issue_to_id = 2", ["id = ?", r.id])
942 :issue_to => Issue.find(1), 1704
943 :relation_type => IssueRelation::TYPE_RELATES).save(false) 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])
944 1709
945 assert_equal [2, 3, 8], Issue.find(1).all_dependent_issues.collect(&:id).sort 1710 assert_equal [2, 3, 8], Issue.find(1).all_dependent_issues.collect(&:id).sort
946 end 1711 end
947 1712
948 context "#done_ratio" do 1713 context "#done_ratio" do
953 @issue2 = Issue.find(2) 1718 @issue2 = Issue.find(2)
954 @issue_status2 = IssueStatus.find(2) 1719 @issue_status2 = IssueStatus.find(2)
955 @issue_status2.update_attribute(:default_done_ratio, 0) 1720 @issue_status2.update_attribute(:default_done_ratio, 0)
956 end 1721 end
957 1722
1723 teardown do
1724 Setting.issue_done_ratio = 'issue_field'
1725 end
1726
958 context "with Setting.issue_done_ratio using the issue_field" do 1727 context "with Setting.issue_done_ratio using the issue_field" do
959 setup do 1728 setup do
960 Setting.issue_done_ratio = 'issue_field' 1729 Setting.issue_done_ratio = 'issue_field'
961 end 1730 end
962 1731
1065 # Private descendant not visible 1834 # Private descendant not visible
1066 assert_equal 1, groups.size 1835 assert_equal 1, groups.size
1067 assert_equal 2, groups.inject(0) {|sum, group| sum + group['total'].to_i} 1836 assert_equal 2, groups.inject(0) {|sum, group| sum + group['total'].to_i}
1068 end 1837 end
1069 1838
1070 context ".allowed_target_projects_on_move" do 1839 def test_recently_updated_scope
1071 should "return all active projects for admin users" do
1072 User.current = User.find(1)
1073 assert_equal Project.active.count, Issue.allowed_target_projects_on_move.size
1074 end
1075
1076 should "return allowed projects for non admin users" do
1077 User.current = User.find(2)
1078 Role.non_member.remove_permission! :move_issues
1079 assert_equal 3, Issue.allowed_target_projects_on_move.size
1080
1081 Role.non_member.add_permission! :move_issues
1082 assert_equal Project.active.count, Issue.allowed_target_projects_on_move.size
1083 end
1084 end
1085
1086 def test_recently_updated_with_limit_scopes
1087 #should return the last updated issue 1840 #should return the last updated issue
1088 assert_equal 1, Issue.recently_updated.with_limit(1).length 1841 assert_equal Issue.reorder("updated_on DESC").first, Issue.recently_updated.limit(1).first
1089 assert_equal Issue.find(:first, :order => "updated_on DESC"), Issue.recently_updated.with_limit(1).first
1090 end 1842 end
1091 1843
1092 def test_on_active_projects_scope 1844 def test_on_active_projects_scope
1093 assert Project.find(2).archive 1845 assert Project.find(2).archive
1094 1846
1095 before = Issue.on_active_project.length 1847 before = Issue.on_active_project.length
1096 # test inclusion to results 1848 # test inclusion to results
1097 issue = Issue.generate_for_project!(Project.find(1), :tracker => Project.find(2).trackers.first) 1849 issue = Issue.generate!(:tracker => Project.find(2).trackers.first)
1098 assert_equal before + 1, Issue.on_active_project.length 1850 assert_equal before + 1, Issue.on_active_project.length
1099 1851
1100 # Move to an archived project 1852 # Move to an archived project
1101 issue.project = Project.find(2) 1853 issue.project = Project.find(2)
1102 assert issue.save 1854 assert issue.save
1104 end 1856 end
1105 1857
1106 context "Issue#recipients" do 1858 context "Issue#recipients" do
1107 setup do 1859 setup do
1108 @project = Project.find(1) 1860 @project = Project.find(1)
1109 @author = User.generate_with_protected! 1861 @author = User.generate!
1110 @assignee = User.generate_with_protected! 1862 @assignee = User.generate!
1111 @issue = Issue.generate_for_project!(@project, :assigned_to => @assignee, :author => @author) 1863 @issue = Issue.generate!(:project => @project, :assigned_to => @assignee, :author => @author)
1112 end 1864 end
1113 1865
1114 should "include project recipients" do 1866 should "include project recipients" do
1115 assert @project.recipients.present? 1867 assert @project.recipients.present?
1116 @project.recipients.each do |project_recipient| 1868 @project.recipients.each do |project_recipient|
1143 should "not include the assigned user if they are only notified of owned issues" do 1895 should "not include the assigned user if they are only notified of owned issues" do
1144 @assignee.update_attribute(:mail_notification, :only_owner) 1896 @assignee.update_attribute(:mail_notification, :only_owner)
1145 1897
1146 assert !@issue.recipients.include?(@issue.assigned_to.mail) 1898 assert !@issue.recipients.include?(@issue.assigned_to.mail)
1147 end 1899 end
1148 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)
1149 end 1938 end
1150 end 1939 end