##// END OF EJS Templates
After copying a task, setting the parent as the orignal task's parent triggers an error (#17580)....
Jean-Philippe Lang -
r14675:300e5e465208
parent child
Show More
@@ -1,2679 +1,2696
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2015 Jean-Philippe Lang
2 # Copyright (C) 2006-2015 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.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
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
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.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
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, :email_addresses, :members, :member_roles, :roles,
21 fixtures :projects, :users, :email_addresses, :members, :member_roles, :roles,
22 :groups_users,
22 :groups_users,
23 :trackers, :projects_trackers,
23 :trackers, :projects_trackers,
24 :enabled_modules,
24 :enabled_modules,
25 :versions,
25 :versions,
26 :issue_statuses, :issue_categories, :issue_relations, :workflows,
26 :issue_statuses, :issue_categories, :issue_relations, :workflows,
27 :enumerations,
27 :enumerations,
28 :issues, :journals, :journal_details,
28 :issues, :journals, :journal_details,
29 :custom_fields, :custom_fields_projects, :custom_fields_trackers, :custom_values,
29 :custom_fields, :custom_fields_projects, :custom_fields_trackers, :custom_values,
30 :time_entries
30 :time_entries
31
31
32 include Redmine::I18n
32 include Redmine::I18n
33
33
34 def setup
34 def setup
35 set_language_if_valid 'en'
35 set_language_if_valid 'en'
36 end
36 end
37
37
38 def teardown
38 def teardown
39 User.current = nil
39 User.current = nil
40 end
40 end
41
41
42 def test_initialize
42 def test_initialize
43 issue = Issue.new
43 issue = Issue.new
44
44
45 assert_nil issue.project_id
45 assert_nil issue.project_id
46 assert_nil issue.tracker_id
46 assert_nil issue.tracker_id
47 assert_nil issue.status_id
47 assert_nil issue.status_id
48 assert_nil issue.author_id
48 assert_nil issue.author_id
49 assert_nil issue.assigned_to_id
49 assert_nil issue.assigned_to_id
50 assert_nil issue.category_id
50 assert_nil issue.category_id
51
51
52 assert_equal IssuePriority.default, issue.priority
52 assert_equal IssuePriority.default, issue.priority
53 end
53 end
54
54
55 def test_create
55 def test_create
56 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3,
56 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3,
57 :status_id => 1, :priority => IssuePriority.all.first,
57 :status_id => 1, :priority => IssuePriority.all.first,
58 :subject => 'test_create',
58 :subject => 'test_create',
59 :description => 'IssueTest#test_create', :estimated_hours => '1:30')
59 :description => 'IssueTest#test_create', :estimated_hours => '1:30')
60 assert issue.save
60 assert issue.save
61 issue.reload
61 issue.reload
62 assert_equal 1.5, issue.estimated_hours
62 assert_equal 1.5, issue.estimated_hours
63 end
63 end
64
64
65 def test_create_minimal
65 def test_create_minimal
66 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3, :subject => 'test_create')
66 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3, :subject => 'test_create')
67 assert issue.save
67 assert issue.save
68 assert_equal issue.tracker.default_status, issue.status
68 assert_equal issue.tracker.default_status, issue.status
69 assert issue.description.nil?
69 assert issue.description.nil?
70 assert_nil issue.estimated_hours
70 assert_nil issue.estimated_hours
71 end
71 end
72
72
73 def test_create_with_all_fields_disabled
73 def test_create_with_all_fields_disabled
74 tracker = Tracker.find(1)
74 tracker = Tracker.find(1)
75 tracker.core_fields = []
75 tracker.core_fields = []
76 tracker.save!
76 tracker.save!
77
77
78 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3, :subject => 'test_create_with_all_fields_disabled')
78 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3, :subject => 'test_create_with_all_fields_disabled')
79 assert_save issue
79 assert_save issue
80 end
80 end
81
81
82 def test_start_date_format_should_be_validated
82 def test_start_date_format_should_be_validated
83 set_language_if_valid 'en'
83 set_language_if_valid 'en'
84 ['2012', 'ABC', '2012-15-20'].each do |invalid_date|
84 ['2012', 'ABC', '2012-15-20'].each do |invalid_date|
85 issue = Issue.new(:start_date => invalid_date)
85 issue = Issue.new(:start_date => invalid_date)
86 assert !issue.valid?
86 assert !issue.valid?
87 assert_include 'Start date is not a valid date', issue.errors.full_messages, "No error found for invalid date #{invalid_date}"
87 assert_include 'Start date is not a valid date', issue.errors.full_messages, "No error found for invalid date #{invalid_date}"
88 end
88 end
89 end
89 end
90
90
91 def test_due_date_format_should_be_validated
91 def test_due_date_format_should_be_validated
92 set_language_if_valid 'en'
92 set_language_if_valid 'en'
93 ['2012', 'ABC', '2012-15-20'].each do |invalid_date|
93 ['2012', 'ABC', '2012-15-20'].each do |invalid_date|
94 issue = Issue.new(:due_date => invalid_date)
94 issue = Issue.new(:due_date => invalid_date)
95 assert !issue.valid?
95 assert !issue.valid?
96 assert_include 'Due date is not a valid date', issue.errors.full_messages, "No error found for invalid date #{invalid_date}"
96 assert_include 'Due date is not a valid date', issue.errors.full_messages, "No error found for invalid date #{invalid_date}"
97 end
97 end
98 end
98 end
99
99
100 def test_due_date_lesser_than_start_date_should_not_validate
100 def test_due_date_lesser_than_start_date_should_not_validate
101 set_language_if_valid 'en'
101 set_language_if_valid 'en'
102 issue = Issue.new(:start_date => '2012-10-06', :due_date => '2012-10-02')
102 issue = Issue.new(:start_date => '2012-10-06', :due_date => '2012-10-02')
103 assert !issue.valid?
103 assert !issue.valid?
104 assert_include 'Due date must be greater than start date', issue.errors.full_messages
104 assert_include 'Due date must be greater than start date', issue.errors.full_messages
105 end
105 end
106
106
107 def test_start_date_lesser_than_soonest_start_should_not_validate_on_create
107 def test_start_date_lesser_than_soonest_start_should_not_validate_on_create
108 issue = Issue.generate(:start_date => '2013-06-04')
108 issue = Issue.generate(:start_date => '2013-06-04')
109 issue.stubs(:soonest_start).returns(Date.parse('2013-06-10'))
109 issue.stubs(:soonest_start).returns(Date.parse('2013-06-10'))
110 assert !issue.valid?
110 assert !issue.valid?
111 assert_include "Start date cannot be earlier than 06/10/2013 because of preceding issues", issue.errors.full_messages
111 assert_include "Start date cannot be earlier than 06/10/2013 because of preceding issues", issue.errors.full_messages
112 end
112 end
113
113
114 def test_start_date_lesser_than_soonest_start_should_not_validate_on_update_if_changed
114 def test_start_date_lesser_than_soonest_start_should_not_validate_on_update_if_changed
115 issue = Issue.generate!(:start_date => '2013-06-04')
115 issue = Issue.generate!(:start_date => '2013-06-04')
116 issue.stubs(:soonest_start).returns(Date.parse('2013-06-10'))
116 issue.stubs(:soonest_start).returns(Date.parse('2013-06-10'))
117 issue.start_date = '2013-06-07'
117 issue.start_date = '2013-06-07'
118 assert !issue.valid?
118 assert !issue.valid?
119 assert_include "Start date cannot be earlier than 06/10/2013 because of preceding issues", issue.errors.full_messages
119 assert_include "Start date cannot be earlier than 06/10/2013 because of preceding issues", issue.errors.full_messages
120 end
120 end
121
121
122 def test_start_date_lesser_than_soonest_start_should_validate_on_update_if_unchanged
122 def test_start_date_lesser_than_soonest_start_should_validate_on_update_if_unchanged
123 issue = Issue.generate!(:start_date => '2013-06-04')
123 issue = Issue.generate!(:start_date => '2013-06-04')
124 issue.stubs(:soonest_start).returns(Date.parse('2013-06-10'))
124 issue.stubs(:soonest_start).returns(Date.parse('2013-06-10'))
125 assert issue.valid?
125 assert issue.valid?
126 end
126 end
127
127
128 def test_estimated_hours_should_be_validated
128 def test_estimated_hours_should_be_validated
129 set_language_if_valid 'en'
129 set_language_if_valid 'en'
130 ['-2'].each do |invalid|
130 ['-2'].each do |invalid|
131 issue = Issue.new(:estimated_hours => invalid)
131 issue = Issue.new(:estimated_hours => invalid)
132 assert !issue.valid?
132 assert !issue.valid?
133 assert_include 'Estimated time is invalid', issue.errors.full_messages
133 assert_include 'Estimated time is invalid', issue.errors.full_messages
134 end
134 end
135 end
135 end
136
136
137 def test_create_with_required_custom_field
137 def test_create_with_required_custom_field
138 set_language_if_valid 'en'
138 set_language_if_valid 'en'
139 field = IssueCustomField.find_by_name('Database')
139 field = IssueCustomField.find_by_name('Database')
140 field.update_attribute(:is_required, true)
140 field.update_attribute(:is_required, true)
141
141
142 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
142 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
143 :status_id => 1, :subject => 'test_create',
143 :status_id => 1, :subject => 'test_create',
144 :description => 'IssueTest#test_create_with_required_custom_field')
144 :description => 'IssueTest#test_create_with_required_custom_field')
145 assert issue.available_custom_fields.include?(field)
145 assert issue.available_custom_fields.include?(field)
146 # No value for the custom field
146 # No value for the custom field
147 assert !issue.save
147 assert !issue.save
148 assert_equal ["Database cannot be blank"], issue.errors.full_messages
148 assert_equal ["Database cannot be blank"], issue.errors.full_messages
149 # Blank value
149 # Blank value
150 issue.custom_field_values = { field.id => '' }
150 issue.custom_field_values = { field.id => '' }
151 assert !issue.save
151 assert !issue.save
152 assert_equal ["Database cannot be blank"], issue.errors.full_messages
152 assert_equal ["Database cannot be blank"], issue.errors.full_messages
153 # Invalid value
153 # Invalid value
154 issue.custom_field_values = { field.id => 'SQLServer' }
154 issue.custom_field_values = { field.id => 'SQLServer' }
155 assert !issue.save
155 assert !issue.save
156 assert_equal ["Database is not included in the list"], issue.errors.full_messages
156 assert_equal ["Database is not included in the list"], issue.errors.full_messages
157 # Valid value
157 # Valid value
158 issue.custom_field_values = { field.id => 'PostgreSQL' }
158 issue.custom_field_values = { field.id => 'PostgreSQL' }
159 assert issue.save
159 assert issue.save
160 issue.reload
160 issue.reload
161 assert_equal 'PostgreSQL', issue.custom_value_for(field).value
161 assert_equal 'PostgreSQL', issue.custom_value_for(field).value
162 end
162 end
163
163
164 def test_create_with_group_assignment
164 def test_create_with_group_assignment
165 with_settings :issue_group_assignment => '1' do
165 with_settings :issue_group_assignment => '1' do
166 assert Issue.new(:project_id => 2, :tracker_id => 1, :author_id => 1,
166 assert Issue.new(:project_id => 2, :tracker_id => 1, :author_id => 1,
167 :subject => 'Group assignment',
167 :subject => 'Group assignment',
168 :assigned_to_id => 11).save
168 :assigned_to_id => 11).save
169 issue = Issue.order('id DESC').first
169 issue = Issue.order('id DESC').first
170 assert_kind_of Group, issue.assigned_to
170 assert_kind_of Group, issue.assigned_to
171 assert_equal Group.find(11), issue.assigned_to
171 assert_equal Group.find(11), issue.assigned_to
172 end
172 end
173 end
173 end
174
174
175 def test_create_with_parent_issue_id
175 def test_create_with_parent_issue_id
176 issue = Issue.new(:project_id => 1, :tracker_id => 1,
176 issue = Issue.new(:project_id => 1, :tracker_id => 1,
177 :author_id => 1, :subject => 'Group assignment',
177 :author_id => 1, :subject => 'Group assignment',
178 :parent_issue_id => 1)
178 :parent_issue_id => 1)
179 assert_save issue
179 assert_save issue
180 assert_equal 1, issue.parent_issue_id
180 assert_equal 1, issue.parent_issue_id
181 assert_equal Issue.find(1), issue.parent
181 assert_equal Issue.find(1), issue.parent
182 end
182 end
183
183
184 def test_create_with_sharp_parent_issue_id
184 def test_create_with_sharp_parent_issue_id
185 issue = Issue.new(:project_id => 1, :tracker_id => 1,
185 issue = Issue.new(:project_id => 1, :tracker_id => 1,
186 :author_id => 1, :subject => 'Group assignment',
186 :author_id => 1, :subject => 'Group assignment',
187 :parent_issue_id => "#1")
187 :parent_issue_id => "#1")
188 assert_save issue
188 assert_save issue
189 assert_equal 1, issue.parent_issue_id
189 assert_equal 1, issue.parent_issue_id
190 assert_equal Issue.find(1), issue.parent
190 assert_equal Issue.find(1), issue.parent
191 end
191 end
192
192
193 def test_create_with_invalid_parent_issue_id
193 def test_create_with_invalid_parent_issue_id
194 set_language_if_valid 'en'
194 set_language_if_valid 'en'
195 issue = Issue.new(:project_id => 1, :tracker_id => 1,
195 issue = Issue.new(:project_id => 1, :tracker_id => 1,
196 :author_id => 1, :subject => 'Group assignment',
196 :author_id => 1, :subject => 'Group assignment',
197 :parent_issue_id => '01ABC')
197 :parent_issue_id => '01ABC')
198 assert !issue.save
198 assert !issue.save
199 assert_equal '01ABC', issue.parent_issue_id
199 assert_equal '01ABC', issue.parent_issue_id
200 assert_include 'Parent task is invalid', issue.errors.full_messages
200 assert_include 'Parent task is invalid', issue.errors.full_messages
201 end
201 end
202
202
203 def test_create_with_invalid_sharp_parent_issue_id
203 def test_create_with_invalid_sharp_parent_issue_id
204 set_language_if_valid 'en'
204 set_language_if_valid 'en'
205 issue = Issue.new(:project_id => 1, :tracker_id => 1,
205 issue = Issue.new(:project_id => 1, :tracker_id => 1,
206 :author_id => 1, :subject => 'Group assignment',
206 :author_id => 1, :subject => 'Group assignment',
207 :parent_issue_id => '#01ABC')
207 :parent_issue_id => '#01ABC')
208 assert !issue.save
208 assert !issue.save
209 assert_equal '#01ABC', issue.parent_issue_id
209 assert_equal '#01ABC', issue.parent_issue_id
210 assert_include 'Parent task is invalid', issue.errors.full_messages
210 assert_include 'Parent task is invalid', issue.errors.full_messages
211 end
211 end
212
212
213 def assert_visibility_match(user, issues)
213 def assert_visibility_match(user, issues)
214 assert_equal issues.collect(&:id).sort, Issue.all.select {|issue| issue.visible?(user)}.collect(&:id).sort
214 assert_equal issues.collect(&:id).sort, Issue.all.select {|issue| issue.visible?(user)}.collect(&:id).sort
215 end
215 end
216
216
217 def test_visible_scope_for_anonymous
217 def test_visible_scope_for_anonymous
218 # Anonymous user should see issues of public projects only
218 # Anonymous user should see issues of public projects only
219 issues = Issue.visible(User.anonymous).to_a
219 issues = Issue.visible(User.anonymous).to_a
220 assert issues.any?
220 assert issues.any?
221 assert_nil issues.detect {|issue| !issue.project.is_public?}
221 assert_nil issues.detect {|issue| !issue.project.is_public?}
222 assert_nil issues.detect {|issue| issue.is_private?}
222 assert_nil issues.detect {|issue| issue.is_private?}
223 assert_visibility_match User.anonymous, issues
223 assert_visibility_match User.anonymous, issues
224 end
224 end
225
225
226 def test_visible_scope_for_anonymous_without_view_issues_permissions
226 def test_visible_scope_for_anonymous_without_view_issues_permissions
227 # Anonymous user should not see issues without permission
227 # Anonymous user should not see issues without permission
228 Role.anonymous.remove_permission!(:view_issues)
228 Role.anonymous.remove_permission!(:view_issues)
229 issues = Issue.visible(User.anonymous).to_a
229 issues = Issue.visible(User.anonymous).to_a
230 assert issues.empty?
230 assert issues.empty?
231 assert_visibility_match User.anonymous, issues
231 assert_visibility_match User.anonymous, issues
232 end
232 end
233
233
234 def test_visible_scope_for_anonymous_without_view_issues_permissions_and_membership
234 def test_visible_scope_for_anonymous_without_view_issues_permissions_and_membership
235 Role.anonymous.remove_permission!(:view_issues)
235 Role.anonymous.remove_permission!(:view_issues)
236 Member.create!(:project_id => 1, :principal => Group.anonymous, :role_ids => [2])
236 Member.create!(:project_id => 1, :principal => Group.anonymous, :role_ids => [2])
237
237
238 issues = Issue.visible(User.anonymous).all
238 issues = Issue.visible(User.anonymous).all
239 assert issues.any?
239 assert issues.any?
240 assert_equal [1], issues.map(&:project_id).uniq.sort
240 assert_equal [1], issues.map(&:project_id).uniq.sort
241 assert_visibility_match User.anonymous, issues
241 assert_visibility_match User.anonymous, issues
242 end
242 end
243
243
244 def test_anonymous_should_not_see_private_issues_with_issues_visibility_set_to_default
244 def test_anonymous_should_not_see_private_issues_with_issues_visibility_set_to_default
245 assert Role.anonymous.update_attribute(:issues_visibility, 'default')
245 assert Role.anonymous.update_attribute(:issues_visibility, 'default')
246 issue = Issue.generate!(:author => User.anonymous, :assigned_to => User.anonymous, :is_private => true)
246 issue = Issue.generate!(:author => User.anonymous, :assigned_to => User.anonymous, :is_private => true)
247 assert_nil Issue.where(:id => issue.id).visible(User.anonymous).first
247 assert_nil Issue.where(:id => issue.id).visible(User.anonymous).first
248 assert !issue.visible?(User.anonymous)
248 assert !issue.visible?(User.anonymous)
249 end
249 end
250
250
251 def test_anonymous_should_not_see_private_issues_with_issues_visibility_set_to_own
251 def test_anonymous_should_not_see_private_issues_with_issues_visibility_set_to_own
252 assert Role.anonymous.update_attribute(:issues_visibility, 'own')
252 assert Role.anonymous.update_attribute(:issues_visibility, 'own')
253 issue = Issue.generate!(:author => User.anonymous, :assigned_to => User.anonymous, :is_private => true)
253 issue = Issue.generate!(:author => User.anonymous, :assigned_to => User.anonymous, :is_private => true)
254 assert_nil Issue.where(:id => issue.id).visible(User.anonymous).first
254 assert_nil Issue.where(:id => issue.id).visible(User.anonymous).first
255 assert !issue.visible?(User.anonymous)
255 assert !issue.visible?(User.anonymous)
256 end
256 end
257
257
258 def test_visible_scope_for_non_member
258 def test_visible_scope_for_non_member
259 user = User.find(9)
259 user = User.find(9)
260 assert user.projects.empty?
260 assert user.projects.empty?
261 # Non member user should see issues of public projects only
261 # Non member user should see issues of public projects only
262 issues = Issue.visible(user).to_a
262 issues = Issue.visible(user).to_a
263 assert issues.any?
263 assert issues.any?
264 assert_nil issues.detect {|issue| !issue.project.is_public?}
264 assert_nil issues.detect {|issue| !issue.project.is_public?}
265 assert_nil issues.detect {|issue| issue.is_private?}
265 assert_nil issues.detect {|issue| issue.is_private?}
266 assert_visibility_match user, issues
266 assert_visibility_match user, issues
267 end
267 end
268
268
269 def test_visible_scope_for_non_member_with_own_issues_visibility
269 def test_visible_scope_for_non_member_with_own_issues_visibility
270 Role.non_member.update_attribute :issues_visibility, 'own'
270 Role.non_member.update_attribute :issues_visibility, 'own'
271 Issue.create!(:project_id => 1, :tracker_id => 1, :author_id => 9, :subject => 'Issue by non member')
271 Issue.create!(:project_id => 1, :tracker_id => 1, :author_id => 9, :subject => 'Issue by non member')
272 user = User.find(9)
272 user = User.find(9)
273
273
274 issues = Issue.visible(user).to_a
274 issues = Issue.visible(user).to_a
275 assert issues.any?
275 assert issues.any?
276 assert_nil issues.detect {|issue| issue.author != user}
276 assert_nil issues.detect {|issue| issue.author != user}
277 assert_visibility_match user, issues
277 assert_visibility_match user, issues
278 end
278 end
279
279
280 def test_visible_scope_for_non_member_without_view_issues_permissions
280 def test_visible_scope_for_non_member_without_view_issues_permissions
281 # Non member user should not see issues without permission
281 # Non member user should not see issues without permission
282 Role.non_member.remove_permission!(:view_issues)
282 Role.non_member.remove_permission!(:view_issues)
283 user = User.find(9)
283 user = User.find(9)
284 assert user.projects.empty?
284 assert user.projects.empty?
285 issues = Issue.visible(user).to_a
285 issues = Issue.visible(user).to_a
286 assert issues.empty?
286 assert issues.empty?
287 assert_visibility_match user, issues
287 assert_visibility_match user, issues
288 end
288 end
289
289
290 def test_visible_scope_for_non_member_without_view_issues_permissions_and_membership
290 def test_visible_scope_for_non_member_without_view_issues_permissions_and_membership
291 Role.non_member.remove_permission!(:view_issues)
291 Role.non_member.remove_permission!(:view_issues)
292 Member.create!(:project_id => 1, :principal => Group.non_member, :role_ids => [2])
292 Member.create!(:project_id => 1, :principal => Group.non_member, :role_ids => [2])
293 user = User.find(9)
293 user = User.find(9)
294
294
295 issues = Issue.visible(user).all
295 issues = Issue.visible(user).all
296 assert issues.any?
296 assert issues.any?
297 assert_equal [1], issues.map(&:project_id).uniq.sort
297 assert_equal [1], issues.map(&:project_id).uniq.sort
298 assert_visibility_match user, issues
298 assert_visibility_match user, issues
299 end
299 end
300
300
301 def test_visible_scope_for_member
301 def test_visible_scope_for_member
302 user = User.find(9)
302 user = User.find(9)
303 # User should see issues of projects for which user has view_issues permissions only
303 # User should see issues of projects for which user has view_issues permissions only
304 Role.non_member.remove_permission!(:view_issues)
304 Role.non_member.remove_permission!(:view_issues)
305 Member.create!(:principal => user, :project_id => 3, :role_ids => [2])
305 Member.create!(:principal => user, :project_id => 3, :role_ids => [2])
306 issues = Issue.visible(user).to_a
306 issues = Issue.visible(user).to_a
307 assert issues.any?
307 assert issues.any?
308 assert_nil issues.detect {|issue| issue.project_id != 3}
308 assert_nil issues.detect {|issue| issue.project_id != 3}
309 assert_nil issues.detect {|issue| issue.is_private?}
309 assert_nil issues.detect {|issue| issue.is_private?}
310 assert_visibility_match user, issues
310 assert_visibility_match user, issues
311 end
311 end
312
312
313 def test_visible_scope_for_member_without_view_issues_permission_and_non_member_role_having_the_permission
313 def test_visible_scope_for_member_without_view_issues_permission_and_non_member_role_having_the_permission
314 Role.non_member.add_permission!(:view_issues)
314 Role.non_member.add_permission!(:view_issues)
315 Role.find(1).remove_permission!(:view_issues)
315 Role.find(1).remove_permission!(:view_issues)
316 user = User.find(2)
316 user = User.find(2)
317
317
318 assert_equal 0, Issue.where(:project_id => 1).visible(user).count
318 assert_equal 0, Issue.where(:project_id => 1).visible(user).count
319 assert_equal false, Issue.where(:project_id => 1).first.visible?(user)
319 assert_equal false, Issue.where(:project_id => 1).first.visible?(user)
320 end
320 end
321
321
322 def test_visible_scope_for_member_with_groups_should_return_assigned_issues
322 def test_visible_scope_for_member_with_groups_should_return_assigned_issues
323 user = User.find(8)
323 user = User.find(8)
324 assert user.groups.any?
324 assert user.groups.any?
325 Member.create!(:principal => user.groups.first, :project_id => 1, :role_ids => [2])
325 Member.create!(:principal => user.groups.first, :project_id => 1, :role_ids => [2])
326 Role.non_member.remove_permission!(:view_issues)
326 Role.non_member.remove_permission!(:view_issues)
327
327
328 issue = Issue.create!(:project_id => 1, :tracker_id => 1, :author_id => 3,
328 issue = Issue.create!(:project_id => 1, :tracker_id => 1, :author_id => 3,
329 :status_id => 1, :priority => IssuePriority.all.first,
329 :status_id => 1, :priority => IssuePriority.all.first,
330 :subject => 'Assignment test',
330 :subject => 'Assignment test',
331 :assigned_to => user.groups.first,
331 :assigned_to => user.groups.first,
332 :is_private => true)
332 :is_private => true)
333
333
334 Role.find(2).update_attribute :issues_visibility, 'default'
334 Role.find(2).update_attribute :issues_visibility, 'default'
335 issues = Issue.visible(User.find(8)).to_a
335 issues = Issue.visible(User.find(8)).to_a
336 assert issues.any?
336 assert issues.any?
337 assert issues.include?(issue)
337 assert issues.include?(issue)
338
338
339 Role.find(2).update_attribute :issues_visibility, 'own'
339 Role.find(2).update_attribute :issues_visibility, 'own'
340 issues = Issue.visible(User.find(8)).to_a
340 issues = Issue.visible(User.find(8)).to_a
341 assert issues.any?
341 assert issues.any?
342 assert_include issue, issues
342 assert_include issue, issues
343 end
343 end
344
344
345 def test_visible_scope_for_admin
345 def test_visible_scope_for_admin
346 user = User.find(1)
346 user = User.find(1)
347 user.members.each(&:destroy)
347 user.members.each(&:destroy)
348 assert user.projects.empty?
348 assert user.projects.empty?
349 issues = Issue.visible(user).to_a
349 issues = Issue.visible(user).to_a
350 assert issues.any?
350 assert issues.any?
351 # Admin should see issues on private projects that admin does not belong to
351 # Admin should see issues on private projects that admin does not belong to
352 assert issues.detect {|issue| !issue.project.is_public?}
352 assert issues.detect {|issue| !issue.project.is_public?}
353 # Admin should see private issues of other users
353 # Admin should see private issues of other users
354 assert issues.detect {|issue| issue.is_private? && issue.author != user}
354 assert issues.detect {|issue| issue.is_private? && issue.author != user}
355 assert_visibility_match user, issues
355 assert_visibility_match user, issues
356 end
356 end
357
357
358 def test_visible_scope_with_project
358 def test_visible_scope_with_project
359 project = Project.find(1)
359 project = Project.find(1)
360 issues = Issue.visible(User.find(2), :project => project).to_a
360 issues = Issue.visible(User.find(2), :project => project).to_a
361 projects = issues.collect(&:project).uniq
361 projects = issues.collect(&:project).uniq
362 assert_equal 1, projects.size
362 assert_equal 1, projects.size
363 assert_equal project, projects.first
363 assert_equal project, projects.first
364 end
364 end
365
365
366 def test_visible_scope_with_project_and_subprojects
366 def test_visible_scope_with_project_and_subprojects
367 project = Project.find(1)
367 project = Project.find(1)
368 issues = Issue.visible(User.find(2), :project => project, :with_subprojects => true).to_a
368 issues = Issue.visible(User.find(2), :project => project, :with_subprojects => true).to_a
369 projects = issues.collect(&:project).uniq
369 projects = issues.collect(&:project).uniq
370 assert projects.size > 1
370 assert projects.size > 1
371 assert_equal [], projects.select {|p| !p.is_or_is_descendant_of?(project)}
371 assert_equal [], projects.select {|p| !p.is_or_is_descendant_of?(project)}
372 end
372 end
373
373
374 def test_visible_and_nested_set_scopes
374 def test_visible_and_nested_set_scopes
375 user = User.generate!
375 user = User.generate!
376 parent = Issue.generate!(:assigned_to => user)
376 parent = Issue.generate!(:assigned_to => user)
377 assert parent.visible?(user)
377 assert parent.visible?(user)
378 child1 = Issue.generate!(:parent_issue_id => parent.id, :assigned_to => user)
378 child1 = Issue.generate!(:parent_issue_id => parent.id, :assigned_to => user)
379 child2 = Issue.generate!(:parent_issue_id => parent.id, :assigned_to => user)
379 child2 = Issue.generate!(:parent_issue_id => parent.id, :assigned_to => user)
380 parent.reload
380 parent.reload
381 child1.reload
381 child1.reload
382 child2.reload
382 child2.reload
383 assert child1.visible?(user)
383 assert child1.visible?(user)
384 assert child2.visible?(user)
384 assert child2.visible?(user)
385 assert_equal 2, parent.descendants.count
385 assert_equal 2, parent.descendants.count
386 assert_equal 2, parent.descendants.visible(user).count
386 assert_equal 2, parent.descendants.visible(user).count
387 # awesome_nested_set 2-1-stable branch has regression.
387 # awesome_nested_set 2-1-stable branch has regression.
388 # https://github.com/collectiveidea/awesome_nested_set/commit/3d5ac746542b564f6586c2316180254b088bebb6
388 # https://github.com/collectiveidea/awesome_nested_set/commit/3d5ac746542b564f6586c2316180254b088bebb6
389 # ActiveRecord::StatementInvalid: SQLite3::SQLException: ambiguous column name: lft:
389 # ActiveRecord::StatementInvalid: SQLite3::SQLException: ambiguous column name: lft:
390 assert_equal 2, parent.descendants.collect{|i| i}.size
390 assert_equal 2, parent.descendants.collect{|i| i}.size
391 assert_equal 2, parent.descendants.visible(user).collect{|i| i}.size
391 assert_equal 2, parent.descendants.visible(user).collect{|i| i}.size
392 end
392 end
393
393
394 def test_visible_scope_with_unsaved_user_should_not_raise_an_error
394 def test_visible_scope_with_unsaved_user_should_not_raise_an_error
395 user = User.new
395 user = User.new
396 assert_nothing_raised do
396 assert_nothing_raised do
397 Issue.visible(user).to_a
397 Issue.visible(user).to_a
398 end
398 end
399 end
399 end
400
400
401 def test_open_scope
401 def test_open_scope
402 issues = Issue.open.to_a
402 issues = Issue.open.to_a
403 assert_nil issues.detect(&:closed?)
403 assert_nil issues.detect(&:closed?)
404 end
404 end
405
405
406 def test_open_scope_with_arg
406 def test_open_scope_with_arg
407 issues = Issue.open(false).to_a
407 issues = Issue.open(false).to_a
408 assert_equal issues, issues.select(&:closed?)
408 assert_equal issues, issues.select(&:closed?)
409 end
409 end
410
410
411 def test_fixed_version_scope_with_a_version_should_return_its_fixed_issues
411 def test_fixed_version_scope_with_a_version_should_return_its_fixed_issues
412 version = Version.find(2)
412 version = Version.find(2)
413 assert version.fixed_issues.any?
413 assert version.fixed_issues.any?
414 assert_equal version.fixed_issues.to_a.sort, Issue.fixed_version(version).to_a.sort
414 assert_equal version.fixed_issues.to_a.sort, Issue.fixed_version(version).to_a.sort
415 end
415 end
416
416
417 def test_fixed_version_scope_with_empty_array_should_return_no_result
417 def test_fixed_version_scope_with_empty_array_should_return_no_result
418 assert_equal 0, Issue.fixed_version([]).count
418 assert_equal 0, Issue.fixed_version([]).count
419 end
419 end
420
420
421 def test_assigned_to_scope_should_return_issues_assigned_to_the_user
421 def test_assigned_to_scope_should_return_issues_assigned_to_the_user
422 user = User.generate!
422 user = User.generate!
423 issue = Issue.generate!
423 issue = Issue.generate!
424 Issue.where(:id => issue.id).update_all :assigned_to_id => user.id
424 Issue.where(:id => issue.id).update_all :assigned_to_id => user.id
425 assert_equal [issue], Issue.assigned_to(user).to_a
425 assert_equal [issue], Issue.assigned_to(user).to_a
426 end
426 end
427
427
428 def test_assigned_to_scope_should_return_issues_assigned_to_the_user_groups
428 def test_assigned_to_scope_should_return_issues_assigned_to_the_user_groups
429 group = Group.generate!
429 group = Group.generate!
430 user = User.generate!
430 user = User.generate!
431 group.users << user
431 group.users << user
432 issue = Issue.generate!
432 issue = Issue.generate!
433 Issue.where(:id => issue.id).update_all :assigned_to_id => group.id
433 Issue.where(:id => issue.id).update_all :assigned_to_id => group.id
434 assert_equal [issue], Issue.assigned_to(user).to_a
434 assert_equal [issue], Issue.assigned_to(user).to_a
435 end
435 end
436
436
437 def test_errors_full_messages_should_include_custom_fields_errors
437 def test_errors_full_messages_should_include_custom_fields_errors
438 field = IssueCustomField.find_by_name('Database')
438 field = IssueCustomField.find_by_name('Database')
439
439
440 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
440 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
441 :status_id => 1, :subject => 'test_create',
441 :status_id => 1, :subject => 'test_create',
442 :description => 'IssueTest#test_create_with_required_custom_field')
442 :description => 'IssueTest#test_create_with_required_custom_field')
443 assert issue.available_custom_fields.include?(field)
443 assert issue.available_custom_fields.include?(field)
444 # Invalid value
444 # Invalid value
445 issue.custom_field_values = { field.id => 'SQLServer' }
445 issue.custom_field_values = { field.id => 'SQLServer' }
446
446
447 assert !issue.valid?
447 assert !issue.valid?
448 assert_equal 1, issue.errors.full_messages.size
448 assert_equal 1, issue.errors.full_messages.size
449 assert_equal "Database #{I18n.translate('activerecord.errors.messages.inclusion')}",
449 assert_equal "Database #{I18n.translate('activerecord.errors.messages.inclusion')}",
450 issue.errors.full_messages.first
450 issue.errors.full_messages.first
451 end
451 end
452
452
453 def test_update_issue_with_required_custom_field
453 def test_update_issue_with_required_custom_field
454 field = IssueCustomField.find_by_name('Database')
454 field = IssueCustomField.find_by_name('Database')
455 field.update_attribute(:is_required, true)
455 field.update_attribute(:is_required, true)
456
456
457 issue = Issue.find(1)
457 issue = Issue.find(1)
458 assert_nil issue.custom_value_for(field)
458 assert_nil issue.custom_value_for(field)
459 assert issue.available_custom_fields.include?(field)
459 assert issue.available_custom_fields.include?(field)
460 # No change to custom values, issue can be saved
460 # No change to custom values, issue can be saved
461 assert issue.save
461 assert issue.save
462 # Blank value
462 # Blank value
463 issue.custom_field_values = { field.id => '' }
463 issue.custom_field_values = { field.id => '' }
464 assert !issue.save
464 assert !issue.save
465 # Valid value
465 # Valid value
466 issue.custom_field_values = { field.id => 'PostgreSQL' }
466 issue.custom_field_values = { field.id => 'PostgreSQL' }
467 assert issue.save
467 assert issue.save
468 issue.reload
468 issue.reload
469 assert_equal 'PostgreSQL', issue.custom_value_for(field).value
469 assert_equal 'PostgreSQL', issue.custom_value_for(field).value
470 end
470 end
471
471
472 def test_should_not_update_attributes_if_custom_fields_validation_fails
472 def test_should_not_update_attributes_if_custom_fields_validation_fails
473 issue = Issue.find(1)
473 issue = Issue.find(1)
474 field = IssueCustomField.find_by_name('Database')
474 field = IssueCustomField.find_by_name('Database')
475 assert issue.available_custom_fields.include?(field)
475 assert issue.available_custom_fields.include?(field)
476
476
477 issue.custom_field_values = { field.id => 'Invalid' }
477 issue.custom_field_values = { field.id => 'Invalid' }
478 issue.subject = 'Should be not be saved'
478 issue.subject = 'Should be not be saved'
479 assert !issue.save
479 assert !issue.save
480
480
481 issue.reload
481 issue.reload
482 assert_equal "Cannot print recipes", issue.subject
482 assert_equal "Cannot print recipes", issue.subject
483 end
483 end
484
484
485 def test_should_not_recreate_custom_values_objects_on_update
485 def test_should_not_recreate_custom_values_objects_on_update
486 field = IssueCustomField.find_by_name('Database')
486 field = IssueCustomField.find_by_name('Database')
487
487
488 issue = Issue.find(1)
488 issue = Issue.find(1)
489 issue.custom_field_values = { field.id => 'PostgreSQL' }
489 issue.custom_field_values = { field.id => 'PostgreSQL' }
490 assert issue.save
490 assert issue.save
491 custom_value = issue.custom_value_for(field)
491 custom_value = issue.custom_value_for(field)
492 issue.reload
492 issue.reload
493 issue.custom_field_values = { field.id => 'MySQL' }
493 issue.custom_field_values = { field.id => 'MySQL' }
494 assert issue.save
494 assert issue.save
495 issue.reload
495 issue.reload
496 assert_equal custom_value.id, issue.custom_value_for(field).id
496 assert_equal custom_value.id, issue.custom_value_for(field).id
497 end
497 end
498
498
499 def test_setting_project_should_set_version_to_default_version
499 def test_setting_project_should_set_version_to_default_version
500 version = Version.generate!(:project_id => 1)
500 version = Version.generate!(:project_id => 1)
501 Project.find(1).update_attribute(:default_version_id, version.id)
501 Project.find(1).update_attribute(:default_version_id, version.id)
502
502
503 issue = Issue.new(:project_id => 1)
503 issue = Issue.new(:project_id => 1)
504 assert_equal version, issue.fixed_version
504 assert_equal version, issue.fixed_version
505 end
505 end
506
506
507 def test_should_not_update_custom_fields_on_changing_tracker_with_different_custom_fields
507 def test_should_not_update_custom_fields_on_changing_tracker_with_different_custom_fields
508 issue = Issue.create!(:project_id => 1, :tracker_id => 1, :author_id => 1,
508 issue = Issue.create!(:project_id => 1, :tracker_id => 1, :author_id => 1,
509 :status_id => 1, :subject => 'Test',
509 :status_id => 1, :subject => 'Test',
510 :custom_field_values => {'2' => 'Test'})
510 :custom_field_values => {'2' => 'Test'})
511 assert !Tracker.find(2).custom_field_ids.include?(2)
511 assert !Tracker.find(2).custom_field_ids.include?(2)
512
512
513 issue = Issue.find(issue.id)
513 issue = Issue.find(issue.id)
514 issue.attributes = {:tracker_id => 2, :custom_field_values => {'1' => ''}}
514 issue.attributes = {:tracker_id => 2, :custom_field_values => {'1' => ''}}
515
515
516 issue = Issue.find(issue.id)
516 issue = Issue.find(issue.id)
517 custom_value = issue.custom_value_for(2)
517 custom_value = issue.custom_value_for(2)
518 assert_not_nil custom_value
518 assert_not_nil custom_value
519 assert_equal 'Test', custom_value.value
519 assert_equal 'Test', custom_value.value
520 end
520 end
521
521
522 def test_assigning_tracker_id_should_reload_custom_fields_values
522 def test_assigning_tracker_id_should_reload_custom_fields_values
523 issue = Issue.new(:project => Project.find(1))
523 issue = Issue.new(:project => Project.find(1))
524 assert issue.custom_field_values.empty?
524 assert issue.custom_field_values.empty?
525 issue.tracker_id = 1
525 issue.tracker_id = 1
526 assert issue.custom_field_values.any?
526 assert issue.custom_field_values.any?
527 end
527 end
528
528
529 def test_assigning_attributes_should_assign_project_and_tracker_first
529 def test_assigning_attributes_should_assign_project_and_tracker_first
530 seq = sequence('seq')
530 seq = sequence('seq')
531 issue = Issue.new
531 issue = Issue.new
532 issue.expects(:project_id=).in_sequence(seq)
532 issue.expects(:project_id=).in_sequence(seq)
533 issue.expects(:tracker_id=).in_sequence(seq)
533 issue.expects(:tracker_id=).in_sequence(seq)
534 issue.expects(:subject=).in_sequence(seq)
534 issue.expects(:subject=).in_sequence(seq)
535 issue.attributes = {:tracker_id => 2, :project_id => 1, :subject => 'Test'}
535 issue.attributes = {:tracker_id => 2, :project_id => 1, :subject => 'Test'}
536 end
536 end
537
537
538 def test_assigning_tracker_and_custom_fields_should_assign_custom_fields
538 def test_assigning_tracker_and_custom_fields_should_assign_custom_fields
539 attributes = ActiveSupport::OrderedHash.new
539 attributes = ActiveSupport::OrderedHash.new
540 attributes['custom_field_values'] = { '1' => 'MySQL' }
540 attributes['custom_field_values'] = { '1' => 'MySQL' }
541 attributes['tracker_id'] = '1'
541 attributes['tracker_id'] = '1'
542 issue = Issue.new(:project => Project.find(1))
542 issue = Issue.new(:project => Project.find(1))
543 issue.attributes = attributes
543 issue.attributes = attributes
544 assert_equal 'MySQL', issue.custom_field_value(1)
544 assert_equal 'MySQL', issue.custom_field_value(1)
545 end
545 end
546
546
547 def test_changing_tracker_should_clear_disabled_core_fields
547 def test_changing_tracker_should_clear_disabled_core_fields
548 tracker = Tracker.find(2)
548 tracker = Tracker.find(2)
549 tracker.core_fields = tracker.core_fields - %w(due_date)
549 tracker.core_fields = tracker.core_fields - %w(due_date)
550 tracker.save!
550 tracker.save!
551
551
552 issue = Issue.generate!(:tracker_id => 1, :start_date => Date.today, :due_date => Date.today)
552 issue = Issue.generate!(:tracker_id => 1, :start_date => Date.today, :due_date => Date.today)
553 issue.save!
553 issue.save!
554
554
555 issue.tracker_id = 2
555 issue.tracker_id = 2
556 issue.save!
556 issue.save!
557 assert_not_nil issue.start_date
557 assert_not_nil issue.start_date
558 assert_nil issue.due_date
558 assert_nil issue.due_date
559 end
559 end
560
560
561 def test_changing_tracker_should_not_add_cleared_fields_to_journal
561 def test_changing_tracker_should_not_add_cleared_fields_to_journal
562 tracker = Tracker.find(2)
562 tracker = Tracker.find(2)
563 tracker.core_fields = tracker.core_fields - %w(due_date)
563 tracker.core_fields = tracker.core_fields - %w(due_date)
564 tracker.save!
564 tracker.save!
565
565
566 issue = Issue.generate!(:tracker_id => 1, :due_date => Date.today)
566 issue = Issue.generate!(:tracker_id => 1, :due_date => Date.today)
567 issue.save!
567 issue.save!
568
568
569 assert_difference 'Journal.count' do
569 assert_difference 'Journal.count' do
570 issue.init_journal User.find(1)
570 issue.init_journal User.find(1)
571 issue.tracker_id = 2
571 issue.tracker_id = 2
572 issue.save!
572 issue.save!
573 assert_nil issue.due_date
573 assert_nil issue.due_date
574 end
574 end
575 journal = Journal.order('id DESC').first
575 journal = Journal.order('id DESC').first
576 assert_equal 1, journal.details.count
576 assert_equal 1, journal.details.count
577 end
577 end
578
578
579 def test_reload_should_reload_custom_field_values
579 def test_reload_should_reload_custom_field_values
580 issue = Issue.generate!
580 issue = Issue.generate!
581 issue.custom_field_values = {'2' => 'Foo'}
581 issue.custom_field_values = {'2' => 'Foo'}
582 issue.save!
582 issue.save!
583
583
584 issue = Issue.order('id desc').first
584 issue = Issue.order('id desc').first
585 assert_equal 'Foo', issue.custom_field_value(2)
585 assert_equal 'Foo', issue.custom_field_value(2)
586
586
587 issue.custom_field_values = {'2' => 'Bar'}
587 issue.custom_field_values = {'2' => 'Bar'}
588 assert_equal 'Bar', issue.custom_field_value(2)
588 assert_equal 'Bar', issue.custom_field_value(2)
589
589
590 issue.reload
590 issue.reload
591 assert_equal 'Foo', issue.custom_field_value(2)
591 assert_equal 'Foo', issue.custom_field_value(2)
592 end
592 end
593
593
594 def test_should_update_issue_with_disabled_tracker
594 def test_should_update_issue_with_disabled_tracker
595 p = Project.find(1)
595 p = Project.find(1)
596 issue = Issue.find(1)
596 issue = Issue.find(1)
597
597
598 p.trackers.delete(issue.tracker)
598 p.trackers.delete(issue.tracker)
599 assert !p.trackers.include?(issue.tracker)
599 assert !p.trackers.include?(issue.tracker)
600
600
601 issue.reload
601 issue.reload
602 issue.subject = 'New subject'
602 issue.subject = 'New subject'
603 assert issue.save
603 assert issue.save
604 end
604 end
605
605
606 def test_should_not_set_a_disabled_tracker
606 def test_should_not_set_a_disabled_tracker
607 p = Project.find(1)
607 p = Project.find(1)
608 p.trackers.delete(Tracker.find(2))
608 p.trackers.delete(Tracker.find(2))
609
609
610 issue = Issue.find(1)
610 issue = Issue.find(1)
611 issue.tracker_id = 2
611 issue.tracker_id = 2
612 issue.subject = 'New subject'
612 issue.subject = 'New subject'
613 assert !issue.save
613 assert !issue.save
614 assert_not_equal [], issue.errors[:tracker_id]
614 assert_not_equal [], issue.errors[:tracker_id]
615 end
615 end
616
616
617 def test_category_based_assignment
617 def test_category_based_assignment
618 issue = Issue.create(:project_id => 1, :tracker_id => 1, :author_id => 3,
618 issue = Issue.create(:project_id => 1, :tracker_id => 1, :author_id => 3,
619 :status_id => 1, :priority => IssuePriority.all.first,
619 :status_id => 1, :priority => IssuePriority.all.first,
620 :subject => 'Assignment test',
620 :subject => 'Assignment test',
621 :description => 'Assignment test', :category_id => 1)
621 :description => 'Assignment test', :category_id => 1)
622 assert_equal IssueCategory.find(1).assigned_to, issue.assigned_to
622 assert_equal IssueCategory.find(1).assigned_to, issue.assigned_to
623 end
623 end
624
624
625 def test_new_statuses_allowed_to
625 def test_new_statuses_allowed_to
626 WorkflowTransition.delete_all
626 WorkflowTransition.delete_all
627 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
627 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
628 :old_status_id => 1, :new_status_id => 2,
628 :old_status_id => 1, :new_status_id => 2,
629 :author => false, :assignee => false)
629 :author => false, :assignee => false)
630 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
630 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
631 :old_status_id => 1, :new_status_id => 3,
631 :old_status_id => 1, :new_status_id => 3,
632 :author => true, :assignee => false)
632 :author => true, :assignee => false)
633 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
633 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
634 :old_status_id => 1, :new_status_id => 4,
634 :old_status_id => 1, :new_status_id => 4,
635 :author => false, :assignee => true)
635 :author => false, :assignee => true)
636 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
636 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
637 :old_status_id => 1, :new_status_id => 5,
637 :old_status_id => 1, :new_status_id => 5,
638 :author => true, :assignee => true)
638 :author => true, :assignee => true)
639 status = IssueStatus.find(1)
639 status = IssueStatus.find(1)
640 role = Role.find(1)
640 role = Role.find(1)
641 tracker = Tracker.find(1)
641 tracker = Tracker.find(1)
642 user = User.find(2)
642 user = User.find(2)
643
643
644 issue = Issue.generate!(:tracker => tracker, :status => status,
644 issue = Issue.generate!(:tracker => tracker, :status => status,
645 :project_id => 1, :author_id => 1)
645 :project_id => 1, :author_id => 1)
646 assert_equal [1, 2], issue.new_statuses_allowed_to(user).map(&:id)
646 assert_equal [1, 2], issue.new_statuses_allowed_to(user).map(&:id)
647
647
648 issue = Issue.generate!(:tracker => tracker, :status => status,
648 issue = Issue.generate!(:tracker => tracker, :status => status,
649 :project_id => 1, :author => user)
649 :project_id => 1, :author => user)
650 assert_equal [1, 2, 3, 5], issue.new_statuses_allowed_to(user).map(&:id)
650 assert_equal [1, 2, 3, 5], issue.new_statuses_allowed_to(user).map(&:id)
651
651
652 issue = Issue.generate!(:tracker => tracker, :status => status,
652 issue = Issue.generate!(:tracker => tracker, :status => status,
653 :project_id => 1, :author_id => 1,
653 :project_id => 1, :author_id => 1,
654 :assigned_to => user)
654 :assigned_to => user)
655 assert_equal [1, 2, 4, 5], issue.new_statuses_allowed_to(user).map(&:id)
655 assert_equal [1, 2, 4, 5], issue.new_statuses_allowed_to(user).map(&:id)
656
656
657 issue = Issue.generate!(:tracker => tracker, :status => status,
657 issue = Issue.generate!(:tracker => tracker, :status => status,
658 :project_id => 1, :author => user,
658 :project_id => 1, :author => user,
659 :assigned_to => user)
659 :assigned_to => user)
660 assert_equal [1, 2, 3, 4, 5], issue.new_statuses_allowed_to(user).map(&:id)
660 assert_equal [1, 2, 3, 4, 5], issue.new_statuses_allowed_to(user).map(&:id)
661
661
662 group = Group.generate!
662 group = Group.generate!
663 group.users << user
663 group.users << user
664 issue = Issue.generate!(:tracker => tracker, :status => status,
664 issue = Issue.generate!(:tracker => tracker, :status => status,
665 :project_id => 1, :author => user,
665 :project_id => 1, :author => user,
666 :assigned_to => group)
666 :assigned_to => group)
667 assert_equal [1, 2, 3, 4, 5], issue.new_statuses_allowed_to(user).map(&:id)
667 assert_equal [1, 2, 3, 4, 5], issue.new_statuses_allowed_to(user).map(&:id)
668 end
668 end
669
669
670 def test_new_statuses_allowed_to_should_consider_group_assignment
670 def test_new_statuses_allowed_to_should_consider_group_assignment
671 WorkflowTransition.delete_all
671 WorkflowTransition.delete_all
672 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
672 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
673 :old_status_id => 1, :new_status_id => 4,
673 :old_status_id => 1, :new_status_id => 4,
674 :author => false, :assignee => true)
674 :author => false, :assignee => true)
675 user = User.find(2)
675 user = User.find(2)
676 group = Group.generate!
676 group = Group.generate!
677 group.users << user
677 group.users << user
678
678
679 issue = Issue.generate!(:author_id => 1, :assigned_to => group)
679 issue = Issue.generate!(:author_id => 1, :assigned_to => group)
680 assert_include 4, issue.new_statuses_allowed_to(user).map(&:id)
680 assert_include 4, issue.new_statuses_allowed_to(user).map(&:id)
681 end
681 end
682
682
683 def test_new_statuses_allowed_to_should_return_all_transitions_for_admin
683 def test_new_statuses_allowed_to_should_return_all_transitions_for_admin
684 admin = User.find(1)
684 admin = User.find(1)
685 issue = Issue.find(1)
685 issue = Issue.find(1)
686 assert !admin.member_of?(issue.project)
686 assert !admin.member_of?(issue.project)
687 expected_statuses = [issue.status] +
687 expected_statuses = [issue.status] +
688 WorkflowTransition.where(:old_status_id => issue.status_id).
688 WorkflowTransition.where(:old_status_id => issue.status_id).
689 map(&:new_status).uniq.sort
689 map(&:new_status).uniq.sort
690 assert_equal expected_statuses, issue.new_statuses_allowed_to(admin)
690 assert_equal expected_statuses, issue.new_statuses_allowed_to(admin)
691 end
691 end
692
692
693 def test_new_statuses_allowed_to_should_return_default_and_current_status_when_copying
693 def test_new_statuses_allowed_to_should_return_default_and_current_status_when_copying
694 issue = Issue.find(1).copy
694 issue = Issue.find(1).copy
695 assert_equal [1], issue.new_statuses_allowed_to(User.find(2)).map(&:id)
695 assert_equal [1], issue.new_statuses_allowed_to(User.find(2)).map(&:id)
696
696
697 issue = Issue.find(2).copy
697 issue = Issue.find(2).copy
698 assert_equal [1, 2], issue.new_statuses_allowed_to(User.find(2)).map(&:id)
698 assert_equal [1, 2], issue.new_statuses_allowed_to(User.find(2)).map(&:id)
699 end
699 end
700
700
701 def test_safe_attributes_names_should_not_include_disabled_field
701 def test_safe_attributes_names_should_not_include_disabled_field
702 tracker = Tracker.new(:core_fields => %w(assigned_to_id fixed_version_id))
702 tracker = Tracker.new(:core_fields => %w(assigned_to_id fixed_version_id))
703
703
704 issue = Issue.new(:tracker => tracker)
704 issue = Issue.new(:tracker => tracker)
705 assert_include 'tracker_id', issue.safe_attribute_names
705 assert_include 'tracker_id', issue.safe_attribute_names
706 assert_include 'status_id', issue.safe_attribute_names
706 assert_include 'status_id', issue.safe_attribute_names
707 assert_include 'subject', issue.safe_attribute_names
707 assert_include 'subject', issue.safe_attribute_names
708 assert_include 'description', issue.safe_attribute_names
708 assert_include 'description', issue.safe_attribute_names
709 assert_include 'custom_field_values', issue.safe_attribute_names
709 assert_include 'custom_field_values', issue.safe_attribute_names
710 assert_include 'custom_fields', issue.safe_attribute_names
710 assert_include 'custom_fields', issue.safe_attribute_names
711 assert_include 'lock_version', issue.safe_attribute_names
711 assert_include 'lock_version', issue.safe_attribute_names
712
712
713 tracker.core_fields.each do |field|
713 tracker.core_fields.each do |field|
714 assert_include field, issue.safe_attribute_names
714 assert_include field, issue.safe_attribute_names
715 end
715 end
716
716
717 tracker.disabled_core_fields.each do |field|
717 tracker.disabled_core_fields.each do |field|
718 assert_not_include field, issue.safe_attribute_names
718 assert_not_include field, issue.safe_attribute_names
719 end
719 end
720 end
720 end
721
721
722 def test_safe_attributes_should_ignore_disabled_fields
722 def test_safe_attributes_should_ignore_disabled_fields
723 tracker = Tracker.find(1)
723 tracker = Tracker.find(1)
724 tracker.core_fields = %w(assigned_to_id due_date)
724 tracker.core_fields = %w(assigned_to_id due_date)
725 tracker.save!
725 tracker.save!
726
726
727 issue = Issue.new(:tracker => tracker)
727 issue = Issue.new(:tracker => tracker)
728 issue.safe_attributes = {'start_date' => '2012-07-14', 'due_date' => '2012-07-14'}
728 issue.safe_attributes = {'start_date' => '2012-07-14', 'due_date' => '2012-07-14'}
729 assert_nil issue.start_date
729 assert_nil issue.start_date
730 assert_equal Date.parse('2012-07-14'), issue.due_date
730 assert_equal Date.parse('2012-07-14'), issue.due_date
731 end
731 end
732
732
733 def test_safe_attributes_should_accept_target_tracker_enabled_fields
733 def test_safe_attributes_should_accept_target_tracker_enabled_fields
734 source = Tracker.find(1)
734 source = Tracker.find(1)
735 source.core_fields = []
735 source.core_fields = []
736 source.save!
736 source.save!
737 target = Tracker.find(2)
737 target = Tracker.find(2)
738 target.core_fields = %w(assigned_to_id due_date)
738 target.core_fields = %w(assigned_to_id due_date)
739 target.save!
739 target.save!
740
740
741 issue = Issue.new(:tracker => source)
741 issue = Issue.new(:tracker => source)
742 issue.safe_attributes = {'tracker_id' => 2, 'due_date' => '2012-07-14'}
742 issue.safe_attributes = {'tracker_id' => 2, 'due_date' => '2012-07-14'}
743 assert_equal target, issue.tracker
743 assert_equal target, issue.tracker
744 assert_equal Date.parse('2012-07-14'), issue.due_date
744 assert_equal Date.parse('2012-07-14'), issue.due_date
745 end
745 end
746
746
747 def test_safe_attributes_should_not_include_readonly_fields
747 def test_safe_attributes_should_not_include_readonly_fields
748 WorkflowPermission.delete_all
748 WorkflowPermission.delete_all
749 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
749 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
750 :role_id => 1, :field_name => 'due_date',
750 :role_id => 1, :field_name => 'due_date',
751 :rule => 'readonly')
751 :rule => 'readonly')
752 user = User.find(2)
752 user = User.find(2)
753
753
754 issue = Issue.new(:project_id => 1, :tracker_id => 1)
754 issue = Issue.new(:project_id => 1, :tracker_id => 1)
755 assert_equal %w(due_date), issue.read_only_attribute_names(user)
755 assert_equal %w(due_date), issue.read_only_attribute_names(user)
756 assert_not_include 'due_date', issue.safe_attribute_names(user)
756 assert_not_include 'due_date', issue.safe_attribute_names(user)
757
757
758 issue.send :safe_attributes=, {'start_date' => '2012-07-14', 'due_date' => '2012-07-14'}, user
758 issue.send :safe_attributes=, {'start_date' => '2012-07-14', 'due_date' => '2012-07-14'}, user
759 assert_equal Date.parse('2012-07-14'), issue.start_date
759 assert_equal Date.parse('2012-07-14'), issue.start_date
760 assert_nil issue.due_date
760 assert_nil issue.due_date
761 end
761 end
762
762
763 def test_safe_attributes_should_not_include_readonly_custom_fields
763 def test_safe_attributes_should_not_include_readonly_custom_fields
764 cf1 = IssueCustomField.create!(:name => 'Writable field',
764 cf1 = IssueCustomField.create!(:name => 'Writable field',
765 :field_format => 'string',
765 :field_format => 'string',
766 :is_for_all => true, :tracker_ids => [1])
766 :is_for_all => true, :tracker_ids => [1])
767 cf2 = IssueCustomField.create!(:name => 'Readonly field',
767 cf2 = IssueCustomField.create!(:name => 'Readonly field',
768 :field_format => 'string',
768 :field_format => 'string',
769 :is_for_all => true, :tracker_ids => [1])
769 :is_for_all => true, :tracker_ids => [1])
770 WorkflowPermission.delete_all
770 WorkflowPermission.delete_all
771 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
771 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
772 :role_id => 1, :field_name => cf2.id.to_s,
772 :role_id => 1, :field_name => cf2.id.to_s,
773 :rule => 'readonly')
773 :rule => 'readonly')
774 user = User.find(2)
774 user = User.find(2)
775 issue = Issue.new(:project_id => 1, :tracker_id => 1)
775 issue = Issue.new(:project_id => 1, :tracker_id => 1)
776 assert_equal [cf2.id.to_s], issue.read_only_attribute_names(user)
776 assert_equal [cf2.id.to_s], issue.read_only_attribute_names(user)
777 assert_not_include cf2.id.to_s, issue.safe_attribute_names(user)
777 assert_not_include cf2.id.to_s, issue.safe_attribute_names(user)
778
778
779 issue.send :safe_attributes=, {'custom_field_values' => {
779 issue.send :safe_attributes=, {'custom_field_values' => {
780 cf1.id.to_s => 'value1', cf2.id.to_s => 'value2'
780 cf1.id.to_s => 'value1', cf2.id.to_s => 'value2'
781 }}, user
781 }}, user
782 assert_equal 'value1', issue.custom_field_value(cf1)
782 assert_equal 'value1', issue.custom_field_value(cf1)
783 assert_nil issue.custom_field_value(cf2)
783 assert_nil issue.custom_field_value(cf2)
784
784
785 issue.send :safe_attributes=, {'custom_fields' => [
785 issue.send :safe_attributes=, {'custom_fields' => [
786 {'id' => cf1.id.to_s, 'value' => 'valuea'},
786 {'id' => cf1.id.to_s, 'value' => 'valuea'},
787 {'id' => cf2.id.to_s, 'value' => 'valueb'}
787 {'id' => cf2.id.to_s, 'value' => 'valueb'}
788 ]}, user
788 ]}, user
789 assert_equal 'valuea', issue.custom_field_value(cf1)
789 assert_equal 'valuea', issue.custom_field_value(cf1)
790 assert_nil issue.custom_field_value(cf2)
790 assert_nil issue.custom_field_value(cf2)
791 end
791 end
792
792
793 def test_editable_custom_field_values_should_return_non_readonly_custom_values
793 def test_editable_custom_field_values_should_return_non_readonly_custom_values
794 cf1 = IssueCustomField.create!(:name => 'Writable field', :field_format => 'string',
794 cf1 = IssueCustomField.create!(:name => 'Writable field', :field_format => 'string',
795 :is_for_all => true, :tracker_ids => [1, 2])
795 :is_for_all => true, :tracker_ids => [1, 2])
796 cf2 = IssueCustomField.create!(:name => 'Readonly field', :field_format => 'string',
796 cf2 = IssueCustomField.create!(:name => 'Readonly field', :field_format => 'string',
797 :is_for_all => true, :tracker_ids => [1, 2])
797 :is_for_all => true, :tracker_ids => [1, 2])
798 WorkflowPermission.delete_all
798 WorkflowPermission.delete_all
799 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, :role_id => 1,
799 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, :role_id => 1,
800 :field_name => cf2.id.to_s, :rule => 'readonly')
800 :field_name => cf2.id.to_s, :rule => 'readonly')
801 user = User.find(2)
801 user = User.find(2)
802
802
803 issue = Issue.new(:project_id => 1, :tracker_id => 1)
803 issue = Issue.new(:project_id => 1, :tracker_id => 1)
804 values = issue.editable_custom_field_values(user)
804 values = issue.editable_custom_field_values(user)
805 assert values.detect {|value| value.custom_field == cf1}
805 assert values.detect {|value| value.custom_field == cf1}
806 assert_nil values.detect {|value| value.custom_field == cf2}
806 assert_nil values.detect {|value| value.custom_field == cf2}
807
807
808 issue.tracker_id = 2
808 issue.tracker_id = 2
809 values = issue.editable_custom_field_values(user)
809 values = issue.editable_custom_field_values(user)
810 assert values.detect {|value| value.custom_field == cf1}
810 assert values.detect {|value| value.custom_field == cf1}
811 assert values.detect {|value| value.custom_field == cf2}
811 assert values.detect {|value| value.custom_field == cf2}
812 end
812 end
813
813
814 def test_editable_custom_fields_should_return_custom_field_that_is_enabled_for_the_role_only
814 def test_editable_custom_fields_should_return_custom_field_that_is_enabled_for_the_role_only
815 enabled_cf = IssueCustomField.generate!(:is_for_all => true, :tracker_ids => [1], :visible => false, :role_ids => [1,2])
815 enabled_cf = IssueCustomField.generate!(:is_for_all => true, :tracker_ids => [1], :visible => false, :role_ids => [1,2])
816 disabled_cf = IssueCustomField.generate!(:is_for_all => true, :tracker_ids => [1], :visible => false, :role_ids => [2])
816 disabled_cf = IssueCustomField.generate!(:is_for_all => true, :tracker_ids => [1], :visible => false, :role_ids => [2])
817 user = User.find(2)
817 user = User.find(2)
818 issue = Issue.new(:project_id => 1, :tracker_id => 1)
818 issue = Issue.new(:project_id => 1, :tracker_id => 1)
819
819
820 assert_include enabled_cf, issue.editable_custom_fields(user)
820 assert_include enabled_cf, issue.editable_custom_fields(user)
821 assert_not_include disabled_cf, issue.editable_custom_fields(user)
821 assert_not_include disabled_cf, issue.editable_custom_fields(user)
822 end
822 end
823
823
824 def test_safe_attributes_should_accept_target_tracker_writable_fields
824 def test_safe_attributes_should_accept_target_tracker_writable_fields
825 WorkflowPermission.delete_all
825 WorkflowPermission.delete_all
826 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
826 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
827 :role_id => 1, :field_name => 'due_date',
827 :role_id => 1, :field_name => 'due_date',
828 :rule => 'readonly')
828 :rule => 'readonly')
829 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2,
829 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2,
830 :role_id => 1, :field_name => 'start_date',
830 :role_id => 1, :field_name => 'start_date',
831 :rule => 'readonly')
831 :rule => 'readonly')
832 user = User.find(2)
832 user = User.find(2)
833
833
834 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1)
834 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1)
835
835
836 issue.send :safe_attributes=, {'start_date' => '2012-07-12',
836 issue.send :safe_attributes=, {'start_date' => '2012-07-12',
837 'due_date' => '2012-07-14'}, user
837 'due_date' => '2012-07-14'}, user
838 assert_equal Date.parse('2012-07-12'), issue.start_date
838 assert_equal Date.parse('2012-07-12'), issue.start_date
839 assert_nil issue.due_date
839 assert_nil issue.due_date
840
840
841 issue.send :safe_attributes=, {'start_date' => '2012-07-15',
841 issue.send :safe_attributes=, {'start_date' => '2012-07-15',
842 'due_date' => '2012-07-16',
842 'due_date' => '2012-07-16',
843 'tracker_id' => 2}, user
843 'tracker_id' => 2}, user
844 assert_equal Date.parse('2012-07-12'), issue.start_date
844 assert_equal Date.parse('2012-07-12'), issue.start_date
845 assert_equal Date.parse('2012-07-16'), issue.due_date
845 assert_equal Date.parse('2012-07-16'), issue.due_date
846 end
846 end
847
847
848 def test_safe_attributes_should_accept_target_status_writable_fields
848 def test_safe_attributes_should_accept_target_status_writable_fields
849 WorkflowPermission.delete_all
849 WorkflowPermission.delete_all
850 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
850 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
851 :role_id => 1, :field_name => 'due_date',
851 :role_id => 1, :field_name => 'due_date',
852 :rule => 'readonly')
852 :rule => 'readonly')
853 WorkflowPermission.create!(:old_status_id => 2, :tracker_id => 1,
853 WorkflowPermission.create!(:old_status_id => 2, :tracker_id => 1,
854 :role_id => 1, :field_name => 'start_date',
854 :role_id => 1, :field_name => 'start_date',
855 :rule => 'readonly')
855 :rule => 'readonly')
856 user = User.find(2)
856 user = User.find(2)
857
857
858 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1)
858 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1)
859
859
860 issue.send :safe_attributes=, {'start_date' => '2012-07-12',
860 issue.send :safe_attributes=, {'start_date' => '2012-07-12',
861 'due_date' => '2012-07-14'},
861 'due_date' => '2012-07-14'},
862 user
862 user
863 assert_equal Date.parse('2012-07-12'), issue.start_date
863 assert_equal Date.parse('2012-07-12'), issue.start_date
864 assert_nil issue.due_date
864 assert_nil issue.due_date
865
865
866 issue.send :safe_attributes=, {'start_date' => '2012-07-15',
866 issue.send :safe_attributes=, {'start_date' => '2012-07-15',
867 'due_date' => '2012-07-16',
867 'due_date' => '2012-07-16',
868 'status_id' => 2},
868 'status_id' => 2},
869 user
869 user
870 assert_equal Date.parse('2012-07-12'), issue.start_date
870 assert_equal Date.parse('2012-07-12'), issue.start_date
871 assert_equal Date.parse('2012-07-16'), issue.due_date
871 assert_equal Date.parse('2012-07-16'), issue.due_date
872 end
872 end
873
873
874 def test_required_attributes_should_be_validated
874 def test_required_attributes_should_be_validated
875 cf = IssueCustomField.create!(:name => 'Foo', :field_format => 'string',
875 cf = IssueCustomField.create!(:name => 'Foo', :field_format => 'string',
876 :is_for_all => true, :tracker_ids => [1, 2])
876 :is_for_all => true, :tracker_ids => [1, 2])
877
877
878 WorkflowPermission.delete_all
878 WorkflowPermission.delete_all
879 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
879 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
880 :role_id => 1, :field_name => 'due_date',
880 :role_id => 1, :field_name => 'due_date',
881 :rule => 'required')
881 :rule => 'required')
882 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
882 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
883 :role_id => 1, :field_name => 'category_id',
883 :role_id => 1, :field_name => 'category_id',
884 :rule => 'required')
884 :rule => 'required')
885 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
885 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
886 :role_id => 1, :field_name => cf.id.to_s,
886 :role_id => 1, :field_name => cf.id.to_s,
887 :rule => 'required')
887 :rule => 'required')
888
888
889 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2,
889 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2,
890 :role_id => 1, :field_name => 'start_date',
890 :role_id => 1, :field_name => 'start_date',
891 :rule => 'required')
891 :rule => 'required')
892 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2,
892 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2,
893 :role_id => 1, :field_name => cf.id.to_s,
893 :role_id => 1, :field_name => cf.id.to_s,
894 :rule => 'required')
894 :rule => 'required')
895 user = User.find(2)
895 user = User.find(2)
896
896
897 issue = Issue.new(:project_id => 1, :tracker_id => 1,
897 issue = Issue.new(:project_id => 1, :tracker_id => 1,
898 :status_id => 1, :subject => 'Required fields',
898 :status_id => 1, :subject => 'Required fields',
899 :author => user)
899 :author => user)
900 assert_equal [cf.id.to_s, "category_id", "due_date"],
900 assert_equal [cf.id.to_s, "category_id", "due_date"],
901 issue.required_attribute_names(user).sort
901 issue.required_attribute_names(user).sort
902 assert !issue.save, "Issue was saved"
902 assert !issue.save, "Issue was saved"
903 assert_equal ["Category cannot be blank", "Due date cannot be blank", "Foo cannot be blank"],
903 assert_equal ["Category cannot be blank", "Due date cannot be blank", "Foo cannot be blank"],
904 issue.errors.full_messages.sort
904 issue.errors.full_messages.sort
905
905
906 issue.tracker_id = 2
906 issue.tracker_id = 2
907 assert_equal [cf.id.to_s, "start_date"], issue.required_attribute_names(user).sort
907 assert_equal [cf.id.to_s, "start_date"], issue.required_attribute_names(user).sort
908 assert !issue.save, "Issue was saved"
908 assert !issue.save, "Issue was saved"
909 assert_equal ["Foo cannot be blank", "Start date cannot be blank"],
909 assert_equal ["Foo cannot be blank", "Start date cannot be blank"],
910 issue.errors.full_messages.sort
910 issue.errors.full_messages.sort
911
911
912 issue.start_date = Date.today
912 issue.start_date = Date.today
913 issue.custom_field_values = {cf.id.to_s => 'bar'}
913 issue.custom_field_values = {cf.id.to_s => 'bar'}
914 assert issue.save
914 assert issue.save
915 end
915 end
916
916
917 def test_required_attribute_that_is_disabled_for_the_tracker_should_not_be_required
917 def test_required_attribute_that_is_disabled_for_the_tracker_should_not_be_required
918 WorkflowPermission.delete_all
918 WorkflowPermission.delete_all
919 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
919 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
920 :role_id => 1, :field_name => 'start_date',
920 :role_id => 1, :field_name => 'start_date',
921 :rule => 'required')
921 :rule => 'required')
922 user = User.find(2)
922 user = User.find(2)
923
923
924 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1,
924 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1,
925 :subject => 'Required fields', :author => user)
925 :subject => 'Required fields', :author => user)
926 assert !issue.save
926 assert !issue.save
927 assert_include "Start date cannot be blank", issue.errors.full_messages
927 assert_include "Start date cannot be blank", issue.errors.full_messages
928
928
929 tracker = Tracker.find(1)
929 tracker = Tracker.find(1)
930 tracker.core_fields -= %w(start_date)
930 tracker.core_fields -= %w(start_date)
931 tracker.save!
931 tracker.save!
932 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1,
932 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1,
933 :subject => 'Required fields', :author => user)
933 :subject => 'Required fields', :author => user)
934 assert issue.save
934 assert issue.save
935 end
935 end
936
936
937 def test_category_should_not_be_required_if_project_has_no_categories
937 def test_category_should_not_be_required_if_project_has_no_categories
938 Project.find(1).issue_categories.delete_all
938 Project.find(1).issue_categories.delete_all
939 WorkflowPermission.delete_all
939 WorkflowPermission.delete_all
940 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
940 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
941 :role_id => 1, :field_name => 'category_id',:rule => 'required')
941 :role_id => 1, :field_name => 'category_id',:rule => 'required')
942 user = User.find(2)
942 user = User.find(2)
943
943
944 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1,
944 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1,
945 :subject => 'Required fields', :author => user)
945 :subject => 'Required fields', :author => user)
946 assert_save issue
946 assert_save issue
947 end
947 end
948
948
949 def test_fixed_version_should_not_be_required_no_assignable_versions
949 def test_fixed_version_should_not_be_required_no_assignable_versions
950 Version.delete_all
950 Version.delete_all
951 WorkflowPermission.delete_all
951 WorkflowPermission.delete_all
952 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
952 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
953 :role_id => 1, :field_name => 'fixed_version_id',:rule => 'required')
953 :role_id => 1, :field_name => 'fixed_version_id',:rule => 'required')
954 user = User.find(2)
954 user = User.find(2)
955
955
956 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1,
956 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1,
957 :subject => 'Required fields', :author => user)
957 :subject => 'Required fields', :author => user)
958 assert_save issue
958 assert_save issue
959 end
959 end
960
960
961 def test_required_custom_field_that_is_not_visible_for_the_user_should_not_be_required
961 def test_required_custom_field_that_is_not_visible_for_the_user_should_not_be_required
962 CustomField.delete_all
962 CustomField.delete_all
963 field = IssueCustomField.generate!(:is_required => true, :visible => false, :role_ids => [1], :trackers => Tracker.all, :is_for_all => true)
963 field = IssueCustomField.generate!(:is_required => true, :visible => false, :role_ids => [1], :trackers => Tracker.all, :is_for_all => true)
964 user = User.generate!
964 user = User.generate!
965 User.add_to_project(user, Project.find(1), Role.find(2))
965 User.add_to_project(user, Project.find(1), Role.find(2))
966
966
967 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1,
967 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1,
968 :subject => 'Required fields', :author => user)
968 :subject => 'Required fields', :author => user)
969 assert_save issue
969 assert_save issue
970 end
970 end
971
971
972 def test_required_custom_field_that_is_visible_for_the_user_should_be_required
972 def test_required_custom_field_that_is_visible_for_the_user_should_be_required
973 CustomField.delete_all
973 CustomField.delete_all
974 field = IssueCustomField.generate!(:is_required => true, :visible => false, :role_ids => [1], :trackers => Tracker.all, :is_for_all => true)
974 field = IssueCustomField.generate!(:is_required => true, :visible => false, :role_ids => [1], :trackers => Tracker.all, :is_for_all => true)
975 user = User.generate!
975 user = User.generate!
976 User.add_to_project(user, Project.find(1), Role.find(1))
976 User.add_to_project(user, Project.find(1), Role.find(1))
977
977
978 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1,
978 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1,
979 :subject => 'Required fields', :author => user)
979 :subject => 'Required fields', :author => user)
980 assert !issue.save
980 assert !issue.save
981 assert_include "#{field.name} cannot be blank", issue.errors.full_messages
981 assert_include "#{field.name} cannot be blank", issue.errors.full_messages
982 end
982 end
983
983
984 def test_required_attribute_names_for_multiple_roles_should_intersect_rules
984 def test_required_attribute_names_for_multiple_roles_should_intersect_rules
985 WorkflowPermission.delete_all
985 WorkflowPermission.delete_all
986 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
986 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
987 :role_id => 1, :field_name => 'due_date',
987 :role_id => 1, :field_name => 'due_date',
988 :rule => 'required')
988 :rule => 'required')
989 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
989 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
990 :role_id => 1, :field_name => 'start_date',
990 :role_id => 1, :field_name => 'start_date',
991 :rule => 'required')
991 :rule => 'required')
992 user = User.find(2)
992 user = User.find(2)
993 member = Member.find(1)
993 member = Member.find(1)
994 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1)
994 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1)
995
995
996 assert_equal %w(due_date start_date), issue.required_attribute_names(user).sort
996 assert_equal %w(due_date start_date), issue.required_attribute_names(user).sort
997
997
998 member.role_ids = [1, 2]
998 member.role_ids = [1, 2]
999 member.save!
999 member.save!
1000 assert_equal [], issue.required_attribute_names(user.reload)
1000 assert_equal [], issue.required_attribute_names(user.reload)
1001
1001
1002 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
1002 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
1003 :role_id => 2, :field_name => 'due_date',
1003 :role_id => 2, :field_name => 'due_date',
1004 :rule => 'required')
1004 :rule => 'required')
1005 assert_equal %w(due_date), issue.required_attribute_names(user)
1005 assert_equal %w(due_date), issue.required_attribute_names(user)
1006
1006
1007 member.role_ids = [1, 2, 3]
1007 member.role_ids = [1, 2, 3]
1008 member.save!
1008 member.save!
1009 assert_equal [], issue.required_attribute_names(user.reload)
1009 assert_equal [], issue.required_attribute_names(user.reload)
1010
1010
1011 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
1011 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
1012 :role_id => 3, :field_name => 'due_date',
1012 :role_id => 3, :field_name => 'due_date',
1013 :rule => 'readonly')
1013 :rule => 'readonly')
1014 # required + readonly => required
1014 # required + readonly => required
1015 assert_equal %w(due_date), issue.required_attribute_names(user)
1015 assert_equal %w(due_date), issue.required_attribute_names(user)
1016 end
1016 end
1017
1017
1018 def test_read_only_attribute_names_for_multiple_roles_should_intersect_rules
1018 def test_read_only_attribute_names_for_multiple_roles_should_intersect_rules
1019 WorkflowPermission.delete_all
1019 WorkflowPermission.delete_all
1020 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
1020 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
1021 :role_id => 1, :field_name => 'due_date',
1021 :role_id => 1, :field_name => 'due_date',
1022 :rule => 'readonly')
1022 :rule => 'readonly')
1023 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
1023 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
1024 :role_id => 1, :field_name => 'start_date',
1024 :role_id => 1, :field_name => 'start_date',
1025 :rule => 'readonly')
1025 :rule => 'readonly')
1026 user = User.find(2)
1026 user = User.find(2)
1027 member = Member.find(1)
1027 member = Member.find(1)
1028 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1)
1028 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1)
1029
1029
1030 assert_equal %w(due_date start_date), issue.read_only_attribute_names(user).sort
1030 assert_equal %w(due_date start_date), issue.read_only_attribute_names(user).sort
1031
1031
1032 member.role_ids = [1, 2]
1032 member.role_ids = [1, 2]
1033 member.save!
1033 member.save!
1034 assert_equal [], issue.read_only_attribute_names(user.reload)
1034 assert_equal [], issue.read_only_attribute_names(user.reload)
1035
1035
1036 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
1036 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
1037 :role_id => 2, :field_name => 'due_date',
1037 :role_id => 2, :field_name => 'due_date',
1038 :rule => 'readonly')
1038 :rule => 'readonly')
1039 assert_equal %w(due_date), issue.read_only_attribute_names(user)
1039 assert_equal %w(due_date), issue.read_only_attribute_names(user)
1040 end
1040 end
1041
1041
1042 # A field that is not visible by role 2 and readonly by role 1 should be readonly for user with role 1 and 2
1042 # A field that is not visible by role 2 and readonly by role 1 should be readonly for user with role 1 and 2
1043 def test_read_only_attribute_names_should_include_custom_fields_that_combine_readonly_and_not_visible_for_roles
1043 def test_read_only_attribute_names_should_include_custom_fields_that_combine_readonly_and_not_visible_for_roles
1044 field = IssueCustomField.generate!(
1044 field = IssueCustomField.generate!(
1045 :is_for_all => true, :trackers => Tracker.all, :visible => false, :role_ids => [1]
1045 :is_for_all => true, :trackers => Tracker.all, :visible => false, :role_ids => [1]
1046 )
1046 )
1047 WorkflowPermission.delete_all
1047 WorkflowPermission.delete_all
1048 WorkflowPermission.create!(
1048 WorkflowPermission.create!(
1049 :old_status_id => 1, :tracker_id => 1, :role_id => 1, :field_name => field.id, :rule => 'readonly'
1049 :old_status_id => 1, :tracker_id => 1, :role_id => 1, :field_name => field.id, :rule => 'readonly'
1050 )
1050 )
1051 user = User.generate!
1051 user = User.generate!
1052 project = Project.find(1)
1052 project = Project.find(1)
1053 User.add_to_project(user, project, Role.where(:id => [1, 2]))
1053 User.add_to_project(user, project, Role.where(:id => [1, 2]))
1054
1054
1055 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1)
1055 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1)
1056 assert_equal [field.id.to_s], issue.read_only_attribute_names(user)
1056 assert_equal [field.id.to_s], issue.read_only_attribute_names(user)
1057 end
1057 end
1058
1058
1059 def test_workflow_rules_should_ignore_roles_without_issue_permissions
1059 def test_workflow_rules_should_ignore_roles_without_issue_permissions
1060 role = Role.generate! :permissions => [:view_issues, :edit_issues]
1060 role = Role.generate! :permissions => [:view_issues, :edit_issues]
1061 ignored_role = Role.generate! :permissions => [:view_issues]
1061 ignored_role = Role.generate! :permissions => [:view_issues]
1062
1062
1063 WorkflowPermission.delete_all
1063 WorkflowPermission.delete_all
1064 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
1064 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
1065 :role => role, :field_name => 'due_date',
1065 :role => role, :field_name => 'due_date',
1066 :rule => 'required')
1066 :rule => 'required')
1067 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
1067 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
1068 :role => role, :field_name => 'start_date',
1068 :role => role, :field_name => 'start_date',
1069 :rule => 'readonly')
1069 :rule => 'readonly')
1070 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
1070 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
1071 :role => role, :field_name => 'done_ratio',
1071 :role => role, :field_name => 'done_ratio',
1072 :rule => 'readonly')
1072 :rule => 'readonly')
1073 user = User.generate!
1073 user = User.generate!
1074 User.add_to_project user, Project.find(1), [role, ignored_role]
1074 User.add_to_project user, Project.find(1), [role, ignored_role]
1075
1075
1076 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1)
1076 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1)
1077
1077
1078 assert_equal %w(due_date), issue.required_attribute_names(user)
1078 assert_equal %w(due_date), issue.required_attribute_names(user)
1079 assert_equal %w(done_ratio start_date), issue.read_only_attribute_names(user).sort
1079 assert_equal %w(done_ratio start_date), issue.read_only_attribute_names(user).sort
1080 end
1080 end
1081
1081
1082 def test_workflow_rules_should_work_for_member_with_duplicate_role
1082 def test_workflow_rules_should_work_for_member_with_duplicate_role
1083 WorkflowPermission.delete_all
1083 WorkflowPermission.delete_all
1084 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
1084 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
1085 :role_id => 1, :field_name => 'due_date',
1085 :role_id => 1, :field_name => 'due_date',
1086 :rule => 'required')
1086 :rule => 'required')
1087 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
1087 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
1088 :role_id => 1, :field_name => 'start_date',
1088 :role_id => 1, :field_name => 'start_date',
1089 :rule => 'readonly')
1089 :rule => 'readonly')
1090
1090
1091 user = User.generate!
1091 user = User.generate!
1092 m = Member.new(:user_id => user.id, :project_id => 1)
1092 m = Member.new(:user_id => user.id, :project_id => 1)
1093 m.member_roles.build(:role_id => 1)
1093 m.member_roles.build(:role_id => 1)
1094 m.member_roles.build(:role_id => 1)
1094 m.member_roles.build(:role_id => 1)
1095 m.save!
1095 m.save!
1096
1096
1097 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1)
1097 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1)
1098
1098
1099 assert_equal %w(due_date), issue.required_attribute_names(user)
1099 assert_equal %w(due_date), issue.required_attribute_names(user)
1100 assert_equal %w(start_date), issue.read_only_attribute_names(user)
1100 assert_equal %w(start_date), issue.read_only_attribute_names(user)
1101 end
1101 end
1102
1102
1103 def test_copy
1103 def test_copy
1104 issue = Issue.new.copy_from(1)
1104 issue = Issue.new.copy_from(1)
1105 assert issue.copy?
1105 assert issue.copy?
1106 assert issue.save
1106 assert issue.save
1107 issue.reload
1107 issue.reload
1108 orig = Issue.find(1)
1108 orig = Issue.find(1)
1109 assert_equal orig.subject, issue.subject
1109 assert_equal orig.subject, issue.subject
1110 assert_equal orig.tracker, issue.tracker
1110 assert_equal orig.tracker, issue.tracker
1111 assert_equal "125", issue.custom_value_for(2).value
1111 assert_equal "125", issue.custom_value_for(2).value
1112 end
1112 end
1113
1113
1114 def test_copy_should_copy_status
1114 def test_copy_should_copy_status
1115 orig = Issue.find(8)
1115 orig = Issue.find(8)
1116 assert orig.status != orig.default_status
1116 assert orig.status != orig.default_status
1117
1117
1118 issue = Issue.new.copy_from(orig)
1118 issue = Issue.new.copy_from(orig)
1119 assert issue.save
1119 assert issue.save
1120 issue.reload
1120 issue.reload
1121 assert_equal orig.status, issue.status
1121 assert_equal orig.status, issue.status
1122 end
1122 end
1123
1123
1124 def test_copy_should_add_relation_with_copied_issue
1124 def test_copy_should_add_relation_with_copied_issue
1125 copied = Issue.find(1)
1125 copied = Issue.find(1)
1126 issue = Issue.new.copy_from(copied)
1126 issue = Issue.new.copy_from(copied)
1127 assert issue.save
1127 assert issue.save
1128 issue.reload
1128 issue.reload
1129
1129
1130 assert_equal 1, issue.relations.size
1130 assert_equal 1, issue.relations.size
1131 relation = issue.relations.first
1131 relation = issue.relations.first
1132 assert_equal 'copied_to', relation.relation_type
1132 assert_equal 'copied_to', relation.relation_type
1133 assert_equal copied, relation.issue_from
1133 assert_equal copied, relation.issue_from
1134 assert_equal issue, relation.issue_to
1134 assert_equal issue, relation.issue_to
1135 end
1135 end
1136
1136
1137 def test_copy_should_copy_subtasks
1137 def test_copy_should_copy_subtasks
1138 issue = Issue.generate_with_descendants!
1138 issue = Issue.generate_with_descendants!
1139
1139
1140 copy = issue.reload.copy
1140 copy = issue.reload.copy
1141 copy.author = User.find(7)
1141 copy.author = User.find(7)
1142 assert_difference 'Issue.count', 1+issue.descendants.count do
1142 assert_difference 'Issue.count', 1+issue.descendants.count do
1143 assert copy.save
1143 assert copy.save
1144 end
1144 end
1145 copy.reload
1145 copy.reload
1146 assert_equal %w(Child1 Child2), copy.children.map(&:subject).sort
1146 assert_equal %w(Child1 Child2), copy.children.map(&:subject).sort
1147 child_copy = copy.children.detect {|c| c.subject == 'Child1'}
1147 child_copy = copy.children.detect {|c| c.subject == 'Child1'}
1148 assert_equal %w(Child11), child_copy.children.map(&:subject).sort
1148 assert_equal %w(Child11), child_copy.children.map(&:subject).sort
1149 assert_equal copy.author, child_copy.author
1149 assert_equal copy.author, child_copy.author
1150 end
1150 end
1151
1151
1152 def test_copy_as_a_child_of_copied_issue_should_not_copy_itself
1152 def test_copy_as_a_child_of_copied_issue_should_not_copy_itself
1153 parent = Issue.generate!
1153 parent = Issue.generate!
1154 child1 = Issue.generate!(:parent_issue_id => parent.id, :subject => 'Child 1')
1154 child1 = Issue.generate!(:parent_issue_id => parent.id, :subject => 'Child 1')
1155 child2 = Issue.generate!(:parent_issue_id => parent.id, :subject => 'Child 2')
1155 child2 = Issue.generate!(:parent_issue_id => parent.id, :subject => 'Child 2')
1156
1156
1157 copy = parent.reload.copy
1157 copy = parent.reload.copy
1158 copy.parent_issue_id = parent.id
1158 copy.parent_issue_id = parent.id
1159 copy.author = User.find(7)
1159 copy.author = User.find(7)
1160 assert_difference 'Issue.count', 3 do
1160 assert_difference 'Issue.count', 3 do
1161 assert copy.save
1161 assert copy.save
1162 end
1162 end
1163 parent.reload
1163 parent.reload
1164 copy.reload
1164 copy.reload
1165 assert_equal parent, copy.parent
1165 assert_equal parent, copy.parent
1166 assert_equal 3, parent.children.count
1166 assert_equal 3, parent.children.count
1167 assert_equal 5, parent.descendants.count
1167 assert_equal 5, parent.descendants.count
1168 assert_equal 2, copy.children.count
1168 assert_equal 2, copy.children.count
1169 assert_equal 2, copy.descendants.count
1169 assert_equal 2, copy.descendants.count
1170 end
1170 end
1171
1171
1172 def test_copy_as_a_descendant_of_copied_issue_should_not_copy_itself
1172 def test_copy_as_a_descendant_of_copied_issue_should_not_copy_itself
1173 parent = Issue.generate!
1173 parent = Issue.generate!
1174 child1 = Issue.generate!(:parent_issue_id => parent.id, :subject => 'Child 1')
1174 child1 = Issue.generate!(:parent_issue_id => parent.id, :subject => 'Child 1')
1175 child2 = Issue.generate!(:parent_issue_id => parent.id, :subject => 'Child 2')
1175 child2 = Issue.generate!(:parent_issue_id => parent.id, :subject => 'Child 2')
1176
1176
1177 copy = parent.reload.copy
1177 copy = parent.reload.copy
1178 copy.parent_issue_id = child1.id
1178 copy.parent_issue_id = child1.id
1179 copy.author = User.find(7)
1179 copy.author = User.find(7)
1180 assert_difference 'Issue.count', 3 do
1180 assert_difference 'Issue.count', 3 do
1181 assert copy.save
1181 assert copy.save
1182 end
1182 end
1183 parent.reload
1183 parent.reload
1184 child1.reload
1184 child1.reload
1185 copy.reload
1185 copy.reload
1186 assert_equal child1, copy.parent
1186 assert_equal child1, copy.parent
1187 assert_equal 2, parent.children.count
1187 assert_equal 2, parent.children.count
1188 assert_equal 5, parent.descendants.count
1188 assert_equal 5, parent.descendants.count
1189 assert_equal 1, child1.children.count
1189 assert_equal 1, child1.children.count
1190 assert_equal 3, child1.descendants.count
1190 assert_equal 3, child1.descendants.count
1191 assert_equal 2, copy.children.count
1191 assert_equal 2, copy.children.count
1192 assert_equal 2, copy.descendants.count
1192 assert_equal 2, copy.descendants.count
1193 end
1193 end
1194
1194
1195 def test_copy_should_copy_subtasks_to_target_project
1195 def test_copy_should_copy_subtasks_to_target_project
1196 issue = Issue.generate_with_descendants!
1196 issue = Issue.generate_with_descendants!
1197
1197
1198 copy = issue.copy(:project_id => 3)
1198 copy = issue.copy(:project_id => 3)
1199 assert_difference 'Issue.count', 1+issue.descendants.count do
1199 assert_difference 'Issue.count', 1+issue.descendants.count do
1200 assert copy.save
1200 assert copy.save
1201 end
1201 end
1202 assert_equal [3], copy.reload.descendants.map(&:project_id).uniq
1202 assert_equal [3], copy.reload.descendants.map(&:project_id).uniq
1203 end
1203 end
1204
1204
1205 def test_copy_should_not_copy_subtasks_twice_when_saving_twice
1205 def test_copy_should_not_copy_subtasks_twice_when_saving_twice
1206 issue = Issue.generate_with_descendants!
1206 issue = Issue.generate_with_descendants!
1207
1207
1208 copy = issue.reload.copy
1208 copy = issue.reload.copy
1209 assert_difference 'Issue.count', 1+issue.descendants.count do
1209 assert_difference 'Issue.count', 1+issue.descendants.count do
1210 assert copy.save
1210 assert copy.save
1211 assert copy.save
1211 assert copy.save
1212 end
1212 end
1213 end
1213 end
1214
1214
1215 def test_should_not_call_after_project_change_on_creation
1215 def test_should_not_call_after_project_change_on_creation
1216 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1,
1216 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1,
1217 :subject => 'Test', :author_id => 1)
1217 :subject => 'Test', :author_id => 1)
1218 issue.expects(:after_project_change).never
1218 issue.expects(:after_project_change).never
1219 issue.save!
1219 issue.save!
1220 end
1220 end
1221
1221
1222 def test_should_not_call_after_project_change_on_update
1222 def test_should_not_call_after_project_change_on_update
1223 issue = Issue.find(1)
1223 issue = Issue.find(1)
1224 issue.project = Project.find(1)
1224 issue.project = Project.find(1)
1225 issue.subject = 'No project change'
1225 issue.subject = 'No project change'
1226 issue.expects(:after_project_change).never
1226 issue.expects(:after_project_change).never
1227 issue.save!
1227 issue.save!
1228 end
1228 end
1229
1229
1230 def test_should_call_after_project_change_on_project_change
1230 def test_should_call_after_project_change_on_project_change
1231 issue = Issue.find(1)
1231 issue = Issue.find(1)
1232 issue.project = Project.find(2)
1232 issue.project = Project.find(2)
1233 issue.expects(:after_project_change).once
1233 issue.expects(:after_project_change).once
1234 issue.save!
1234 issue.save!
1235 end
1235 end
1236
1236
1237 def test_adding_journal_should_update_timestamp
1237 def test_adding_journal_should_update_timestamp
1238 issue = Issue.find(1)
1238 issue = Issue.find(1)
1239 updated_on_was = issue.updated_on
1239 updated_on_was = issue.updated_on
1240
1240
1241 issue.init_journal(User.first, "Adding notes")
1241 issue.init_journal(User.first, "Adding notes")
1242 assert_difference 'Journal.count' do
1242 assert_difference 'Journal.count' do
1243 assert issue.save
1243 assert issue.save
1244 end
1244 end
1245 issue.reload
1245 issue.reload
1246
1246
1247 assert_not_equal updated_on_was, issue.updated_on
1247 assert_not_equal updated_on_was, issue.updated_on
1248 end
1248 end
1249
1249
1250 def test_should_close_duplicates
1250 def test_should_close_duplicates
1251 # Create 3 issues
1251 # Create 3 issues
1252 issue1 = Issue.generate!
1252 issue1 = Issue.generate!
1253 issue2 = Issue.generate!
1253 issue2 = Issue.generate!
1254 issue3 = Issue.generate!
1254 issue3 = Issue.generate!
1255
1255
1256 # 2 is a dupe of 1
1256 # 2 is a dupe of 1
1257 IssueRelation.create!(:issue_from => issue2, :issue_to => issue1,
1257 IssueRelation.create!(:issue_from => issue2, :issue_to => issue1,
1258 :relation_type => IssueRelation::TYPE_DUPLICATES)
1258 :relation_type => IssueRelation::TYPE_DUPLICATES)
1259 # And 3 is a dupe of 2
1259 # And 3 is a dupe of 2
1260 # IssueRelation.create!(:issue_from => issue3, :issue_to => issue2,
1260 # IssueRelation.create!(:issue_from => issue3, :issue_to => issue2,
1261 # :relation_type => IssueRelation::TYPE_DUPLICATES)
1261 # :relation_type => IssueRelation::TYPE_DUPLICATES)
1262 # And 3 is a dupe of 1 (circular duplicates)
1262 # And 3 is a dupe of 1 (circular duplicates)
1263 IssueRelation.create!(:issue_from => issue3, :issue_to => issue1,
1263 IssueRelation.create!(:issue_from => issue3, :issue_to => issue1,
1264 :relation_type => IssueRelation::TYPE_DUPLICATES)
1264 :relation_type => IssueRelation::TYPE_DUPLICATES)
1265
1265
1266 assert issue1.reload.duplicates.include?(issue2)
1266 assert issue1.reload.duplicates.include?(issue2)
1267
1267
1268 # Closing issue 1
1268 # Closing issue 1
1269 issue1.init_journal(User.first, "Closing issue1")
1269 issue1.init_journal(User.first, "Closing issue1")
1270 issue1.status = IssueStatus.where(:is_closed => true).first
1270 issue1.status = IssueStatus.where(:is_closed => true).first
1271 assert issue1.save
1271 assert issue1.save
1272 # 2 and 3 should be also closed
1272 # 2 and 3 should be also closed
1273 assert issue2.reload.closed?
1273 assert issue2.reload.closed?
1274 assert issue3.reload.closed?
1274 assert issue3.reload.closed?
1275 end
1275 end
1276
1276
1277 def test_should_not_close_duplicated_issue
1277 def test_should_not_close_duplicated_issue
1278 issue1 = Issue.generate!
1278 issue1 = Issue.generate!
1279 issue2 = Issue.generate!
1279 issue2 = Issue.generate!
1280
1280
1281 # 2 is a dupe of 1
1281 # 2 is a dupe of 1
1282 IssueRelation.create(:issue_from => issue2, :issue_to => issue1,
1282 IssueRelation.create(:issue_from => issue2, :issue_to => issue1,
1283 :relation_type => IssueRelation::TYPE_DUPLICATES)
1283 :relation_type => IssueRelation::TYPE_DUPLICATES)
1284 # 2 is a dup of 1 but 1 is not a duplicate of 2
1284 # 2 is a dup of 1 but 1 is not a duplicate of 2
1285 assert !issue2.reload.duplicates.include?(issue1)
1285 assert !issue2.reload.duplicates.include?(issue1)
1286
1286
1287 # Closing issue 2
1287 # Closing issue 2
1288 issue2.init_journal(User.first, "Closing issue2")
1288 issue2.init_journal(User.first, "Closing issue2")
1289 issue2.status = IssueStatus.where(:is_closed => true).first
1289 issue2.status = IssueStatus.where(:is_closed => true).first
1290 assert issue2.save
1290 assert issue2.save
1291 # 1 should not be also closed
1291 # 1 should not be also closed
1292 assert !issue1.reload.closed?
1292 assert !issue1.reload.closed?
1293 end
1293 end
1294
1294
1295 def test_assignable_versions
1295 def test_assignable_versions
1296 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
1296 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
1297 :status_id => 1, :fixed_version_id => 1,
1297 :status_id => 1, :fixed_version_id => 1,
1298 :subject => 'New issue')
1298 :subject => 'New issue')
1299 assert_equal ['open'], issue.assignable_versions.collect(&:status).uniq
1299 assert_equal ['open'], issue.assignable_versions.collect(&:status).uniq
1300 end
1300 end
1301
1301
1302 def test_should_not_be_able_to_assign_a_new_issue_to_a_closed_version
1302 def test_should_not_be_able_to_assign_a_new_issue_to_a_closed_version
1303 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
1303 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
1304 :status_id => 1, :fixed_version_id => 1,
1304 :status_id => 1, :fixed_version_id => 1,
1305 :subject => 'New issue')
1305 :subject => 'New issue')
1306 assert !issue.save
1306 assert !issue.save
1307 assert_not_equal [], issue.errors[:fixed_version_id]
1307 assert_not_equal [], issue.errors[:fixed_version_id]
1308 end
1308 end
1309
1309
1310 def test_should_not_be_able_to_assign_a_new_issue_to_a_locked_version
1310 def test_should_not_be_able_to_assign_a_new_issue_to_a_locked_version
1311 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
1311 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
1312 :status_id => 1, :fixed_version_id => 2,
1312 :status_id => 1, :fixed_version_id => 2,
1313 :subject => 'New issue')
1313 :subject => 'New issue')
1314 assert !issue.save
1314 assert !issue.save
1315 assert_not_equal [], issue.errors[:fixed_version_id]
1315 assert_not_equal [], issue.errors[:fixed_version_id]
1316 end
1316 end
1317
1317
1318 def test_should_be_able_to_assign_a_new_issue_to_an_open_version
1318 def test_should_be_able_to_assign_a_new_issue_to_an_open_version
1319 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
1319 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
1320 :status_id => 1, :fixed_version_id => 3,
1320 :status_id => 1, :fixed_version_id => 3,
1321 :subject => 'New issue')
1321 :subject => 'New issue')
1322 assert issue.save
1322 assert issue.save
1323 end
1323 end
1324
1324
1325 def test_should_be_able_to_update_an_issue_assigned_to_a_closed_version
1325 def test_should_be_able_to_update_an_issue_assigned_to_a_closed_version
1326 issue = Issue.find(11)
1326 issue = Issue.find(11)
1327 assert_equal 'closed', issue.fixed_version.status
1327 assert_equal 'closed', issue.fixed_version.status
1328 issue.subject = 'Subject changed'
1328 issue.subject = 'Subject changed'
1329 assert issue.save
1329 assert issue.save
1330 end
1330 end
1331
1331
1332 def test_should_not_be_able_to_reopen_an_issue_assigned_to_a_closed_version
1332 def test_should_not_be_able_to_reopen_an_issue_assigned_to_a_closed_version
1333 issue = Issue.find(11)
1333 issue = Issue.find(11)
1334 issue.status_id = 1
1334 issue.status_id = 1
1335 assert !issue.save
1335 assert !issue.save
1336 assert_not_equal [], issue.errors[:base]
1336 assert_not_equal [], issue.errors[:base]
1337 end
1337 end
1338
1338
1339 def test_should_be_able_to_reopen_and_reassign_an_issue_assigned_to_a_closed_version
1339 def test_should_be_able_to_reopen_and_reassign_an_issue_assigned_to_a_closed_version
1340 issue = Issue.find(11)
1340 issue = Issue.find(11)
1341 issue.status_id = 1
1341 issue.status_id = 1
1342 issue.fixed_version_id = 3
1342 issue.fixed_version_id = 3
1343 assert issue.save
1343 assert issue.save
1344 end
1344 end
1345
1345
1346 def test_should_be_able_to_reopen_an_issue_assigned_to_a_locked_version
1346 def test_should_be_able_to_reopen_an_issue_assigned_to_a_locked_version
1347 issue = Issue.find(12)
1347 issue = Issue.find(12)
1348 assert_equal 'locked', issue.fixed_version.status
1348 assert_equal 'locked', issue.fixed_version.status
1349 issue.status_id = 1
1349 issue.status_id = 1
1350 assert issue.save
1350 assert issue.save
1351 end
1351 end
1352
1352
1353 def test_should_not_be_able_to_keep_unshared_version_when_changing_project
1353 def test_should_not_be_able_to_keep_unshared_version_when_changing_project
1354 issue = Issue.find(2)
1354 issue = Issue.find(2)
1355 assert_equal 2, issue.fixed_version_id
1355 assert_equal 2, issue.fixed_version_id
1356 issue.project_id = 3
1356 issue.project_id = 3
1357 assert_nil issue.fixed_version_id
1357 assert_nil issue.fixed_version_id
1358 issue.fixed_version_id = 2
1358 issue.fixed_version_id = 2
1359 assert !issue.save
1359 assert !issue.save
1360 assert_include 'Target version is not included in the list', issue.errors.full_messages
1360 assert_include 'Target version is not included in the list', issue.errors.full_messages
1361 end
1361 end
1362
1362
1363 def test_should_keep_shared_version_when_changing_project
1363 def test_should_keep_shared_version_when_changing_project
1364 Version.find(2).update_attribute :sharing, 'tree'
1364 Version.find(2).update_attribute :sharing, 'tree'
1365
1365
1366 issue = Issue.find(2)
1366 issue = Issue.find(2)
1367 assert_equal 2, issue.fixed_version_id
1367 assert_equal 2, issue.fixed_version_id
1368 issue.project_id = 3
1368 issue.project_id = 3
1369 assert_equal 2, issue.fixed_version_id
1369 assert_equal 2, issue.fixed_version_id
1370 assert issue.save
1370 assert issue.save
1371 end
1371 end
1372
1372
1373 def test_allowed_target_projects_should_include_projects_with_issue_tracking_enabled
1373 def test_allowed_target_projects_should_include_projects_with_issue_tracking_enabled
1374 assert_include Project.find(2), Issue.allowed_target_projects(User.find(2))
1374 assert_include Project.find(2), Issue.allowed_target_projects(User.find(2))
1375 end
1375 end
1376
1376
1377 def test_allowed_target_projects_should_not_include_projects_with_issue_tracking_disabled
1377 def test_allowed_target_projects_should_not_include_projects_with_issue_tracking_disabled
1378 Project.find(2).disable_module! :issue_tracking
1378 Project.find(2).disable_module! :issue_tracking
1379 assert_not_include Project.find(2), Issue.allowed_target_projects(User.find(2))
1379 assert_not_include Project.find(2), Issue.allowed_target_projects(User.find(2))
1380 end
1380 end
1381
1381
1382 def test_allowed_target_projects_should_not_include_projects_without_trackers
1382 def test_allowed_target_projects_should_not_include_projects_without_trackers
1383 project = Project.generate!(:tracker_ids => [])
1383 project = Project.generate!(:tracker_ids => [])
1384 assert project.trackers.empty?
1384 assert project.trackers.empty?
1385 assert_not_include project, Issue.allowed_target_projects(User.find(1))
1385 assert_not_include project, Issue.allowed_target_projects(User.find(1))
1386 end
1386 end
1387
1387
1388 def test_move_to_another_project_with_same_category
1388 def test_move_to_another_project_with_same_category
1389 issue = Issue.find(1)
1389 issue = Issue.find(1)
1390 issue.project = Project.find(2)
1390 issue.project = Project.find(2)
1391 assert issue.save
1391 assert issue.save
1392 issue.reload
1392 issue.reload
1393 assert_equal 2, issue.project_id
1393 assert_equal 2, issue.project_id
1394 # Category changes
1394 # Category changes
1395 assert_equal 4, issue.category_id
1395 assert_equal 4, issue.category_id
1396 # Make sure time entries were move to the target project
1396 # Make sure time entries were move to the target project
1397 assert_equal 2, issue.time_entries.first.project_id
1397 assert_equal 2, issue.time_entries.first.project_id
1398 end
1398 end
1399
1399
1400 def test_move_to_another_project_without_same_category
1400 def test_move_to_another_project_without_same_category
1401 issue = Issue.find(2)
1401 issue = Issue.find(2)
1402 issue.project = Project.find(2)
1402 issue.project = Project.find(2)
1403 assert issue.save
1403 assert issue.save
1404 issue.reload
1404 issue.reload
1405 assert_equal 2, issue.project_id
1405 assert_equal 2, issue.project_id
1406 # Category cleared
1406 # Category cleared
1407 assert_nil issue.category_id
1407 assert_nil issue.category_id
1408 end
1408 end
1409
1409
1410 def test_move_to_another_project_should_clear_fixed_version_when_not_shared
1410 def test_move_to_another_project_should_clear_fixed_version_when_not_shared
1411 issue = Issue.find(1)
1411 issue = Issue.find(1)
1412 issue.update_attribute(:fixed_version_id, 1)
1412 issue.update_attribute(:fixed_version_id, 1)
1413 issue.project = Project.find(2)
1413 issue.project = Project.find(2)
1414 assert issue.save
1414 assert issue.save
1415 issue.reload
1415 issue.reload
1416 assert_equal 2, issue.project_id
1416 assert_equal 2, issue.project_id
1417 # Cleared fixed_version
1417 # Cleared fixed_version
1418 assert_equal nil, issue.fixed_version
1418 assert_equal nil, issue.fixed_version
1419 end
1419 end
1420
1420
1421 def test_move_to_another_project_should_keep_fixed_version_when_shared_with_the_target_project
1421 def test_move_to_another_project_should_keep_fixed_version_when_shared_with_the_target_project
1422 issue = Issue.find(1)
1422 issue = Issue.find(1)
1423 issue.update_attribute(:fixed_version_id, 4)
1423 issue.update_attribute(:fixed_version_id, 4)
1424 issue.project = Project.find(5)
1424 issue.project = Project.find(5)
1425 assert issue.save
1425 assert issue.save
1426 issue.reload
1426 issue.reload
1427 assert_equal 5, issue.project_id
1427 assert_equal 5, issue.project_id
1428 # Keep fixed_version
1428 # Keep fixed_version
1429 assert_equal 4, issue.fixed_version_id
1429 assert_equal 4, issue.fixed_version_id
1430 end
1430 end
1431
1431
1432 def test_move_to_another_project_should_clear_fixed_version_when_not_shared_with_the_target_project
1432 def test_move_to_another_project_should_clear_fixed_version_when_not_shared_with_the_target_project
1433 issue = Issue.find(1)
1433 issue = Issue.find(1)
1434 issue.update_attribute(:fixed_version_id, 1)
1434 issue.update_attribute(:fixed_version_id, 1)
1435 issue.project = Project.find(5)
1435 issue.project = Project.find(5)
1436 assert issue.save
1436 assert issue.save
1437 issue.reload
1437 issue.reload
1438 assert_equal 5, issue.project_id
1438 assert_equal 5, issue.project_id
1439 # Cleared fixed_version
1439 # Cleared fixed_version
1440 assert_equal nil, issue.fixed_version
1440 assert_equal nil, issue.fixed_version
1441 end
1441 end
1442
1442
1443 def test_move_to_another_project_should_keep_fixed_version_when_shared_systemwide
1443 def test_move_to_another_project_should_keep_fixed_version_when_shared_systemwide
1444 issue = Issue.find(1)
1444 issue = Issue.find(1)
1445 issue.update_attribute(:fixed_version_id, 7)
1445 issue.update_attribute(:fixed_version_id, 7)
1446 issue.project = Project.find(2)
1446 issue.project = Project.find(2)
1447 assert issue.save
1447 assert issue.save
1448 issue.reload
1448 issue.reload
1449 assert_equal 2, issue.project_id
1449 assert_equal 2, issue.project_id
1450 # Keep fixed_version
1450 # Keep fixed_version
1451 assert_equal 7, issue.fixed_version_id
1451 assert_equal 7, issue.fixed_version_id
1452 end
1452 end
1453
1453
1454 def test_move_to_another_project_should_keep_parent_if_valid
1454 def test_move_to_another_project_should_keep_parent_if_valid
1455 issue = Issue.find(1)
1455 issue = Issue.find(1)
1456 issue.update_attribute(:parent_issue_id, 2)
1456 issue.update_attribute(:parent_issue_id, 2)
1457 issue.project = Project.find(3)
1457 issue.project = Project.find(3)
1458 assert issue.save
1458 assert issue.save
1459 issue.reload
1459 issue.reload
1460 assert_equal 2, issue.parent_id
1460 assert_equal 2, issue.parent_id
1461 end
1461 end
1462
1462
1463 def test_move_to_another_project_should_clear_parent_if_not_valid
1463 def test_move_to_another_project_should_clear_parent_if_not_valid
1464 issue = Issue.find(1)
1464 issue = Issue.find(1)
1465 issue.update_attribute(:parent_issue_id, 2)
1465 issue.update_attribute(:parent_issue_id, 2)
1466 issue.project = Project.find(2)
1466 issue.project = Project.find(2)
1467 assert issue.save
1467 assert issue.save
1468 issue.reload
1468 issue.reload
1469 assert_nil issue.parent_id
1469 assert_nil issue.parent_id
1470 end
1470 end
1471
1471
1472 def test_move_to_another_project_with_disabled_tracker
1472 def test_move_to_another_project_with_disabled_tracker
1473 issue = Issue.find(1)
1473 issue = Issue.find(1)
1474 target = Project.find(2)
1474 target = Project.find(2)
1475 target.tracker_ids = [3]
1475 target.tracker_ids = [3]
1476 target.save
1476 target.save
1477 issue.project = target
1477 issue.project = target
1478 assert issue.save
1478 assert issue.save
1479 issue.reload
1479 issue.reload
1480 assert_equal 2, issue.project_id
1480 assert_equal 2, issue.project_id
1481 assert_equal 3, issue.tracker_id
1481 assert_equal 3, issue.tracker_id
1482 end
1482 end
1483
1483
1484 def test_copy_to_the_same_project
1484 def test_copy_to_the_same_project
1485 issue = Issue.find(1)
1485 issue = Issue.find(1)
1486 copy = issue.copy
1486 copy = issue.copy
1487 assert_difference 'Issue.count' do
1487 assert_difference 'Issue.count' do
1488 copy.save!
1488 copy.save!
1489 end
1489 end
1490 assert_kind_of Issue, copy
1490 assert_kind_of Issue, copy
1491 assert_equal issue.project, copy.project
1491 assert_equal issue.project, copy.project
1492 assert_equal "125", copy.custom_value_for(2).value
1492 assert_equal "125", copy.custom_value_for(2).value
1493 end
1493 end
1494
1494
1495 def test_copy_to_another_project_and_tracker
1495 def test_copy_to_another_project_and_tracker
1496 issue = Issue.find(1)
1496 issue = Issue.find(1)
1497 copy = issue.copy(:project_id => 3, :tracker_id => 2)
1497 copy = issue.copy(:project_id => 3, :tracker_id => 2)
1498 assert_difference 'Issue.count' do
1498 assert_difference 'Issue.count' do
1499 copy.save!
1499 copy.save!
1500 end
1500 end
1501 copy.reload
1501 copy.reload
1502 assert_kind_of Issue, copy
1502 assert_kind_of Issue, copy
1503 assert_equal Project.find(3), copy.project
1503 assert_equal Project.find(3), copy.project
1504 assert_equal Tracker.find(2), copy.tracker
1504 assert_equal Tracker.find(2), copy.tracker
1505 # Custom field #2 is not associated with target tracker
1505 # Custom field #2 is not associated with target tracker
1506 assert_nil copy.custom_value_for(2)
1506 assert_nil copy.custom_value_for(2)
1507 end
1507 end
1508
1508
1509 test "#copy should not create a journal" do
1509 test "#copy should not create a journal" do
1510 copy = Issue.find(1).copy({:project_id => 3, :tracker_id => 2, :assigned_to_id => 3}, :link => false)
1510 copy = Issue.find(1).copy({:project_id => 3, :tracker_id => 2, :assigned_to_id => 3}, :link => false)
1511 copy.save!
1511 copy.save!
1512 assert_equal 0, copy.reload.journals.size
1512 assert_equal 0, copy.reload.journals.size
1513 end
1513 end
1514
1514
1515 test "#copy should allow assigned_to changes" do
1515 test "#copy should allow assigned_to changes" do
1516 copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2, :assigned_to_id => 3)
1516 copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2, :assigned_to_id => 3)
1517 assert_equal 3, copy.assigned_to_id
1517 assert_equal 3, copy.assigned_to_id
1518 end
1518 end
1519
1519
1520 test "#copy should allow status changes" do
1520 test "#copy should allow status changes" do
1521 copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2, :status_id => 2)
1521 copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2, :status_id => 2)
1522 assert_equal 2, copy.status_id
1522 assert_equal 2, copy.status_id
1523 end
1523 end
1524
1524
1525 test "#copy should allow start date changes" do
1525 test "#copy should allow start date changes" do
1526 date = Date.today
1526 date = Date.today
1527 copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2, :start_date => date)
1527 copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2, :start_date => date)
1528 assert_equal date, copy.start_date
1528 assert_equal date, copy.start_date
1529 end
1529 end
1530
1530
1531 test "#copy should allow due date changes" do
1531 test "#copy should allow due date changes" do
1532 date = Date.today
1532 date = Date.today
1533 copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2, :due_date => date)
1533 copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2, :due_date => date)
1534 assert_equal date, copy.due_date
1534 assert_equal date, copy.due_date
1535 end
1535 end
1536
1536
1537 test "#copy should set current user as author" do
1537 test "#copy should set current user as author" do
1538 User.current = User.find(9)
1538 User.current = User.find(9)
1539 copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2)
1539 copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2)
1540 assert_equal User.current, copy.author
1540 assert_equal User.current, copy.author
1541 end
1541 end
1542
1542
1543 test "#copy should create a journal with notes" do
1543 test "#copy should create a journal with notes" do
1544 date = Date.today
1544 date = Date.today
1545 notes = "Notes added when copying"
1545 notes = "Notes added when copying"
1546 copy = Issue.find(1).copy({:project_id => 3, :tracker_id => 2, :start_date => date}, :link => false)
1546 copy = Issue.find(1).copy({:project_id => 3, :tracker_id => 2, :start_date => date}, :link => false)
1547 copy.init_journal(User.current, notes)
1547 copy.init_journal(User.current, notes)
1548 copy.save!
1548 copy.save!
1549
1549
1550 assert_equal 1, copy.journals.size
1550 assert_equal 1, copy.journals.size
1551 journal = copy.journals.first
1551 journal = copy.journals.first
1552 assert_equal 0, journal.details.size
1552 assert_equal 0, journal.details.size
1553 assert_equal notes, journal.notes
1553 assert_equal notes, journal.notes
1554 end
1554 end
1555
1555
1556 def test_valid_parent_project
1556 def test_valid_parent_project
1557 issue = Issue.find(1)
1557 issue = Issue.find(1)
1558 issue_in_same_project = Issue.find(2)
1558 issue_in_same_project = Issue.find(2)
1559 issue_in_child_project = Issue.find(5)
1559 issue_in_child_project = Issue.find(5)
1560 issue_in_grandchild_project = Issue.generate!(:project_id => 6, :tracker_id => 1)
1560 issue_in_grandchild_project = Issue.generate!(:project_id => 6, :tracker_id => 1)
1561 issue_in_other_child_project = Issue.find(6)
1561 issue_in_other_child_project = Issue.find(6)
1562 issue_in_different_tree = Issue.find(4)
1562 issue_in_different_tree = Issue.find(4)
1563
1563
1564 with_settings :cross_project_subtasks => '' do
1564 with_settings :cross_project_subtasks => '' do
1565 assert_equal true, issue.valid_parent_project?(issue_in_same_project)
1565 assert_equal true, issue.valid_parent_project?(issue_in_same_project)
1566 assert_equal false, issue.valid_parent_project?(issue_in_child_project)
1566 assert_equal false, issue.valid_parent_project?(issue_in_child_project)
1567 assert_equal false, issue.valid_parent_project?(issue_in_grandchild_project)
1567 assert_equal false, issue.valid_parent_project?(issue_in_grandchild_project)
1568 assert_equal false, issue.valid_parent_project?(issue_in_different_tree)
1568 assert_equal false, issue.valid_parent_project?(issue_in_different_tree)
1569 end
1569 end
1570
1570
1571 with_settings :cross_project_subtasks => 'system' do
1571 with_settings :cross_project_subtasks => 'system' do
1572 assert_equal true, issue.valid_parent_project?(issue_in_same_project)
1572 assert_equal true, issue.valid_parent_project?(issue_in_same_project)
1573 assert_equal true, issue.valid_parent_project?(issue_in_child_project)
1573 assert_equal true, issue.valid_parent_project?(issue_in_child_project)
1574 assert_equal true, issue.valid_parent_project?(issue_in_different_tree)
1574 assert_equal true, issue.valid_parent_project?(issue_in_different_tree)
1575 end
1575 end
1576
1576
1577 with_settings :cross_project_subtasks => 'tree' do
1577 with_settings :cross_project_subtasks => 'tree' do
1578 assert_equal true, issue.valid_parent_project?(issue_in_same_project)
1578 assert_equal true, issue.valid_parent_project?(issue_in_same_project)
1579 assert_equal true, issue.valid_parent_project?(issue_in_child_project)
1579 assert_equal true, issue.valid_parent_project?(issue_in_child_project)
1580 assert_equal true, issue.valid_parent_project?(issue_in_grandchild_project)
1580 assert_equal true, issue.valid_parent_project?(issue_in_grandchild_project)
1581 assert_equal false, issue.valid_parent_project?(issue_in_different_tree)
1581 assert_equal false, issue.valid_parent_project?(issue_in_different_tree)
1582
1582
1583 assert_equal true, issue_in_child_project.valid_parent_project?(issue_in_same_project)
1583 assert_equal true, issue_in_child_project.valid_parent_project?(issue_in_same_project)
1584 assert_equal true, issue_in_child_project.valid_parent_project?(issue_in_other_child_project)
1584 assert_equal true, issue_in_child_project.valid_parent_project?(issue_in_other_child_project)
1585 end
1585 end
1586
1586
1587 with_settings :cross_project_subtasks => 'descendants' do
1587 with_settings :cross_project_subtasks => 'descendants' do
1588 assert_equal true, issue.valid_parent_project?(issue_in_same_project)
1588 assert_equal true, issue.valid_parent_project?(issue_in_same_project)
1589 assert_equal false, issue.valid_parent_project?(issue_in_child_project)
1589 assert_equal false, issue.valid_parent_project?(issue_in_child_project)
1590 assert_equal false, issue.valid_parent_project?(issue_in_grandchild_project)
1590 assert_equal false, issue.valid_parent_project?(issue_in_grandchild_project)
1591 assert_equal false, issue.valid_parent_project?(issue_in_different_tree)
1591 assert_equal false, issue.valid_parent_project?(issue_in_different_tree)
1592
1592
1593 assert_equal true, issue_in_child_project.valid_parent_project?(issue)
1593 assert_equal true, issue_in_child_project.valid_parent_project?(issue)
1594 assert_equal false, issue_in_child_project.valid_parent_project?(issue_in_other_child_project)
1594 assert_equal false, issue_in_child_project.valid_parent_project?(issue_in_other_child_project)
1595 end
1595 end
1596 end
1596 end
1597
1597
1598 def test_recipients_should_include_previous_assignee
1598 def test_recipients_should_include_previous_assignee
1599 user = User.find(3)
1599 user = User.find(3)
1600 user.members.update_all ["mail_notification = ?", false]
1600 user.members.update_all ["mail_notification = ?", false]
1601 user.update_attribute :mail_notification, 'only_assigned'
1601 user.update_attribute :mail_notification, 'only_assigned'
1602
1602
1603 issue = Issue.find(2)
1603 issue = Issue.find(2)
1604 issue.assigned_to = nil
1604 issue.assigned_to = nil
1605 assert_include user.mail, issue.recipients
1605 assert_include user.mail, issue.recipients
1606 issue.save!
1606 issue.save!
1607 assert !issue.recipients.include?(user.mail)
1607 assert !issue.recipients.include?(user.mail)
1608 end
1608 end
1609
1609
1610 def test_recipients_should_not_include_users_that_cannot_view_the_issue
1610 def test_recipients_should_not_include_users_that_cannot_view_the_issue
1611 issue = Issue.find(12)
1611 issue = Issue.find(12)
1612 assert issue.recipients.include?(issue.author.mail)
1612 assert issue.recipients.include?(issue.author.mail)
1613 # copy the issue to a private project
1613 # copy the issue to a private project
1614 copy = issue.copy(:project_id => 5, :tracker_id => 2)
1614 copy = issue.copy(:project_id => 5, :tracker_id => 2)
1615 # author is not a member of project anymore
1615 # author is not a member of project anymore
1616 assert !copy.recipients.include?(copy.author.mail)
1616 assert !copy.recipients.include?(copy.author.mail)
1617 end
1617 end
1618
1618
1619 def test_recipients_should_include_the_assigned_group_members
1619 def test_recipients_should_include_the_assigned_group_members
1620 group_member = User.generate!
1620 group_member = User.generate!
1621 group = Group.generate!
1621 group = Group.generate!
1622 group.users << group_member
1622 group.users << group_member
1623
1623
1624 issue = Issue.find(12)
1624 issue = Issue.find(12)
1625 issue.assigned_to = group
1625 issue.assigned_to = group
1626 assert issue.recipients.include?(group_member.mail)
1626 assert issue.recipients.include?(group_member.mail)
1627 end
1627 end
1628
1628
1629 def test_watcher_recipients_should_not_include_users_that_cannot_view_the_issue
1629 def test_watcher_recipients_should_not_include_users_that_cannot_view_the_issue
1630 user = User.find(3)
1630 user = User.find(3)
1631 issue = Issue.find(9)
1631 issue = Issue.find(9)
1632 Watcher.create!(:user => user, :watchable => issue)
1632 Watcher.create!(:user => user, :watchable => issue)
1633 assert issue.watched_by?(user)
1633 assert issue.watched_by?(user)
1634 assert !issue.watcher_recipients.include?(user.mail)
1634 assert !issue.watcher_recipients.include?(user.mail)
1635 end
1635 end
1636
1636
1637 def test_issue_destroy
1637 def test_issue_destroy
1638 Issue.find(1).destroy
1638 Issue.find(1).destroy
1639 assert_nil Issue.find_by_id(1)
1639 assert_nil Issue.find_by_id(1)
1640 assert_nil TimeEntry.find_by_issue_id(1)
1640 assert_nil TimeEntry.find_by_issue_id(1)
1641 end
1641 end
1642
1642
1643 def test_destroy_should_delete_time_entries_custom_values
1643 def test_destroy_should_delete_time_entries_custom_values
1644 issue = Issue.generate!
1644 issue = Issue.generate!
1645 time_entry = TimeEntry.generate!(:issue => issue, :custom_field_values => {10 => '1'})
1645 time_entry = TimeEntry.generate!(:issue => issue, :custom_field_values => {10 => '1'})
1646
1646
1647 assert_difference 'CustomValue.where(:customized_type => "TimeEntry").count', -1 do
1647 assert_difference 'CustomValue.where(:customized_type => "TimeEntry").count', -1 do
1648 assert issue.destroy
1648 assert issue.destroy
1649 end
1649 end
1650 end
1650 end
1651
1651
1652 def test_destroying_a_deleted_issue_should_not_raise_an_error
1652 def test_destroying_a_deleted_issue_should_not_raise_an_error
1653 issue = Issue.find(1)
1653 issue = Issue.find(1)
1654 Issue.find(1).destroy
1654 Issue.find(1).destroy
1655
1655
1656 assert_nothing_raised do
1656 assert_nothing_raised do
1657 assert_no_difference 'Issue.count' do
1657 assert_no_difference 'Issue.count' do
1658 issue.destroy
1658 issue.destroy
1659 end
1659 end
1660 assert issue.destroyed?
1660 assert issue.destroyed?
1661 end
1661 end
1662 end
1662 end
1663
1663
1664 def test_destroying_a_stale_issue_should_not_raise_an_error
1664 def test_destroying_a_stale_issue_should_not_raise_an_error
1665 issue = Issue.find(1)
1665 issue = Issue.find(1)
1666 Issue.find(1).update_attribute :subject, "Updated"
1666 Issue.find(1).update_attribute :subject, "Updated"
1667
1667
1668 assert_nothing_raised do
1668 assert_nothing_raised do
1669 assert_difference 'Issue.count', -1 do
1669 assert_difference 'Issue.count', -1 do
1670 issue.destroy
1670 issue.destroy
1671 end
1671 end
1672 assert issue.destroyed?
1672 assert issue.destroyed?
1673 end
1673 end
1674 end
1674 end
1675
1675
1676 def test_blocked
1676 def test_blocked
1677 blocked_issue = Issue.find(9)
1677 blocked_issue = Issue.find(9)
1678 blocking_issue = Issue.find(10)
1678 blocking_issue = Issue.find(10)
1679
1679
1680 assert blocked_issue.blocked?
1680 assert blocked_issue.blocked?
1681 assert !blocking_issue.blocked?
1681 assert !blocking_issue.blocked?
1682 end
1682 end
1683
1683
1684 def test_blocked_issues_dont_allow_closed_statuses
1684 def test_blocked_issues_dont_allow_closed_statuses
1685 blocked_issue = Issue.find(9)
1685 blocked_issue = Issue.find(9)
1686
1686
1687 allowed_statuses = blocked_issue.new_statuses_allowed_to(users(:users_002))
1687 allowed_statuses = blocked_issue.new_statuses_allowed_to(users(:users_002))
1688 assert !allowed_statuses.empty?
1688 assert !allowed_statuses.empty?
1689 closed_statuses = allowed_statuses.select {|st| st.is_closed?}
1689 closed_statuses = allowed_statuses.select {|st| st.is_closed?}
1690 assert closed_statuses.empty?
1690 assert closed_statuses.empty?
1691 end
1691 end
1692
1692
1693 def test_unblocked_issues_allow_closed_statuses
1693 def test_unblocked_issues_allow_closed_statuses
1694 blocking_issue = Issue.find(10)
1694 blocking_issue = Issue.find(10)
1695
1695
1696 allowed_statuses = blocking_issue.new_statuses_allowed_to(users(:users_002))
1696 allowed_statuses = blocking_issue.new_statuses_allowed_to(users(:users_002))
1697 assert !allowed_statuses.empty?
1697 assert !allowed_statuses.empty?
1698 closed_statuses = allowed_statuses.select {|st| st.is_closed?}
1698 closed_statuses = allowed_statuses.select {|st| st.is_closed?}
1699 assert !closed_statuses.empty?
1699 assert !closed_statuses.empty?
1700 end
1700 end
1701
1701
1702 def test_reschedule_an_issue_without_dates
1702 def test_reschedule_an_issue_without_dates
1703 with_settings :non_working_week_days => [] do
1703 with_settings :non_working_week_days => [] do
1704 issue = Issue.new(:start_date => nil, :due_date => nil)
1704 issue = Issue.new(:start_date => nil, :due_date => nil)
1705 issue.reschedule_on '2012-10-09'.to_date
1705 issue.reschedule_on '2012-10-09'.to_date
1706 assert_equal '2012-10-09'.to_date, issue.start_date
1706 assert_equal '2012-10-09'.to_date, issue.start_date
1707 assert_equal '2012-10-09'.to_date, issue.due_date
1707 assert_equal '2012-10-09'.to_date, issue.due_date
1708 end
1708 end
1709
1709
1710 with_settings :non_working_week_days => %w(6 7) do
1710 with_settings :non_working_week_days => %w(6 7) do
1711 issue = Issue.new(:start_date => nil, :due_date => nil)
1711 issue = Issue.new(:start_date => nil, :due_date => nil)
1712 issue.reschedule_on '2012-10-09'.to_date
1712 issue.reschedule_on '2012-10-09'.to_date
1713 assert_equal '2012-10-09'.to_date, issue.start_date
1713 assert_equal '2012-10-09'.to_date, issue.start_date
1714 assert_equal '2012-10-09'.to_date, issue.due_date
1714 assert_equal '2012-10-09'.to_date, issue.due_date
1715
1715
1716 issue = Issue.new(:start_date => nil, :due_date => nil)
1716 issue = Issue.new(:start_date => nil, :due_date => nil)
1717 issue.reschedule_on '2012-10-13'.to_date
1717 issue.reschedule_on '2012-10-13'.to_date
1718 assert_equal '2012-10-15'.to_date, issue.start_date
1718 assert_equal '2012-10-15'.to_date, issue.start_date
1719 assert_equal '2012-10-15'.to_date, issue.due_date
1719 assert_equal '2012-10-15'.to_date, issue.due_date
1720 end
1720 end
1721 end
1721 end
1722
1722
1723 def test_reschedule_an_issue_with_start_date
1723 def test_reschedule_an_issue_with_start_date
1724 with_settings :non_working_week_days => [] do
1724 with_settings :non_working_week_days => [] do
1725 issue = Issue.new(:start_date => '2012-10-09', :due_date => nil)
1725 issue = Issue.new(:start_date => '2012-10-09', :due_date => nil)
1726 issue.reschedule_on '2012-10-13'.to_date
1726 issue.reschedule_on '2012-10-13'.to_date
1727 assert_equal '2012-10-13'.to_date, issue.start_date
1727 assert_equal '2012-10-13'.to_date, issue.start_date
1728 assert_equal '2012-10-13'.to_date, issue.due_date
1728 assert_equal '2012-10-13'.to_date, issue.due_date
1729 end
1729 end
1730
1730
1731 with_settings :non_working_week_days => %w(6 7) do
1731 with_settings :non_working_week_days => %w(6 7) do
1732 issue = Issue.new(:start_date => '2012-10-09', :due_date => nil)
1732 issue = Issue.new(:start_date => '2012-10-09', :due_date => nil)
1733 issue.reschedule_on '2012-10-11'.to_date
1733 issue.reschedule_on '2012-10-11'.to_date
1734 assert_equal '2012-10-11'.to_date, issue.start_date
1734 assert_equal '2012-10-11'.to_date, issue.start_date
1735 assert_equal '2012-10-11'.to_date, issue.due_date
1735 assert_equal '2012-10-11'.to_date, issue.due_date
1736
1736
1737 issue = Issue.new(:start_date => '2012-10-09', :due_date => nil)
1737 issue = Issue.new(:start_date => '2012-10-09', :due_date => nil)
1738 issue.reschedule_on '2012-10-13'.to_date
1738 issue.reschedule_on '2012-10-13'.to_date
1739 assert_equal '2012-10-15'.to_date, issue.start_date
1739 assert_equal '2012-10-15'.to_date, issue.start_date
1740 assert_equal '2012-10-15'.to_date, issue.due_date
1740 assert_equal '2012-10-15'.to_date, issue.due_date
1741 end
1741 end
1742 end
1742 end
1743
1743
1744 def test_reschedule_an_issue_with_start_and_due_dates
1744 def test_reschedule_an_issue_with_start_and_due_dates
1745 with_settings :non_working_week_days => [] do
1745 with_settings :non_working_week_days => [] do
1746 issue = Issue.new(:start_date => '2012-10-09', :due_date => '2012-10-15')
1746 issue = Issue.new(:start_date => '2012-10-09', :due_date => '2012-10-15')
1747 issue.reschedule_on '2012-10-13'.to_date
1747 issue.reschedule_on '2012-10-13'.to_date
1748 assert_equal '2012-10-13'.to_date, issue.start_date
1748 assert_equal '2012-10-13'.to_date, issue.start_date
1749 assert_equal '2012-10-19'.to_date, issue.due_date
1749 assert_equal '2012-10-19'.to_date, issue.due_date
1750 end
1750 end
1751
1751
1752 with_settings :non_working_week_days => %w(6 7) do
1752 with_settings :non_working_week_days => %w(6 7) do
1753 issue = Issue.new(:start_date => '2012-10-09', :due_date => '2012-10-19') # 8 working days
1753 issue = Issue.new(:start_date => '2012-10-09', :due_date => '2012-10-19') # 8 working days
1754 issue.reschedule_on '2012-10-11'.to_date
1754 issue.reschedule_on '2012-10-11'.to_date
1755 assert_equal '2012-10-11'.to_date, issue.start_date
1755 assert_equal '2012-10-11'.to_date, issue.start_date
1756 assert_equal '2012-10-23'.to_date, issue.due_date
1756 assert_equal '2012-10-23'.to_date, issue.due_date
1757
1757
1758 issue = Issue.new(:start_date => '2012-10-09', :due_date => '2012-10-19')
1758 issue = Issue.new(:start_date => '2012-10-09', :due_date => '2012-10-19')
1759 issue.reschedule_on '2012-10-13'.to_date
1759 issue.reschedule_on '2012-10-13'.to_date
1760 assert_equal '2012-10-15'.to_date, issue.start_date
1760 assert_equal '2012-10-15'.to_date, issue.start_date
1761 assert_equal '2012-10-25'.to_date, issue.due_date
1761 assert_equal '2012-10-25'.to_date, issue.due_date
1762 end
1762 end
1763 end
1763 end
1764
1764
1765 def test_rescheduling_an_issue_to_a_later_due_date_should_reschedule_following_issue
1765 def test_rescheduling_an_issue_to_a_later_due_date_should_reschedule_following_issue
1766 issue1 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1766 issue1 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1767 issue2 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1767 issue2 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1768 IssueRelation.create!(:issue_from => issue1, :issue_to => issue2,
1768 IssueRelation.create!(:issue_from => issue1, :issue_to => issue2,
1769 :relation_type => IssueRelation::TYPE_PRECEDES)
1769 :relation_type => IssueRelation::TYPE_PRECEDES)
1770 assert_equal Date.parse('2012-10-18'), issue2.reload.start_date
1770 assert_equal Date.parse('2012-10-18'), issue2.reload.start_date
1771
1771
1772 issue1.reload
1772 issue1.reload
1773 issue1.due_date = '2012-10-23'
1773 issue1.due_date = '2012-10-23'
1774 issue1.save!
1774 issue1.save!
1775 issue2.reload
1775 issue2.reload
1776 assert_equal Date.parse('2012-10-24'), issue2.start_date
1776 assert_equal Date.parse('2012-10-24'), issue2.start_date
1777 assert_equal Date.parse('2012-10-26'), issue2.due_date
1777 assert_equal Date.parse('2012-10-26'), issue2.due_date
1778 end
1778 end
1779
1779
1780 def test_rescheduling_an_issue_to_an_earlier_due_date_should_reschedule_following_issue
1780 def test_rescheduling_an_issue_to_an_earlier_due_date_should_reschedule_following_issue
1781 issue1 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1781 issue1 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1782 issue2 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1782 issue2 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1783 IssueRelation.create!(:issue_from => issue1, :issue_to => issue2,
1783 IssueRelation.create!(:issue_from => issue1, :issue_to => issue2,
1784 :relation_type => IssueRelation::TYPE_PRECEDES)
1784 :relation_type => IssueRelation::TYPE_PRECEDES)
1785 assert_equal Date.parse('2012-10-18'), issue2.reload.start_date
1785 assert_equal Date.parse('2012-10-18'), issue2.reload.start_date
1786
1786
1787 issue1.reload
1787 issue1.reload
1788 issue1.start_date = '2012-09-17'
1788 issue1.start_date = '2012-09-17'
1789 issue1.due_date = '2012-09-18'
1789 issue1.due_date = '2012-09-18'
1790 issue1.save!
1790 issue1.save!
1791 issue2.reload
1791 issue2.reload
1792 assert_equal Date.parse('2012-09-19'), issue2.start_date
1792 assert_equal Date.parse('2012-09-19'), issue2.start_date
1793 assert_equal Date.parse('2012-09-21'), issue2.due_date
1793 assert_equal Date.parse('2012-09-21'), issue2.due_date
1794 end
1794 end
1795
1795
1796 def test_rescheduling_reschedule_following_issue_earlier_should_consider_other_preceding_issues
1796 def test_rescheduling_reschedule_following_issue_earlier_should_consider_other_preceding_issues
1797 issue1 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1797 issue1 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1798 issue2 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1798 issue2 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1799 issue3 = Issue.generate!(:start_date => '2012-10-01', :due_date => '2012-10-02')
1799 issue3 = Issue.generate!(:start_date => '2012-10-01', :due_date => '2012-10-02')
1800 IssueRelation.create!(:issue_from => issue1, :issue_to => issue2,
1800 IssueRelation.create!(:issue_from => issue1, :issue_to => issue2,
1801 :relation_type => IssueRelation::TYPE_PRECEDES)
1801 :relation_type => IssueRelation::TYPE_PRECEDES)
1802 IssueRelation.create!(:issue_from => issue3, :issue_to => issue2,
1802 IssueRelation.create!(:issue_from => issue3, :issue_to => issue2,
1803 :relation_type => IssueRelation::TYPE_PRECEDES)
1803 :relation_type => IssueRelation::TYPE_PRECEDES)
1804 assert_equal Date.parse('2012-10-18'), issue2.reload.start_date
1804 assert_equal Date.parse('2012-10-18'), issue2.reload.start_date
1805
1805
1806 issue1.reload
1806 issue1.reload
1807 issue1.start_date = '2012-09-17'
1807 issue1.start_date = '2012-09-17'
1808 issue1.due_date = '2012-09-18'
1808 issue1.due_date = '2012-09-18'
1809 issue1.save!
1809 issue1.save!
1810 issue2.reload
1810 issue2.reload
1811 # Issue 2 must start after Issue 3
1811 # Issue 2 must start after Issue 3
1812 assert_equal Date.parse('2012-10-03'), issue2.start_date
1812 assert_equal Date.parse('2012-10-03'), issue2.start_date
1813 assert_equal Date.parse('2012-10-05'), issue2.due_date
1813 assert_equal Date.parse('2012-10-05'), issue2.due_date
1814 end
1814 end
1815
1815
1816 def test_rescheduling_a_stale_issue_should_not_raise_an_error
1816 def test_rescheduling_a_stale_issue_should_not_raise_an_error
1817 with_settings :non_working_week_days => [] do
1817 with_settings :non_working_week_days => [] do
1818 stale = Issue.find(1)
1818 stale = Issue.find(1)
1819 issue = Issue.find(1)
1819 issue = Issue.find(1)
1820 issue.subject = "Updated"
1820 issue.subject = "Updated"
1821 issue.save!
1821 issue.save!
1822 date = 10.days.from_now.to_date
1822 date = 10.days.from_now.to_date
1823 assert_nothing_raised do
1823 assert_nothing_raised do
1824 stale.reschedule_on!(date)
1824 stale.reschedule_on!(date)
1825 end
1825 end
1826 assert_equal date, stale.reload.start_date
1826 assert_equal date, stale.reload.start_date
1827 end
1827 end
1828 end
1828 end
1829
1829
1830 def test_child_issue_should_consider_parent_soonest_start_on_create
1830 def test_child_issue_should_consider_parent_soonest_start_on_create
1831 set_language_if_valid 'en'
1831 set_language_if_valid 'en'
1832 issue1 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1832 issue1 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1833 issue2 = Issue.generate!(:start_date => '2012-10-18', :due_date => '2012-10-20')
1833 issue2 = Issue.generate!(:start_date => '2012-10-18', :due_date => '2012-10-20')
1834 IssueRelation.create!(:issue_from => issue1, :issue_to => issue2,
1834 IssueRelation.create!(:issue_from => issue1, :issue_to => issue2,
1835 :relation_type => IssueRelation::TYPE_PRECEDES)
1835 :relation_type => IssueRelation::TYPE_PRECEDES)
1836 issue1.reload
1836 issue1.reload
1837 issue2.reload
1837 issue2.reload
1838 assert_equal Date.parse('2012-10-18'), issue2.start_date
1838 assert_equal Date.parse('2012-10-18'), issue2.start_date
1839
1839
1840 with_settings :date_format => '%m/%d/%Y' do
1840 with_settings :date_format => '%m/%d/%Y' do
1841 child = Issue.new(:parent_issue_id => issue2.id, :start_date => '2012-10-16',
1841 child = Issue.new(:parent_issue_id => issue2.id, :start_date => '2012-10-16',
1842 :project_id => 1, :tracker_id => 1, :status_id => 1, :subject => 'Child', :author_id => 1)
1842 :project_id => 1, :tracker_id => 1, :status_id => 1, :subject => 'Child', :author_id => 1)
1843 assert !child.valid?
1843 assert !child.valid?
1844 assert_include 'Start date cannot be earlier than 10/18/2012 because of preceding issues', child.errors.full_messages
1844 assert_include 'Start date cannot be earlier than 10/18/2012 because of preceding issues', child.errors.full_messages
1845 assert_equal Date.parse('2012-10-18'), child.soonest_start
1845 assert_equal Date.parse('2012-10-18'), child.soonest_start
1846 child.start_date = '2012-10-18'
1846 child.start_date = '2012-10-18'
1847 assert child.save
1847 assert child.save
1848 end
1848 end
1849 end
1849 end
1850
1850
1851 def test_setting_parent_to_a_an_issue_that_precedes_should_not_validate
1851 def test_setting_parent_to_a_an_issue_that_precedes_should_not_validate
1852 # tests that 3 cannot have 1 as parent:
1852 # tests that 3 cannot have 1 as parent:
1853 #
1853 #
1854 # 1 -> 2 -> 3
1854 # 1 -> 2 -> 3
1855 #
1855 #
1856 set_language_if_valid 'en'
1856 set_language_if_valid 'en'
1857 issue1 = Issue.generate!
1857 issue1 = Issue.generate!
1858 issue2 = Issue.generate!
1858 issue2 = Issue.generate!
1859 issue3 = Issue.generate!
1859 issue3 = Issue.generate!
1860 IssueRelation.create!(:issue_from => issue1, :issue_to => issue2, :relation_type => IssueRelation::TYPE_PRECEDES)
1860 IssueRelation.create!(:issue_from => issue1, :issue_to => issue2, :relation_type => IssueRelation::TYPE_PRECEDES)
1861 IssueRelation.create!(:issue_from => issue2, :issue_to => issue3, :relation_type => IssueRelation::TYPE_PRECEDES)
1861 IssueRelation.create!(:issue_from => issue2, :issue_to => issue3, :relation_type => IssueRelation::TYPE_PRECEDES)
1862 issue3.reload
1862 issue3.reload
1863 issue3.parent_issue_id = issue1.id
1863 issue3.parent_issue_id = issue1.id
1864 assert !issue3.valid?
1864 assert !issue3.valid?
1865 assert_include 'Parent task is invalid', issue3.errors.full_messages
1865 assert_include 'Parent task is invalid', issue3.errors.full_messages
1866 end
1866 end
1867
1867
1868 def test_setting_parent_to_a_an_issue_that_follows_should_not_validate
1868 def test_setting_parent_to_a_an_issue_that_follows_should_not_validate
1869 # tests that 1 cannot have 3 as parent:
1869 # tests that 1 cannot have 3 as parent:
1870 #
1870 #
1871 # 1 -> 2 -> 3
1871 # 1 -> 2 -> 3
1872 #
1872 #
1873 set_language_if_valid 'en'
1873 set_language_if_valid 'en'
1874 issue1 = Issue.generate!
1874 issue1 = Issue.generate!
1875 issue2 = Issue.generate!
1875 issue2 = Issue.generate!
1876 issue3 = Issue.generate!
1876 issue3 = Issue.generate!
1877 IssueRelation.create!(:issue_from => issue1, :issue_to => issue2, :relation_type => IssueRelation::TYPE_PRECEDES)
1877 IssueRelation.create!(:issue_from => issue1, :issue_to => issue2, :relation_type => IssueRelation::TYPE_PRECEDES)
1878 IssueRelation.create!(:issue_from => issue2, :issue_to => issue3, :relation_type => IssueRelation::TYPE_PRECEDES)
1878 IssueRelation.create!(:issue_from => issue2, :issue_to => issue3, :relation_type => IssueRelation::TYPE_PRECEDES)
1879 issue1.reload
1879 issue1.reload
1880 issue1.parent_issue_id = issue3.id
1880 issue1.parent_issue_id = issue3.id
1881 assert !issue1.valid?
1881 assert !issue1.valid?
1882 assert_include 'Parent task is invalid', issue1.errors.full_messages
1882 assert_include 'Parent task is invalid', issue1.errors.full_messages
1883 end
1883 end
1884
1884
1885 def test_setting_parent_to_a_an_issue_that_precedes_through_hierarchy_should_not_validate
1885 def test_setting_parent_to_a_an_issue_that_precedes_through_hierarchy_should_not_validate
1886 # tests that 4 cannot have 1 as parent:
1886 # tests that 4 cannot have 1 as parent:
1887 # changing the due date of 4 would update the end date of 1 which would reschedule 2
1887 # changing the due date of 4 would update the end date of 1 which would reschedule 2
1888 # which would change the end date of 3 which would reschedule 4 and so on...
1888 # which would change the end date of 3 which would reschedule 4 and so on...
1889 #
1889 #
1890 # 3 -> 4
1890 # 3 -> 4
1891 # ^
1891 # ^
1892 # 1 -> 2
1892 # 1 -> 2
1893 #
1893 #
1894 set_language_if_valid 'en'
1894 set_language_if_valid 'en'
1895 issue1 = Issue.generate!
1895 issue1 = Issue.generate!
1896 issue2 = Issue.generate!
1896 issue2 = Issue.generate!
1897 IssueRelation.create!(:issue_from => issue1, :issue_to => issue2, :relation_type => IssueRelation::TYPE_PRECEDES)
1897 IssueRelation.create!(:issue_from => issue1, :issue_to => issue2, :relation_type => IssueRelation::TYPE_PRECEDES)
1898 issue3 = Issue.generate!
1898 issue3 = Issue.generate!
1899 issue2.reload
1899 issue2.reload
1900 issue2.parent_issue_id = issue3.id
1900 issue2.parent_issue_id = issue3.id
1901 issue2.save!
1901 issue2.save!
1902 issue4 = Issue.generate!
1902 issue4 = Issue.generate!
1903 IssueRelation.create!(:issue_from => issue3, :issue_to => issue4, :relation_type => IssueRelation::TYPE_PRECEDES)
1903 IssueRelation.create!(:issue_from => issue3, :issue_to => issue4, :relation_type => IssueRelation::TYPE_PRECEDES)
1904 issue4.reload
1904 issue4.reload
1905 issue4.parent_issue_id = issue1.id
1905 issue4.parent_issue_id = issue1.id
1906 assert !issue4.valid?
1906 assert !issue4.valid?
1907 assert_include 'Parent task is invalid', issue4.errors.full_messages
1907 assert_include 'Parent task is invalid', issue4.errors.full_messages
1908 end
1908 end
1909
1909
1910 def test_issue_and_following_issue_should_be_able_to_be_moved_to_the_same_parent
1910 def test_issue_and_following_issue_should_be_able_to_be_moved_to_the_same_parent
1911 set_language_if_valid 'en'
1911 set_language_if_valid 'en'
1912 issue1 = Issue.generate!
1912 issue1 = Issue.generate!
1913 issue2 = Issue.generate!
1913 issue2 = Issue.generate!
1914 relation = IssueRelation.create!(:issue_from => issue2, :issue_to => issue1, :relation_type => IssueRelation::TYPE_FOLLOWS)
1914 relation = IssueRelation.create!(:issue_from => issue2, :issue_to => issue1, :relation_type => IssueRelation::TYPE_FOLLOWS)
1915 parent = Issue.generate!
1915 parent = Issue.generate!
1916 issue1.reload.parent_issue_id = parent.id
1916 issue1.reload.parent_issue_id = parent.id
1917 assert_save issue1
1917 assert_save issue1
1918 parent.reload
1918 parent.reload
1919 issue2.reload.parent_issue_id = parent.id
1919 issue2.reload.parent_issue_id = parent.id
1920 assert_save issue2
1920 assert_save issue2
1921 assert IssueRelation.exists?(relation.id)
1921 assert IssueRelation.exists?(relation.id)
1922 end
1922 end
1923
1923
1924 def test_issue_and_preceding_issue_should_be_able_to_be_moved_to_the_same_parent
1924 def test_issue_and_preceding_issue_should_be_able_to_be_moved_to_the_same_parent
1925 set_language_if_valid 'en'
1925 set_language_if_valid 'en'
1926 issue1 = Issue.generate!
1926 issue1 = Issue.generate!
1927 issue2 = Issue.generate!
1927 issue2 = Issue.generate!
1928 relation = IssueRelation.create!(:issue_from => issue2, :issue_to => issue1, :relation_type => IssueRelation::TYPE_PRECEDES)
1928 relation = IssueRelation.create!(:issue_from => issue2, :issue_to => issue1, :relation_type => IssueRelation::TYPE_PRECEDES)
1929 parent = Issue.generate!
1929 parent = Issue.generate!
1930 issue1.reload.parent_issue_id = parent.id
1930 issue1.reload.parent_issue_id = parent.id
1931 assert_save issue1
1931 assert_save issue1
1932 parent.reload
1932 parent.reload
1933 issue2.reload.parent_issue_id = parent.id
1933 issue2.reload.parent_issue_id = parent.id
1934 assert_save issue2
1934 assert_save issue2
1935 assert IssueRelation.exists?(relation.id)
1935 assert IssueRelation.exists?(relation.id)
1936 end
1936 end
1937
1937
1938 def test_issue_and_blocked_issue_should_be_able_to_be_moved_to_the_same_parent
1938 def test_issue_and_blocked_issue_should_be_able_to_be_moved_to_the_same_parent
1939 set_language_if_valid 'en'
1939 set_language_if_valid 'en'
1940 issue1 = Issue.generate!
1940 issue1 = Issue.generate!
1941 issue2 = Issue.generate!
1941 issue2 = Issue.generate!
1942 relation = IssueRelation.create!(:issue_from => issue2, :issue_to => issue1, :relation_type => IssueRelation::TYPE_BLOCKED)
1942 relation = IssueRelation.create!(:issue_from => issue2, :issue_to => issue1, :relation_type => IssueRelation::TYPE_BLOCKED)
1943 parent = Issue.generate!
1943 parent = Issue.generate!
1944 issue1.reload.parent_issue_id = parent.id
1944 issue1.reload.parent_issue_id = parent.id
1945 assert_save issue1
1945 assert_save issue1
1946 parent.reload
1946 parent.reload
1947 issue2.reload.parent_issue_id = parent.id
1947 issue2.reload.parent_issue_id = parent.id
1948 assert_save issue2
1948 assert_save issue2
1949 assert IssueRelation.exists?(relation.id)
1949 assert IssueRelation.exists?(relation.id)
1950 end
1950 end
1951
1951
1952 def test_issue_and_blocking_issue_should_be_able_to_be_moved_to_the_same_parent
1952 def test_issue_and_blocking_issue_should_be_able_to_be_moved_to_the_same_parent
1953 set_language_if_valid 'en'
1953 set_language_if_valid 'en'
1954 issue1 = Issue.generate!
1954 issue1 = Issue.generate!
1955 issue2 = Issue.generate!
1955 issue2 = Issue.generate!
1956 relation = IssueRelation.create!(:issue_from => issue2, :issue_to => issue1, :relation_type => IssueRelation::TYPE_BLOCKS)
1956 relation = IssueRelation.create!(:issue_from => issue2, :issue_to => issue1, :relation_type => IssueRelation::TYPE_BLOCKS)
1957 parent = Issue.generate!
1957 parent = Issue.generate!
1958 issue1.reload.parent_issue_id = parent.id
1958 issue1.reload.parent_issue_id = parent.id
1959 assert_save issue1
1959 assert_save issue1
1960 parent.reload
1960 parent.reload
1961 issue2.reload.parent_issue_id = parent.id
1961 issue2.reload.parent_issue_id = parent.id
1962 assert_save issue2
1962 assert_save issue2
1963 assert IssueRelation.exists?(relation.id)
1963 assert IssueRelation.exists?(relation.id)
1964 end
1964 end
1965
1965
1966 def test_issue_copy_should_be_able_to_be_moved_to_the_same_parent_as_copied_issue
1967 issue = Issue.generate!
1968 parent = Issue.generate!
1969 issue.parent_issue_id = parent.id
1970 issue.save!
1971 issue.reload
1972
1973 copy = Issue.new.copy_from(issue, :link => true)
1974 relation = new_record(IssueRelation) do
1975 copy.save!
1976 end
1977
1978 copy.parent_issue_id = parent.id
1979 assert_save copy
1980 assert IssueRelation.exists?(relation.id)
1981 end
1982
1966 def test_overdue
1983 def test_overdue
1967 assert Issue.new(:due_date => 1.day.ago.to_date).overdue?
1984 assert Issue.new(:due_date => 1.day.ago.to_date).overdue?
1968 assert !Issue.new(:due_date => Date.today).overdue?
1985 assert !Issue.new(:due_date => Date.today).overdue?
1969 assert !Issue.new(:due_date => 1.day.from_now.to_date).overdue?
1986 assert !Issue.new(:due_date => 1.day.from_now.to_date).overdue?
1970 assert !Issue.new(:due_date => nil).overdue?
1987 assert !Issue.new(:due_date => nil).overdue?
1971 assert !Issue.new(:due_date => 1.day.ago.to_date,
1988 assert !Issue.new(:due_date => 1.day.ago.to_date,
1972 :status => IssueStatus.where(:is_closed => true).first
1989 :status => IssueStatus.where(:is_closed => true).first
1973 ).overdue?
1990 ).overdue?
1974 end
1991 end
1975
1992
1976 test "#behind_schedule? should be false if the issue has no start_date" do
1993 test "#behind_schedule? should be false if the issue has no start_date" do
1977 assert !Issue.new(:start_date => nil,
1994 assert !Issue.new(:start_date => nil,
1978 :due_date => 1.day.from_now.to_date,
1995 :due_date => 1.day.from_now.to_date,
1979 :done_ratio => 0).behind_schedule?
1996 :done_ratio => 0).behind_schedule?
1980 end
1997 end
1981
1998
1982 test "#behind_schedule? should be false if the issue has no end_date" do
1999 test "#behind_schedule? should be false if the issue has no end_date" do
1983 assert !Issue.new(:start_date => 1.day.from_now.to_date,
2000 assert !Issue.new(:start_date => 1.day.from_now.to_date,
1984 :due_date => nil,
2001 :due_date => nil,
1985 :done_ratio => 0).behind_schedule?
2002 :done_ratio => 0).behind_schedule?
1986 end
2003 end
1987
2004
1988 test "#behind_schedule? should be false if the issue has more done than it's calendar time" do
2005 test "#behind_schedule? should be false if the issue has more done than it's calendar time" do
1989 assert !Issue.new(:start_date => 50.days.ago.to_date,
2006 assert !Issue.new(:start_date => 50.days.ago.to_date,
1990 :due_date => 50.days.from_now.to_date,
2007 :due_date => 50.days.from_now.to_date,
1991 :done_ratio => 90).behind_schedule?
2008 :done_ratio => 90).behind_schedule?
1992 end
2009 end
1993
2010
1994 test "#behind_schedule? should be true if the issue hasn't been started at all" do
2011 test "#behind_schedule? should be true if the issue hasn't been started at all" do
1995 assert Issue.new(:start_date => 1.day.ago.to_date,
2012 assert Issue.new(:start_date => 1.day.ago.to_date,
1996 :due_date => 1.day.from_now.to_date,
2013 :due_date => 1.day.from_now.to_date,
1997 :done_ratio => 0).behind_schedule?
2014 :done_ratio => 0).behind_schedule?
1998 end
2015 end
1999
2016
2000 test "#behind_schedule? should be true if the issue has used more calendar time than it's done ratio" do
2017 test "#behind_schedule? should be true if the issue has used more calendar time than it's done ratio" do
2001 assert Issue.new(:start_date => 100.days.ago.to_date,
2018 assert Issue.new(:start_date => 100.days.ago.to_date,
2002 :due_date => Date.today,
2019 :due_date => Date.today,
2003 :done_ratio => 90).behind_schedule?
2020 :done_ratio => 90).behind_schedule?
2004 end
2021 end
2005
2022
2006 test "#assignable_users should be Users" do
2023 test "#assignable_users should be Users" do
2007 assert_kind_of User, Issue.find(1).assignable_users.first
2024 assert_kind_of User, Issue.find(1).assignable_users.first
2008 end
2025 end
2009
2026
2010 test "#assignable_users should include the issue author" do
2027 test "#assignable_users should include the issue author" do
2011 non_project_member = User.generate!
2028 non_project_member = User.generate!
2012 issue = Issue.generate!(:author => non_project_member)
2029 issue = Issue.generate!(:author => non_project_member)
2013
2030
2014 assert issue.assignable_users.include?(non_project_member)
2031 assert issue.assignable_users.include?(non_project_member)
2015 end
2032 end
2016
2033
2017 def test_assignable_users_should_not_include_anonymous_user
2034 def test_assignable_users_should_not_include_anonymous_user
2018 issue = Issue.generate!(:author => User.anonymous)
2035 issue = Issue.generate!(:author => User.anonymous)
2019
2036
2020 assert !issue.assignable_users.include?(User.anonymous)
2037 assert !issue.assignable_users.include?(User.anonymous)
2021 end
2038 end
2022
2039
2023 def test_assignable_users_should_not_include_locked_user
2040 def test_assignable_users_should_not_include_locked_user
2024 user = User.generate!
2041 user = User.generate!
2025 issue = Issue.generate!(:author => user)
2042 issue = Issue.generate!(:author => user)
2026 user.lock!
2043 user.lock!
2027
2044
2028 assert !issue.assignable_users.include?(user)
2045 assert !issue.assignable_users.include?(user)
2029 end
2046 end
2030
2047
2031 test "#assignable_users should include the current assignee" do
2048 test "#assignable_users should include the current assignee" do
2032 user = User.generate!
2049 user = User.generate!
2033 issue = Issue.generate!(:assigned_to => user)
2050 issue = Issue.generate!(:assigned_to => user)
2034 user.lock!
2051 user.lock!
2035
2052
2036 assert Issue.find(issue.id).assignable_users.include?(user)
2053 assert Issue.find(issue.id).assignable_users.include?(user)
2037 end
2054 end
2038
2055
2039 test "#assignable_users should not show the issue author twice" do
2056 test "#assignable_users should not show the issue author twice" do
2040 assignable_user_ids = Issue.find(1).assignable_users.collect(&:id)
2057 assignable_user_ids = Issue.find(1).assignable_users.collect(&:id)
2041 assert_equal 2, assignable_user_ids.length
2058 assert_equal 2, assignable_user_ids.length
2042
2059
2043 assignable_user_ids.each do |user_id|
2060 assignable_user_ids.each do |user_id|
2044 assert_equal 1, assignable_user_ids.select {|i| i == user_id}.length,
2061 assert_equal 1, assignable_user_ids.select {|i| i == user_id}.length,
2045 "User #{user_id} appears more or less than once"
2062 "User #{user_id} appears more or less than once"
2046 end
2063 end
2047 end
2064 end
2048
2065
2049 test "#assignable_users with issue_group_assignment should include groups" do
2066 test "#assignable_users with issue_group_assignment should include groups" do
2050 issue = Issue.new(:project => Project.find(2))
2067 issue = Issue.new(:project => Project.find(2))
2051
2068
2052 with_settings :issue_group_assignment => '1' do
2069 with_settings :issue_group_assignment => '1' do
2053 assert_equal %w(Group User), issue.assignable_users.map {|a| a.class.name}.uniq.sort
2070 assert_equal %w(Group User), issue.assignable_users.map {|a| a.class.name}.uniq.sort
2054 assert issue.assignable_users.include?(Group.find(11))
2071 assert issue.assignable_users.include?(Group.find(11))
2055 end
2072 end
2056 end
2073 end
2057
2074
2058 test "#assignable_users without issue_group_assignment should not include groups" do
2075 test "#assignable_users without issue_group_assignment should not include groups" do
2059 issue = Issue.new(:project => Project.find(2))
2076 issue = Issue.new(:project => Project.find(2))
2060
2077
2061 with_settings :issue_group_assignment => '0' do
2078 with_settings :issue_group_assignment => '0' do
2062 assert_equal %w(User), issue.assignable_users.map {|a| a.class.name}.uniq.sort
2079 assert_equal %w(User), issue.assignable_users.map {|a| a.class.name}.uniq.sort
2063 assert !issue.assignable_users.include?(Group.find(11))
2080 assert !issue.assignable_users.include?(Group.find(11))
2064 end
2081 end
2065 end
2082 end
2066
2083
2067 def test_assignable_users_should_not_include_builtin_groups
2084 def test_assignable_users_should_not_include_builtin_groups
2068 Member.create!(:project_id => 1, :principal => Group.non_member, :role_ids => [1])
2085 Member.create!(:project_id => 1, :principal => Group.non_member, :role_ids => [1])
2069 Member.create!(:project_id => 1, :principal => Group.anonymous, :role_ids => [1])
2086 Member.create!(:project_id => 1, :principal => Group.anonymous, :role_ids => [1])
2070 issue = Issue.new(:project => Project.find(1))
2087 issue = Issue.new(:project => Project.find(1))
2071
2088
2072 with_settings :issue_group_assignment => '1' do
2089 with_settings :issue_group_assignment => '1' do
2073 assert_nil issue.assignable_users.detect {|u| u.is_a?(GroupBuiltin)}
2090 assert_nil issue.assignable_users.detect {|u| u.is_a?(GroupBuiltin)}
2074 end
2091 end
2075 end
2092 end
2076
2093
2077 def test_create_should_send_email_notification
2094 def test_create_should_send_email_notification
2078 ActionMailer::Base.deliveries.clear
2095 ActionMailer::Base.deliveries.clear
2079 issue = Issue.new(:project_id => 1, :tracker_id => 1,
2096 issue = Issue.new(:project_id => 1, :tracker_id => 1,
2080 :author_id => 3, :status_id => 1,
2097 :author_id => 3, :status_id => 1,
2081 :priority => IssuePriority.all.first,
2098 :priority => IssuePriority.all.first,
2082 :subject => 'test_create', :estimated_hours => '1:30')
2099 :subject => 'test_create', :estimated_hours => '1:30')
2083 with_settings :notified_events => %w(issue_added) do
2100 with_settings :notified_events => %w(issue_added) do
2084 assert issue.save
2101 assert issue.save
2085 assert_equal 1, ActionMailer::Base.deliveries.size
2102 assert_equal 1, ActionMailer::Base.deliveries.size
2086 end
2103 end
2087 end
2104 end
2088
2105
2089 def test_create_should_send_one_email_notification_with_both_settings
2106 def test_create_should_send_one_email_notification_with_both_settings
2090 ActionMailer::Base.deliveries.clear
2107 ActionMailer::Base.deliveries.clear
2091 issue = Issue.new(:project_id => 1, :tracker_id => 1,
2108 issue = Issue.new(:project_id => 1, :tracker_id => 1,
2092 :author_id => 3, :status_id => 1,
2109 :author_id => 3, :status_id => 1,
2093 :priority => IssuePriority.all.first,
2110 :priority => IssuePriority.all.first,
2094 :subject => 'test_create', :estimated_hours => '1:30')
2111 :subject => 'test_create', :estimated_hours => '1:30')
2095 with_settings :notified_events => %w(issue_added issue_updated) do
2112 with_settings :notified_events => %w(issue_added issue_updated) do
2096 assert issue.save
2113 assert issue.save
2097 assert_equal 1, ActionMailer::Base.deliveries.size
2114 assert_equal 1, ActionMailer::Base.deliveries.size
2098 end
2115 end
2099 end
2116 end
2100
2117
2101 def test_create_should_not_send_email_notification_with_no_setting
2118 def test_create_should_not_send_email_notification_with_no_setting
2102 ActionMailer::Base.deliveries.clear
2119 ActionMailer::Base.deliveries.clear
2103 issue = Issue.new(:project_id => 1, :tracker_id => 1,
2120 issue = Issue.new(:project_id => 1, :tracker_id => 1,
2104 :author_id => 3, :status_id => 1,
2121 :author_id => 3, :status_id => 1,
2105 :priority => IssuePriority.all.first,
2122 :priority => IssuePriority.all.first,
2106 :subject => 'test_create', :estimated_hours => '1:30')
2123 :subject => 'test_create', :estimated_hours => '1:30')
2107 with_settings :notified_events => [] do
2124 with_settings :notified_events => [] do
2108 assert issue.save
2125 assert issue.save
2109 assert_equal 0, ActionMailer::Base.deliveries.size
2126 assert_equal 0, ActionMailer::Base.deliveries.size
2110 end
2127 end
2111 end
2128 end
2112
2129
2113 def test_update_should_notify_previous_assignee
2130 def test_update_should_notify_previous_assignee
2114 ActionMailer::Base.deliveries.clear
2131 ActionMailer::Base.deliveries.clear
2115 user = User.find(3)
2132 user = User.find(3)
2116 user.members.update_all ["mail_notification = ?", false]
2133 user.members.update_all ["mail_notification = ?", false]
2117 user.update_attribute :mail_notification, 'only_assigned'
2134 user.update_attribute :mail_notification, 'only_assigned'
2118
2135
2119 with_settings :notified_events => %w(issue_updated) do
2136 with_settings :notified_events => %w(issue_updated) do
2120 issue = Issue.find(2)
2137 issue = Issue.find(2)
2121 issue.init_journal User.find(1)
2138 issue.init_journal User.find(1)
2122 issue.assigned_to = nil
2139 issue.assigned_to = nil
2123 issue.save!
2140 issue.save!
2124 assert_include user.mail, ActionMailer::Base.deliveries.last.bcc
2141 assert_include user.mail, ActionMailer::Base.deliveries.last.bcc
2125 end
2142 end
2126 end
2143 end
2127
2144
2128 def test_stale_issue_should_not_send_email_notification
2145 def test_stale_issue_should_not_send_email_notification
2129 ActionMailer::Base.deliveries.clear
2146 ActionMailer::Base.deliveries.clear
2130 issue = Issue.find(1)
2147 issue = Issue.find(1)
2131 stale = Issue.find(1)
2148 stale = Issue.find(1)
2132
2149
2133 issue.init_journal(User.find(1))
2150 issue.init_journal(User.find(1))
2134 issue.subject = 'Subjet update'
2151 issue.subject = 'Subjet update'
2135 with_settings :notified_events => %w(issue_updated) do
2152 with_settings :notified_events => %w(issue_updated) do
2136 assert issue.save
2153 assert issue.save
2137 assert_equal 1, ActionMailer::Base.deliveries.size
2154 assert_equal 1, ActionMailer::Base.deliveries.size
2138 ActionMailer::Base.deliveries.clear
2155 ActionMailer::Base.deliveries.clear
2139
2156
2140 stale.init_journal(User.find(1))
2157 stale.init_journal(User.find(1))
2141 stale.subject = 'Another subjet update'
2158 stale.subject = 'Another subjet update'
2142 assert_raise ActiveRecord::StaleObjectError do
2159 assert_raise ActiveRecord::StaleObjectError do
2143 stale.save
2160 stale.save
2144 end
2161 end
2145 assert ActionMailer::Base.deliveries.empty?
2162 assert ActionMailer::Base.deliveries.empty?
2146 end
2163 end
2147 end
2164 end
2148
2165
2149 def test_journalized_description
2166 def test_journalized_description
2150 IssueCustomField.delete_all
2167 IssueCustomField.delete_all
2151
2168
2152 i = Issue.first
2169 i = Issue.first
2153 old_description = i.description
2170 old_description = i.description
2154 new_description = "This is the new description"
2171 new_description = "This is the new description"
2155
2172
2156 i.init_journal(User.find(2))
2173 i.init_journal(User.find(2))
2157 i.description = new_description
2174 i.description = new_description
2158 assert_difference 'Journal.count', 1 do
2175 assert_difference 'Journal.count', 1 do
2159 assert_difference 'JournalDetail.count', 1 do
2176 assert_difference 'JournalDetail.count', 1 do
2160 i.save!
2177 i.save!
2161 end
2178 end
2162 end
2179 end
2163
2180
2164 detail = JournalDetail.order('id DESC').first
2181 detail = JournalDetail.order('id DESC').first
2165 assert_equal i, detail.journal.journalized
2182 assert_equal i, detail.journal.journalized
2166 assert_equal 'attr', detail.property
2183 assert_equal 'attr', detail.property
2167 assert_equal 'description', detail.prop_key
2184 assert_equal 'description', detail.prop_key
2168 assert_equal old_description, detail.old_value
2185 assert_equal old_description, detail.old_value
2169 assert_equal new_description, detail.value
2186 assert_equal new_description, detail.value
2170 end
2187 end
2171
2188
2172 def test_blank_descriptions_should_not_be_journalized
2189 def test_blank_descriptions_should_not_be_journalized
2173 IssueCustomField.delete_all
2190 IssueCustomField.delete_all
2174 Issue.where(:id => 1).update_all("description = NULL")
2191 Issue.where(:id => 1).update_all("description = NULL")
2175
2192
2176 i = Issue.find(1)
2193 i = Issue.find(1)
2177 i.init_journal(User.find(2))
2194 i.init_journal(User.find(2))
2178 i.subject = "blank description"
2195 i.subject = "blank description"
2179 i.description = "\r\n"
2196 i.description = "\r\n"
2180
2197
2181 assert_difference 'Journal.count', 1 do
2198 assert_difference 'Journal.count', 1 do
2182 assert_difference 'JournalDetail.count', 1 do
2199 assert_difference 'JournalDetail.count', 1 do
2183 i.save!
2200 i.save!
2184 end
2201 end
2185 end
2202 end
2186 end
2203 end
2187
2204
2188 def test_journalized_multi_custom_field
2205 def test_journalized_multi_custom_field
2189 field = IssueCustomField.create!(:name => 'filter', :field_format => 'list',
2206 field = IssueCustomField.create!(:name => 'filter', :field_format => 'list',
2190 :is_filter => true, :is_for_all => true,
2207 :is_filter => true, :is_for_all => true,
2191 :tracker_ids => [1],
2208 :tracker_ids => [1],
2192 :possible_values => ['value1', 'value2', 'value3'],
2209 :possible_values => ['value1', 'value2', 'value3'],
2193 :multiple => true)
2210 :multiple => true)
2194
2211
2195 issue = Issue.create!(:project_id => 1, :tracker_id => 1,
2212 issue = Issue.create!(:project_id => 1, :tracker_id => 1,
2196 :subject => 'Test', :author_id => 1)
2213 :subject => 'Test', :author_id => 1)
2197
2214
2198 assert_difference 'Journal.count' do
2215 assert_difference 'Journal.count' do
2199 assert_difference 'JournalDetail.count' do
2216 assert_difference 'JournalDetail.count' do
2200 issue.init_journal(User.first)
2217 issue.init_journal(User.first)
2201 issue.custom_field_values = {field.id => ['value1']}
2218 issue.custom_field_values = {field.id => ['value1']}
2202 issue.save!
2219 issue.save!
2203 end
2220 end
2204 assert_difference 'JournalDetail.count' do
2221 assert_difference 'JournalDetail.count' do
2205 issue.init_journal(User.first)
2222 issue.init_journal(User.first)
2206 issue.custom_field_values = {field.id => ['value1', 'value2']}
2223 issue.custom_field_values = {field.id => ['value1', 'value2']}
2207 issue.save!
2224 issue.save!
2208 end
2225 end
2209 assert_difference 'JournalDetail.count', 2 do
2226 assert_difference 'JournalDetail.count', 2 do
2210 issue.init_journal(User.first)
2227 issue.init_journal(User.first)
2211 issue.custom_field_values = {field.id => ['value3', 'value2']}
2228 issue.custom_field_values = {field.id => ['value3', 'value2']}
2212 issue.save!
2229 issue.save!
2213 end
2230 end
2214 assert_difference 'JournalDetail.count', 2 do
2231 assert_difference 'JournalDetail.count', 2 do
2215 issue.init_journal(User.first)
2232 issue.init_journal(User.first)
2216 issue.custom_field_values = {field.id => nil}
2233 issue.custom_field_values = {field.id => nil}
2217 issue.save!
2234 issue.save!
2218 end
2235 end
2219 end
2236 end
2220 end
2237 end
2221
2238
2222 def test_description_eol_should_be_normalized
2239 def test_description_eol_should_be_normalized
2223 i = Issue.new(:description => "CR \r LF \n CRLF \r\n")
2240 i = Issue.new(:description => "CR \r LF \n CRLF \r\n")
2224 assert_equal "CR \r\n LF \r\n CRLF \r\n", i.description
2241 assert_equal "CR \r\n LF \r\n CRLF \r\n", i.description
2225 end
2242 end
2226
2243
2227 def test_saving_twice_should_not_duplicate_journal_details
2244 def test_saving_twice_should_not_duplicate_journal_details
2228 i = Issue.first
2245 i = Issue.first
2229 i.init_journal(User.find(2), 'Some notes')
2246 i.init_journal(User.find(2), 'Some notes')
2230 # initial changes
2247 # initial changes
2231 i.subject = 'New subject'
2248 i.subject = 'New subject'
2232 i.done_ratio = i.done_ratio + 10
2249 i.done_ratio = i.done_ratio + 10
2233 assert_difference 'Journal.count' do
2250 assert_difference 'Journal.count' do
2234 assert i.save
2251 assert i.save
2235 end
2252 end
2236 # 1 more change
2253 # 1 more change
2237 i.priority = IssuePriority.where("id <> ?", i.priority_id).first
2254 i.priority = IssuePriority.where("id <> ?", i.priority_id).first
2238 assert_no_difference 'Journal.count' do
2255 assert_no_difference 'Journal.count' do
2239 assert_difference 'JournalDetail.count', 1 do
2256 assert_difference 'JournalDetail.count', 1 do
2240 i.save
2257 i.save
2241 end
2258 end
2242 end
2259 end
2243 # no more change
2260 # no more change
2244 assert_no_difference 'Journal.count' do
2261 assert_no_difference 'Journal.count' do
2245 assert_no_difference 'JournalDetail.count' do
2262 assert_no_difference 'JournalDetail.count' do
2246 i.save
2263 i.save
2247 end
2264 end
2248 end
2265 end
2249 end
2266 end
2250
2267
2251 test "#done_ratio should use the issue_status according to Setting.issue_done_ratio" do
2268 test "#done_ratio should use the issue_status according to Setting.issue_done_ratio" do
2252 @issue = Issue.find(1)
2269 @issue = Issue.find(1)
2253 @issue_status = IssueStatus.find(1)
2270 @issue_status = IssueStatus.find(1)
2254 @issue_status.update_attribute(:default_done_ratio, 50)
2271 @issue_status.update_attribute(:default_done_ratio, 50)
2255 @issue2 = Issue.find(2)
2272 @issue2 = Issue.find(2)
2256 @issue_status2 = IssueStatus.find(2)
2273 @issue_status2 = IssueStatus.find(2)
2257 @issue_status2.update_attribute(:default_done_ratio, 0)
2274 @issue_status2.update_attribute(:default_done_ratio, 0)
2258
2275
2259 with_settings :issue_done_ratio => 'issue_field' do
2276 with_settings :issue_done_ratio => 'issue_field' do
2260 assert_equal 0, @issue.done_ratio
2277 assert_equal 0, @issue.done_ratio
2261 assert_equal 30, @issue2.done_ratio
2278 assert_equal 30, @issue2.done_ratio
2262 end
2279 end
2263
2280
2264 with_settings :issue_done_ratio => 'issue_status' do
2281 with_settings :issue_done_ratio => 'issue_status' do
2265 assert_equal 50, @issue.done_ratio
2282 assert_equal 50, @issue.done_ratio
2266 assert_equal 0, @issue2.done_ratio
2283 assert_equal 0, @issue2.done_ratio
2267 end
2284 end
2268 end
2285 end
2269
2286
2270 test "#update_done_ratio_from_issue_status should update done_ratio according to Setting.issue_done_ratio" do
2287 test "#update_done_ratio_from_issue_status should update done_ratio according to Setting.issue_done_ratio" do
2271 @issue = Issue.find(1)
2288 @issue = Issue.find(1)
2272 @issue_status = IssueStatus.find(1)
2289 @issue_status = IssueStatus.find(1)
2273 @issue_status.update_attribute(:default_done_ratio, 50)
2290 @issue_status.update_attribute(:default_done_ratio, 50)
2274 @issue2 = Issue.find(2)
2291 @issue2 = Issue.find(2)
2275 @issue_status2 = IssueStatus.find(2)
2292 @issue_status2 = IssueStatus.find(2)
2276 @issue_status2.update_attribute(:default_done_ratio, 0)
2293 @issue_status2.update_attribute(:default_done_ratio, 0)
2277
2294
2278 with_settings :issue_done_ratio => 'issue_field' do
2295 with_settings :issue_done_ratio => 'issue_field' do
2279 @issue.update_done_ratio_from_issue_status
2296 @issue.update_done_ratio_from_issue_status
2280 @issue2.update_done_ratio_from_issue_status
2297 @issue2.update_done_ratio_from_issue_status
2281
2298
2282 assert_equal 0, @issue.read_attribute(:done_ratio)
2299 assert_equal 0, @issue.read_attribute(:done_ratio)
2283 assert_equal 30, @issue2.read_attribute(:done_ratio)
2300 assert_equal 30, @issue2.read_attribute(:done_ratio)
2284 end
2301 end
2285
2302
2286 with_settings :issue_done_ratio => 'issue_status' do
2303 with_settings :issue_done_ratio => 'issue_status' do
2287 @issue.update_done_ratio_from_issue_status
2304 @issue.update_done_ratio_from_issue_status
2288 @issue2.update_done_ratio_from_issue_status
2305 @issue2.update_done_ratio_from_issue_status
2289
2306
2290 assert_equal 50, @issue.read_attribute(:done_ratio)
2307 assert_equal 50, @issue.read_attribute(:done_ratio)
2291 assert_equal 0, @issue2.read_attribute(:done_ratio)
2308 assert_equal 0, @issue2.read_attribute(:done_ratio)
2292 end
2309 end
2293 end
2310 end
2294
2311
2295 test "#by_tracker" do
2312 test "#by_tracker" do
2296 User.current = User.anonymous
2313 User.current = User.anonymous
2297 groups = Issue.by_tracker(Project.find(1))
2314 groups = Issue.by_tracker(Project.find(1))
2298 assert_equal 3, groups.count
2315 assert_equal 3, groups.count
2299 assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i}
2316 assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i}
2300 end
2317 end
2301
2318
2302 test "#by_version" do
2319 test "#by_version" do
2303 User.current = User.anonymous
2320 User.current = User.anonymous
2304 groups = Issue.by_version(Project.find(1))
2321 groups = Issue.by_version(Project.find(1))
2305 assert_equal 3, groups.count
2322 assert_equal 3, groups.count
2306 assert_equal 3, groups.inject(0) {|sum, group| sum + group['total'].to_i}
2323 assert_equal 3, groups.inject(0) {|sum, group| sum + group['total'].to_i}
2307 end
2324 end
2308
2325
2309 test "#by_priority" do
2326 test "#by_priority" do
2310 User.current = User.anonymous
2327 User.current = User.anonymous
2311 groups = Issue.by_priority(Project.find(1))
2328 groups = Issue.by_priority(Project.find(1))
2312 assert_equal 4, groups.count
2329 assert_equal 4, groups.count
2313 assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i}
2330 assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i}
2314 end
2331 end
2315
2332
2316 test "#by_category" do
2333 test "#by_category" do
2317 User.current = User.anonymous
2334 User.current = User.anonymous
2318 groups = Issue.by_category(Project.find(1))
2335 groups = Issue.by_category(Project.find(1))
2319 assert_equal 2, groups.count
2336 assert_equal 2, groups.count
2320 assert_equal 3, groups.inject(0) {|sum, group| sum + group['total'].to_i}
2337 assert_equal 3, groups.inject(0) {|sum, group| sum + group['total'].to_i}
2321 end
2338 end
2322
2339
2323 test "#by_assigned_to" do
2340 test "#by_assigned_to" do
2324 User.current = User.anonymous
2341 User.current = User.anonymous
2325 groups = Issue.by_assigned_to(Project.find(1))
2342 groups = Issue.by_assigned_to(Project.find(1))
2326 assert_equal 2, groups.count
2343 assert_equal 2, groups.count
2327 assert_equal 2, groups.inject(0) {|sum, group| sum + group['total'].to_i}
2344 assert_equal 2, groups.inject(0) {|sum, group| sum + group['total'].to_i}
2328 end
2345 end
2329
2346
2330 test "#by_author" do
2347 test "#by_author" do
2331 User.current = User.anonymous
2348 User.current = User.anonymous
2332 groups = Issue.by_author(Project.find(1))
2349 groups = Issue.by_author(Project.find(1))
2333 assert_equal 4, groups.count
2350 assert_equal 4, groups.count
2334 assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i}
2351 assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i}
2335 end
2352 end
2336
2353
2337 test "#by_subproject" do
2354 test "#by_subproject" do
2338 User.current = User.anonymous
2355 User.current = User.anonymous
2339 groups = Issue.by_subproject(Project.find(1))
2356 groups = Issue.by_subproject(Project.find(1))
2340 # Private descendant not visible
2357 # Private descendant not visible
2341 assert_equal 1, groups.count
2358 assert_equal 1, groups.count
2342 assert_equal 2, groups.inject(0) {|sum, group| sum + group['total'].to_i}
2359 assert_equal 2, groups.inject(0) {|sum, group| sum + group['total'].to_i}
2343 end
2360 end
2344
2361
2345 def test_recently_updated_scope
2362 def test_recently_updated_scope
2346 #should return the last updated issue
2363 #should return the last updated issue
2347 assert_equal Issue.reorder("updated_on DESC").first, Issue.recently_updated.limit(1).first
2364 assert_equal Issue.reorder("updated_on DESC").first, Issue.recently_updated.limit(1).first
2348 end
2365 end
2349
2366
2350 def test_on_active_projects_scope
2367 def test_on_active_projects_scope
2351 assert Project.find(2).archive
2368 assert Project.find(2).archive
2352
2369
2353 before = Issue.on_active_project.length
2370 before = Issue.on_active_project.length
2354 # test inclusion to results
2371 # test inclusion to results
2355 issue = Issue.generate!(:tracker => Project.find(2).trackers.first)
2372 issue = Issue.generate!(:tracker => Project.find(2).trackers.first)
2356 assert_equal before + 1, Issue.on_active_project.length
2373 assert_equal before + 1, Issue.on_active_project.length
2357
2374
2358 # Move to an archived project
2375 # Move to an archived project
2359 issue.project = Project.find(2)
2376 issue.project = Project.find(2)
2360 assert issue.save
2377 assert issue.save
2361 assert_equal before, Issue.on_active_project.length
2378 assert_equal before, Issue.on_active_project.length
2362 end
2379 end
2363
2380
2364 test "Issue#recipients should include project recipients" do
2381 test "Issue#recipients should include project recipients" do
2365 issue = Issue.generate!
2382 issue = Issue.generate!
2366 assert issue.project.recipients.present?
2383 assert issue.project.recipients.present?
2367 issue.project.recipients.each do |project_recipient|
2384 issue.project.recipients.each do |project_recipient|
2368 assert issue.recipients.include?(project_recipient)
2385 assert issue.recipients.include?(project_recipient)
2369 end
2386 end
2370 end
2387 end
2371
2388
2372 test "Issue#recipients should include the author if the author is active" do
2389 test "Issue#recipients should include the author if the author is active" do
2373 issue = Issue.generate!(:author => User.generate!)
2390 issue = Issue.generate!(:author => User.generate!)
2374 assert issue.author, "No author set for Issue"
2391 assert issue.author, "No author set for Issue"
2375 assert issue.recipients.include?(issue.author.mail)
2392 assert issue.recipients.include?(issue.author.mail)
2376 end
2393 end
2377
2394
2378 test "Issue#recipients should include the assigned to user if the assigned to user is active" do
2395 test "Issue#recipients should include the assigned to user if the assigned to user is active" do
2379 issue = Issue.generate!(:assigned_to => User.generate!)
2396 issue = Issue.generate!(:assigned_to => User.generate!)
2380 assert issue.assigned_to, "No assigned_to set for Issue"
2397 assert issue.assigned_to, "No assigned_to set for Issue"
2381 assert issue.recipients.include?(issue.assigned_to.mail)
2398 assert issue.recipients.include?(issue.assigned_to.mail)
2382 end
2399 end
2383
2400
2384 test "Issue#recipients should not include users who opt out of all email" do
2401 test "Issue#recipients should not include users who opt out of all email" do
2385 issue = Issue.generate!(:author => User.generate!)
2402 issue = Issue.generate!(:author => User.generate!)
2386 issue.author.update_attribute(:mail_notification, :none)
2403 issue.author.update_attribute(:mail_notification, :none)
2387 assert !issue.recipients.include?(issue.author.mail)
2404 assert !issue.recipients.include?(issue.author.mail)
2388 end
2405 end
2389
2406
2390 test "Issue#recipients should not include the issue author if they are only notified of assigned issues" do
2407 test "Issue#recipients should not include the issue author if they are only notified of assigned issues" do
2391 issue = Issue.generate!(:author => User.generate!)
2408 issue = Issue.generate!(:author => User.generate!)
2392 issue.author.update_attribute(:mail_notification, :only_assigned)
2409 issue.author.update_attribute(:mail_notification, :only_assigned)
2393 assert !issue.recipients.include?(issue.author.mail)
2410 assert !issue.recipients.include?(issue.author.mail)
2394 end
2411 end
2395
2412
2396 test "Issue#recipients should not include the assigned user if they are only notified of owned issues" do
2413 test "Issue#recipients should not include the assigned user if they are only notified of owned issues" do
2397 issue = Issue.generate!(:assigned_to => User.generate!)
2414 issue = Issue.generate!(:assigned_to => User.generate!)
2398 issue.assigned_to.update_attribute(:mail_notification, :only_owner)
2415 issue.assigned_to.update_attribute(:mail_notification, :only_owner)
2399 assert !issue.recipients.include?(issue.assigned_to.mail)
2416 assert !issue.recipients.include?(issue.assigned_to.mail)
2400 end
2417 end
2401
2418
2402 def test_last_journal_id_with_journals_should_return_the_journal_id
2419 def test_last_journal_id_with_journals_should_return_the_journal_id
2403 assert_equal 2, Issue.find(1).last_journal_id
2420 assert_equal 2, Issue.find(1).last_journal_id
2404 end
2421 end
2405
2422
2406 def test_last_journal_id_without_journals_should_return_nil
2423 def test_last_journal_id_without_journals_should_return_nil
2407 assert_nil Issue.find(3).last_journal_id
2424 assert_nil Issue.find(3).last_journal_id
2408 end
2425 end
2409
2426
2410 def test_journals_after_should_return_journals_with_greater_id
2427 def test_journals_after_should_return_journals_with_greater_id
2411 assert_equal [Journal.find(2)], Issue.find(1).journals_after('1')
2428 assert_equal [Journal.find(2)], Issue.find(1).journals_after('1')
2412 assert_equal [], Issue.find(1).journals_after('2')
2429 assert_equal [], Issue.find(1).journals_after('2')
2413 end
2430 end
2414
2431
2415 def test_journals_after_with_blank_arg_should_return_all_journals
2432 def test_journals_after_with_blank_arg_should_return_all_journals
2416 assert_equal [Journal.find(1), Journal.find(2)], Issue.find(1).journals_after('')
2433 assert_equal [Journal.find(1), Journal.find(2)], Issue.find(1).journals_after('')
2417 end
2434 end
2418
2435
2419 def test_css_classes_should_include_tracker
2436 def test_css_classes_should_include_tracker
2420 issue = Issue.new(:tracker => Tracker.find(2))
2437 issue = Issue.new(:tracker => Tracker.find(2))
2421 classes = issue.css_classes.split(' ')
2438 classes = issue.css_classes.split(' ')
2422 assert_include 'tracker-2', classes
2439 assert_include 'tracker-2', classes
2423 end
2440 end
2424
2441
2425 def test_css_classes_should_include_priority
2442 def test_css_classes_should_include_priority
2426 issue = Issue.new(:priority => IssuePriority.find(8))
2443 issue = Issue.new(:priority => IssuePriority.find(8))
2427 classes = issue.css_classes.split(' ')
2444 classes = issue.css_classes.split(' ')
2428 assert_include 'priority-8', classes
2445 assert_include 'priority-8', classes
2429 assert_include 'priority-highest', classes
2446 assert_include 'priority-highest', classes
2430 end
2447 end
2431
2448
2432 def test_css_classes_should_include_user_and_group_assignment
2449 def test_css_classes_should_include_user_and_group_assignment
2433 project = Project.first
2450 project = Project.first
2434 user = User.generate!
2451 user = User.generate!
2435 group = Group.generate!
2452 group = Group.generate!
2436 Member.create!(:principal => group, :project => project, :role_ids => [1, 2])
2453 Member.create!(:principal => group, :project => project, :role_ids => [1, 2])
2437 group.users << user
2454 group.users << user
2438 assert user.member_of?(project)
2455 assert user.member_of?(project)
2439 issue1 = Issue.generate(:assigned_to_id => group.id)
2456 issue1 = Issue.generate(:assigned_to_id => group.id)
2440 assert_include 'assigned-to-my-group', issue1.css_classes(user)
2457 assert_include 'assigned-to-my-group', issue1.css_classes(user)
2441 assert_not_include 'assigned-to-me', issue1.css_classes(user)
2458 assert_not_include 'assigned-to-me', issue1.css_classes(user)
2442 issue2 = Issue.generate(:assigned_to_id => user.id)
2459 issue2 = Issue.generate(:assigned_to_id => user.id)
2443 assert_not_include 'assigned-to-my-group', issue2.css_classes(user)
2460 assert_not_include 'assigned-to-my-group', issue2.css_classes(user)
2444 assert_include 'assigned-to-me', issue2.css_classes(user)
2461 assert_include 'assigned-to-me', issue2.css_classes(user)
2445 end
2462 end
2446
2463
2447 def test_save_attachments_with_hash_should_save_attachments_in_keys_order
2464 def test_save_attachments_with_hash_should_save_attachments_in_keys_order
2448 set_tmp_attachments_directory
2465 set_tmp_attachments_directory
2449 issue = Issue.generate!
2466 issue = Issue.generate!
2450 issue.save_attachments({
2467 issue.save_attachments({
2451 'p0' => {'file' => mock_file_with_options(:original_filename => 'upload')},
2468 'p0' => {'file' => mock_file_with_options(:original_filename => 'upload')},
2452 '3' => {'file' => mock_file_with_options(:original_filename => 'bar')},
2469 '3' => {'file' => mock_file_with_options(:original_filename => 'bar')},
2453 '1' => {'file' => mock_file_with_options(:original_filename => 'foo')}
2470 '1' => {'file' => mock_file_with_options(:original_filename => 'foo')}
2454 })
2471 })
2455 issue.attach_saved_attachments
2472 issue.attach_saved_attachments
2456
2473
2457 assert_equal 3, issue.reload.attachments.count
2474 assert_equal 3, issue.reload.attachments.count
2458 assert_equal %w(upload foo bar), issue.attachments.map(&:filename)
2475 assert_equal %w(upload foo bar), issue.attachments.map(&:filename)
2459 end
2476 end
2460
2477
2461 def test_closed_on_should_be_nil_when_creating_an_open_issue
2478 def test_closed_on_should_be_nil_when_creating_an_open_issue
2462 issue = Issue.generate!(:status_id => 1).reload
2479 issue = Issue.generate!(:status_id => 1).reload
2463 assert !issue.closed?
2480 assert !issue.closed?
2464 assert_nil issue.closed_on
2481 assert_nil issue.closed_on
2465 end
2482 end
2466
2483
2467 def test_closed_on_should_be_set_when_creating_a_closed_issue
2484 def test_closed_on_should_be_set_when_creating_a_closed_issue
2468 issue = Issue.generate!(:status_id => 5).reload
2485 issue = Issue.generate!(:status_id => 5).reload
2469 assert issue.closed?
2486 assert issue.closed?
2470 assert_not_nil issue.closed_on
2487 assert_not_nil issue.closed_on
2471 assert_equal issue.updated_on, issue.closed_on
2488 assert_equal issue.updated_on, issue.closed_on
2472 assert_equal issue.created_on, issue.closed_on
2489 assert_equal issue.created_on, issue.closed_on
2473 end
2490 end
2474
2491
2475 def test_closed_on_should_be_nil_when_updating_an_open_issue
2492 def test_closed_on_should_be_nil_when_updating_an_open_issue
2476 issue = Issue.find(1)
2493 issue = Issue.find(1)
2477 issue.subject = 'Not closed yet'
2494 issue.subject = 'Not closed yet'
2478 issue.save!
2495 issue.save!
2479 issue.reload
2496 issue.reload
2480 assert_nil issue.closed_on
2497 assert_nil issue.closed_on
2481 end
2498 end
2482
2499
2483 def test_closed_on_should_be_set_when_closing_an_open_issue
2500 def test_closed_on_should_be_set_when_closing_an_open_issue
2484 issue = Issue.find(1)
2501 issue = Issue.find(1)
2485 issue.subject = 'Now closed'
2502 issue.subject = 'Now closed'
2486 issue.status_id = 5
2503 issue.status_id = 5
2487 issue.save!
2504 issue.save!
2488 issue.reload
2505 issue.reload
2489 assert_not_nil issue.closed_on
2506 assert_not_nil issue.closed_on
2490 assert_equal issue.updated_on, issue.closed_on
2507 assert_equal issue.updated_on, issue.closed_on
2491 end
2508 end
2492
2509
2493 def test_closed_on_should_not_be_updated_when_updating_a_closed_issue
2510 def test_closed_on_should_not_be_updated_when_updating_a_closed_issue
2494 issue = Issue.open(false).first
2511 issue = Issue.open(false).first
2495 was_closed_on = issue.closed_on
2512 was_closed_on = issue.closed_on
2496 assert_not_nil was_closed_on
2513 assert_not_nil was_closed_on
2497 issue.subject = 'Updating a closed issue'
2514 issue.subject = 'Updating a closed issue'
2498 issue.save!
2515 issue.save!
2499 issue.reload
2516 issue.reload
2500 assert_equal was_closed_on, issue.closed_on
2517 assert_equal was_closed_on, issue.closed_on
2501 end
2518 end
2502
2519
2503 def test_closed_on_should_be_preserved_when_reopening_a_closed_issue
2520 def test_closed_on_should_be_preserved_when_reopening_a_closed_issue
2504 issue = Issue.open(false).first
2521 issue = Issue.open(false).first
2505 was_closed_on = issue.closed_on
2522 was_closed_on = issue.closed_on
2506 assert_not_nil was_closed_on
2523 assert_not_nil was_closed_on
2507 issue.subject = 'Reopening a closed issue'
2524 issue.subject = 'Reopening a closed issue'
2508 issue.status_id = 1
2525 issue.status_id = 1
2509 issue.save!
2526 issue.save!
2510 issue.reload
2527 issue.reload
2511 assert !issue.closed?
2528 assert !issue.closed?
2512 assert_equal was_closed_on, issue.closed_on
2529 assert_equal was_closed_on, issue.closed_on
2513 end
2530 end
2514
2531
2515 def test_status_was_should_return_nil_for_new_issue
2532 def test_status_was_should_return_nil_for_new_issue
2516 issue = Issue.new
2533 issue = Issue.new
2517 assert_nil issue.status_was
2534 assert_nil issue.status_was
2518 end
2535 end
2519
2536
2520 def test_status_was_should_return_status_before_change
2537 def test_status_was_should_return_status_before_change
2521 issue = Issue.find(1)
2538 issue = Issue.find(1)
2522 issue.status = IssueStatus.find(2)
2539 issue.status = IssueStatus.find(2)
2523 assert_equal IssueStatus.find(1), issue.status_was
2540 assert_equal IssueStatus.find(1), issue.status_was
2524 end
2541 end
2525
2542
2526 def test_status_was_should_return_status_before_change_with_status_id
2543 def test_status_was_should_return_status_before_change_with_status_id
2527 issue = Issue.find(1)
2544 issue = Issue.find(1)
2528 assert_equal IssueStatus.find(1), issue.status
2545 assert_equal IssueStatus.find(1), issue.status
2529 issue.status_id = 2
2546 issue.status_id = 2
2530 assert_equal IssueStatus.find(1), issue.status_was
2547 assert_equal IssueStatus.find(1), issue.status_was
2531 end
2548 end
2532
2549
2533 def test_status_was_should_be_reset_on_save
2550 def test_status_was_should_be_reset_on_save
2534 issue = Issue.find(1)
2551 issue = Issue.find(1)
2535 issue.status = IssueStatus.find(2)
2552 issue.status = IssueStatus.find(2)
2536 assert_equal IssueStatus.find(1), issue.status_was
2553 assert_equal IssueStatus.find(1), issue.status_was
2537 assert issue.save!
2554 assert issue.save!
2538 assert_equal IssueStatus.find(2), issue.status_was
2555 assert_equal IssueStatus.find(2), issue.status_was
2539 end
2556 end
2540
2557
2541 def test_closing_should_return_true_when_closing_an_issue
2558 def test_closing_should_return_true_when_closing_an_issue
2542 issue = Issue.find(1)
2559 issue = Issue.find(1)
2543 issue.status = IssueStatus.find(2)
2560 issue.status = IssueStatus.find(2)
2544 assert_equal false, issue.closing?
2561 assert_equal false, issue.closing?
2545 issue.status = IssueStatus.find(5)
2562 issue.status = IssueStatus.find(5)
2546 assert_equal true, issue.closing?
2563 assert_equal true, issue.closing?
2547 end
2564 end
2548
2565
2549 def test_closing_should_return_true_when_closing_an_issue_with_status_id
2566 def test_closing_should_return_true_when_closing_an_issue_with_status_id
2550 issue = Issue.find(1)
2567 issue = Issue.find(1)
2551 issue.status_id = 2
2568 issue.status_id = 2
2552 assert_equal false, issue.closing?
2569 assert_equal false, issue.closing?
2553 issue.status_id = 5
2570 issue.status_id = 5
2554 assert_equal true, issue.closing?
2571 assert_equal true, issue.closing?
2555 end
2572 end
2556
2573
2557 def test_closing_should_return_true_for_new_closed_issue
2574 def test_closing_should_return_true_for_new_closed_issue
2558 issue = Issue.new
2575 issue = Issue.new
2559 assert_equal false, issue.closing?
2576 assert_equal false, issue.closing?
2560 issue.status = IssueStatus.find(5)
2577 issue.status = IssueStatus.find(5)
2561 assert_equal true, issue.closing?
2578 assert_equal true, issue.closing?
2562 end
2579 end
2563
2580
2564 def test_closing_should_return_true_for_new_closed_issue_with_status_id
2581 def test_closing_should_return_true_for_new_closed_issue_with_status_id
2565 issue = Issue.new
2582 issue = Issue.new
2566 assert_equal false, issue.closing?
2583 assert_equal false, issue.closing?
2567 issue.status_id = 5
2584 issue.status_id = 5
2568 assert_equal true, issue.closing?
2585 assert_equal true, issue.closing?
2569 end
2586 end
2570
2587
2571 def test_closing_should_be_reset_after_save
2588 def test_closing_should_be_reset_after_save
2572 issue = Issue.find(1)
2589 issue = Issue.find(1)
2573 issue.status_id = 5
2590 issue.status_id = 5
2574 assert_equal true, issue.closing?
2591 assert_equal true, issue.closing?
2575 issue.save!
2592 issue.save!
2576 assert_equal false, issue.closing?
2593 assert_equal false, issue.closing?
2577 end
2594 end
2578
2595
2579 def test_reopening_should_return_true_when_reopening_an_issue
2596 def test_reopening_should_return_true_when_reopening_an_issue
2580 issue = Issue.find(8)
2597 issue = Issue.find(8)
2581 issue.status = IssueStatus.find(6)
2598 issue.status = IssueStatus.find(6)
2582 assert_equal false, issue.reopening?
2599 assert_equal false, issue.reopening?
2583 issue.status = IssueStatus.find(2)
2600 issue.status = IssueStatus.find(2)
2584 assert_equal true, issue.reopening?
2601 assert_equal true, issue.reopening?
2585 end
2602 end
2586
2603
2587 def test_reopening_should_return_true_when_reopening_an_issue_with_status_id
2604 def test_reopening_should_return_true_when_reopening_an_issue_with_status_id
2588 issue = Issue.find(8)
2605 issue = Issue.find(8)
2589 issue.status_id = 6
2606 issue.status_id = 6
2590 assert_equal false, issue.reopening?
2607 assert_equal false, issue.reopening?
2591 issue.status_id = 2
2608 issue.status_id = 2
2592 assert_equal true, issue.reopening?
2609 assert_equal true, issue.reopening?
2593 end
2610 end
2594
2611
2595 def test_reopening_should_return_false_for_new_open_issue
2612 def test_reopening_should_return_false_for_new_open_issue
2596 issue = Issue.new
2613 issue = Issue.new
2597 issue.status = IssueStatus.find(1)
2614 issue.status = IssueStatus.find(1)
2598 assert_equal false, issue.reopening?
2615 assert_equal false, issue.reopening?
2599 end
2616 end
2600
2617
2601 def test_reopening_should_be_reset_after_save
2618 def test_reopening_should_be_reset_after_save
2602 issue = Issue.find(8)
2619 issue = Issue.find(8)
2603 issue.status_id = 2
2620 issue.status_id = 2
2604 assert_equal true, issue.reopening?
2621 assert_equal true, issue.reopening?
2605 issue.save!
2622 issue.save!
2606 assert_equal false, issue.reopening?
2623 assert_equal false, issue.reopening?
2607 end
2624 end
2608
2625
2609 def test_default_status_without_tracker_should_be_nil
2626 def test_default_status_without_tracker_should_be_nil
2610 issue = Issue.new
2627 issue = Issue.new
2611 assert_nil issue.tracker
2628 assert_nil issue.tracker
2612 assert_nil issue.default_status
2629 assert_nil issue.default_status
2613 end
2630 end
2614
2631
2615 def test_default_status_should_be_tracker_default_status
2632 def test_default_status_should_be_tracker_default_status
2616 issue = Issue.new(:tracker_id => 1)
2633 issue = Issue.new(:tracker_id => 1)
2617 assert_not_nil issue.status
2634 assert_not_nil issue.status
2618 assert_equal issue.tracker.default_status, issue.default_status
2635 assert_equal issue.tracker.default_status, issue.default_status
2619 end
2636 end
2620
2637
2621 def test_initializing_with_tracker_should_set_default_status
2638 def test_initializing_with_tracker_should_set_default_status
2622 issue = Issue.new(:tracker => Tracker.find(1))
2639 issue = Issue.new(:tracker => Tracker.find(1))
2623 assert_not_nil issue.status
2640 assert_not_nil issue.status
2624 assert_equal issue.default_status, issue.status
2641 assert_equal issue.default_status, issue.status
2625 end
2642 end
2626
2643
2627 def test_initializing_with_tracker_id_should_set_default_status
2644 def test_initializing_with_tracker_id_should_set_default_status
2628 issue = Issue.new(:tracker_id => 1)
2645 issue = Issue.new(:tracker_id => 1)
2629 assert_not_nil issue.status
2646 assert_not_nil issue.status
2630 assert_equal issue.default_status, issue.status
2647 assert_equal issue.default_status, issue.status
2631 end
2648 end
2632
2649
2633 def test_setting_tracker_should_set_default_status
2650 def test_setting_tracker_should_set_default_status
2634 issue = Issue.new
2651 issue = Issue.new
2635 issue.tracker = Tracker.find(1)
2652 issue.tracker = Tracker.find(1)
2636 assert_not_nil issue.status
2653 assert_not_nil issue.status
2637 assert_equal issue.default_status, issue.status
2654 assert_equal issue.default_status, issue.status
2638 end
2655 end
2639
2656
2640 def test_changing_tracker_should_set_default_status_if_status_was_default
2657 def test_changing_tracker_should_set_default_status_if_status_was_default
2641 WorkflowTransition.delete_all
2658 WorkflowTransition.delete_all
2642 WorkflowTransition.create! :role_id => 1, :tracker_id => 2, :old_status_id => 2, :new_status_id => 1
2659 WorkflowTransition.create! :role_id => 1, :tracker_id => 2, :old_status_id => 2, :new_status_id => 1
2643 Tracker.find(2).update! :default_status_id => 2
2660 Tracker.find(2).update! :default_status_id => 2
2644
2661
2645 issue = Issue.new(:tracker_id => 1, :status_id => 1)
2662 issue = Issue.new(:tracker_id => 1, :status_id => 1)
2646 assert_equal IssueStatus.find(1), issue.status
2663 assert_equal IssueStatus.find(1), issue.status
2647 issue.tracker = Tracker.find(2)
2664 issue.tracker = Tracker.find(2)
2648 assert_equal IssueStatus.find(2), issue.status
2665 assert_equal IssueStatus.find(2), issue.status
2649 end
2666 end
2650
2667
2651 def test_changing_tracker_should_set_default_status_if_status_is_not_used_by_tracker
2668 def test_changing_tracker_should_set_default_status_if_status_is_not_used_by_tracker
2652 WorkflowTransition.delete_all
2669 WorkflowTransition.delete_all
2653 Tracker.find(2).update! :default_status_id => 2
2670 Tracker.find(2).update! :default_status_id => 2
2654
2671
2655 issue = Issue.new(:tracker_id => 1, :status_id => 3)
2672 issue = Issue.new(:tracker_id => 1, :status_id => 3)
2656 assert_equal IssueStatus.find(3), issue.status
2673 assert_equal IssueStatus.find(3), issue.status
2657 issue.tracker = Tracker.find(2)
2674 issue.tracker = Tracker.find(2)
2658 assert_equal IssueStatus.find(2), issue.status
2675 assert_equal IssueStatus.find(2), issue.status
2659 end
2676 end
2660
2677
2661 def test_changing_tracker_should_keep_status_if_status_was_not_default_and_is_used_by_tracker
2678 def test_changing_tracker_should_keep_status_if_status_was_not_default_and_is_used_by_tracker
2662 WorkflowTransition.delete_all
2679 WorkflowTransition.delete_all
2663 WorkflowTransition.create! :role_id => 1, :tracker_id => 2, :old_status_id => 2, :new_status_id => 3
2680 WorkflowTransition.create! :role_id => 1, :tracker_id => 2, :old_status_id => 2, :new_status_id => 3
2664 Tracker.find(2).update! :default_status_id => 2
2681 Tracker.find(2).update! :default_status_id => 2
2665
2682
2666 issue = Issue.new(:tracker_id => 1, :status_id => 3)
2683 issue = Issue.new(:tracker_id => 1, :status_id => 3)
2667 assert_equal IssueStatus.find(3), issue.status
2684 assert_equal IssueStatus.find(3), issue.status
2668 issue.tracker = Tracker.find(2)
2685 issue.tracker = Tracker.find(2)
2669 assert_equal IssueStatus.find(3), issue.status
2686 assert_equal IssueStatus.find(3), issue.status
2670 end
2687 end
2671
2688
2672 def test_assigned_to_was_with_a_group
2689 def test_assigned_to_was_with_a_group
2673 group = Group.find(10)
2690 group = Group.find(10)
2674
2691
2675 issue = Issue.generate!(:assigned_to => group)
2692 issue = Issue.generate!(:assigned_to => group)
2676 issue.reload.assigned_to = nil
2693 issue.reload.assigned_to = nil
2677 assert_equal group, issue.assigned_to_was
2694 assert_equal group, issue.assigned_to_was
2678 end
2695 end
2679 end
2696 end
General Comments 0
You need to be logged in to leave comments. Login now