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