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