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