comparison test/unit/issue_test.rb @ 524:1248a47e81b3 feature_36

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