##// END OF EJS Templates
Removed shoulda assertions....
Jean-Philippe Lang -
r8968:80663e694dc2
parent child
Show More
@@ -1,1179 +1,1150
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2011 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 ProjectTest < ActiveSupport::TestCase
21 21 fixtures :projects, :trackers, :issue_statuses, :issues,
22 22 :journals, :journal_details,
23 23 :enumerations, :users, :issue_categories,
24 24 :projects_trackers,
25 25 :custom_fields,
26 26 :custom_fields_projects,
27 27 :custom_fields_trackers,
28 28 :custom_values,
29 29 :roles,
30 30 :member_roles,
31 31 :members,
32 32 :enabled_modules,
33 33 :workflows,
34 34 :versions,
35 35 :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions,
36 36 :groups_users,
37 37 :boards,
38 38 :repositories
39 39
40 40 def setup
41 41 @ecookbook = Project.find(1)
42 42 @ecookbook_sub1 = Project.find(3)
43 43 set_tmp_attachments_directory
44 44 User.current = nil
45 45 end
46 46
47 should_validate_presence_of :name
48 should_validate_presence_of :identifier
49
50 should_validate_uniqueness_of :identifier
51
52 context "associations" do
53 should_have_many :members
54 should_have_many :users, :through => :members
55 should_have_many :member_principals
56 should_have_many :principals, :through => :member_principals
57 should_have_many :enabled_modules
58 should_have_many :issues
59 should_have_many :issue_changes, :through => :issues
60 should_have_many :versions
61 should_have_many :time_entries
62 should_have_many :queries
63 should_have_many :documents
64 should_have_many :news
65 should_have_many :issue_categories
66 should_have_many :boards
67 should_have_many :changesets, :through => :repository
68
69 should_have_one :repository
70 should_have_one :wiki
71
72 should_have_and_belong_to_many :trackers
73 should_have_and_belong_to_many :issue_custom_fields
74 end
75
76 47 def test_truth
77 48 assert_kind_of Project, @ecookbook
78 49 assert_equal "eCookbook", @ecookbook.name
79 50 end
80 51
81 52 def test_default_attributes
82 53 with_settings :default_projects_public => '1' do
83 54 assert_equal true, Project.new.is_public
84 55 assert_equal false, Project.new(:is_public => false).is_public
85 56 end
86 57
87 58 with_settings :default_projects_public => '0' do
88 59 assert_equal false, Project.new.is_public
89 60 assert_equal true, Project.new(:is_public => true).is_public
90 61 end
91 62
92 63 with_settings :sequential_project_identifiers => '1' do
93 64 assert !Project.new.identifier.blank?
94 65 assert Project.new(:identifier => '').identifier.blank?
95 66 end
96 67
97 68 with_settings :sequential_project_identifiers => '0' do
98 69 assert Project.new.identifier.blank?
99 70 assert !Project.new(:identifier => 'test').blank?
100 71 end
101 72
102 73 with_settings :default_projects_modules => ['issue_tracking', 'repository'] do
103 74 assert_equal ['issue_tracking', 'repository'], Project.new.enabled_module_names
104 75 end
105 76
106 77 assert_equal Tracker.all.sort, Project.new.trackers.sort
107 78 assert_equal Tracker.find(1, 3).sort, Project.new(:tracker_ids => [1, 3]).trackers.sort
108 79 end
109 80
110 81 def test_update
111 82 assert_equal "eCookbook", @ecookbook.name
112 83 @ecookbook.name = "eCook"
113 84 assert @ecookbook.save, @ecookbook.errors.full_messages.join("; ")
114 85 @ecookbook.reload
115 86 assert_equal "eCook", @ecookbook.name
116 87 end
117 88
118 89 def test_validate_identifier
119 90 to_test = {"abc" => true,
120 91 "ab12" => true,
121 92 "ab-12" => true,
122 93 "ab_12" => true,
123 94 "12" => false,
124 95 "new" => false}
125 96
126 97 to_test.each do |identifier, valid|
127 98 p = Project.new
128 99 p.identifier = identifier
129 100 p.valid?
130 101 if valid
131 102 assert p.errors['identifier'].blank?, "identifier #{identifier} was not valid"
132 103 else
133 104 assert p.errors['identifier'].present?, "identifier #{identifier} was valid"
134 105 end
135 106 end
136 107 end
137 108
138 109 def test_members_should_be_active_users
139 110 Project.all.each do |project|
140 111 assert_nil project.members.detect {|m| !(m.user.is_a?(User) && m.user.active?) }
141 112 end
142 113 end
143 114
144 115 def test_users_should_be_active_users
145 116 Project.all.each do |project|
146 117 assert_nil project.users.detect {|u| !(u.is_a?(User) && u.active?) }
147 118 end
148 119 end
149 120
150 121 def test_archive
151 122 user = @ecookbook.members.first.user
152 123 @ecookbook.archive
153 124 @ecookbook.reload
154 125
155 126 assert !@ecookbook.active?
156 127 assert @ecookbook.archived?
157 128 assert !user.projects.include?(@ecookbook)
158 129 # Subproject are also archived
159 130 assert !@ecookbook.children.empty?
160 131 assert @ecookbook.descendants.active.empty?
161 132 end
162 133
163 134 def test_archive_should_fail_if_versions_are_used_by_non_descendant_projects
164 135 # Assign an issue of a project to a version of a child project
165 136 Issue.find(4).update_attribute :fixed_version_id, 4
166 137
167 138 assert_no_difference "Project.count(:all, :conditions => 'status = #{Project::STATUS_ARCHIVED}')" do
168 139 assert_equal false, @ecookbook.archive
169 140 end
170 141 @ecookbook.reload
171 142 assert @ecookbook.active?
172 143 end
173 144
174 145 def test_unarchive
175 146 user = @ecookbook.members.first.user
176 147 @ecookbook.archive
177 148 # A subproject of an archived project can not be unarchived
178 149 assert !@ecookbook_sub1.unarchive
179 150
180 151 # Unarchive project
181 152 assert @ecookbook.unarchive
182 153 @ecookbook.reload
183 154 assert @ecookbook.active?
184 155 assert !@ecookbook.archived?
185 156 assert user.projects.include?(@ecookbook)
186 157 # Subproject can now be unarchived
187 158 @ecookbook_sub1.reload
188 159 assert @ecookbook_sub1.unarchive
189 160 end
190 161
191 162 def test_destroy
192 163 # 2 active members
193 164 assert_equal 2, @ecookbook.members.size
194 165 # and 1 is locked
195 166 assert_equal 3, Member.find(:all, :conditions => ['project_id = ?', @ecookbook.id]).size
196 167 # some boards
197 168 assert @ecookbook.boards.any?
198 169
199 170 @ecookbook.destroy
200 171 # make sure that the project non longer exists
201 172 assert_raise(ActiveRecord::RecordNotFound) { Project.find(@ecookbook.id) }
202 173 # make sure related data was removed
203 174 assert_nil Member.first(:conditions => {:project_id => @ecookbook.id})
204 175 assert_nil Board.first(:conditions => {:project_id => @ecookbook.id})
205 176 assert_nil Issue.first(:conditions => {:project_id => @ecookbook.id})
206 177 end
207 178
208 179 def test_destroying_root_projects_should_clear_data
209 180 Project.roots.each do |root|
210 181 root.destroy
211 182 end
212 183
213 184 assert_equal 0, Project.count, "Projects were not deleted: #{Project.all.inspect}"
214 185 assert_equal 0, Member.count, "Members were not deleted: #{Member.all.inspect}"
215 186 assert_equal 0, MemberRole.count
216 187 assert_equal 0, Issue.count
217 188 assert_equal 0, Journal.count
218 189 assert_equal 0, JournalDetail.count
219 190 assert_equal 0, Attachment.count
220 191 assert_equal 0, EnabledModule.count
221 192 assert_equal 0, IssueCategory.count
222 193 assert_equal 0, IssueRelation.count
223 194 assert_equal 0, Board.count
224 195 assert_equal 0, Message.count
225 196 assert_equal 0, News.count
226 197 assert_equal 0, Query.count(:conditions => "project_id IS NOT NULL")
227 198 assert_equal 0, Repository.count
228 199 assert_equal 0, Changeset.count
229 200 assert_equal 0, Change.count
230 201 assert_equal 0, Comment.count
231 202 assert_equal 0, TimeEntry.count
232 203 assert_equal 0, Version.count
233 204 assert_equal 0, Watcher.count
234 205 assert_equal 0, Wiki.count
235 206 assert_equal 0, WikiPage.count
236 207 assert_equal 0, WikiContent.count
237 208 assert_equal 0, WikiContent::Version.count
238 209 assert_equal 0, Project.connection.select_all("SELECT * FROM projects_trackers").size
239 210 assert_equal 0, Project.connection.select_all("SELECT * FROM custom_fields_projects").size
240 211 assert_equal 0, CustomValue.count(:conditions => {:customized_type => ['Project', 'Issue', 'TimeEntry', 'Version']})
241 212 end
242 213
243 214 def test_move_an_orphan_project_to_a_root_project
244 215 sub = Project.find(2)
245 216 sub.set_parent! @ecookbook
246 217 assert_equal @ecookbook.id, sub.parent.id
247 218 @ecookbook.reload
248 219 assert_equal 4, @ecookbook.children.size
249 220 end
250 221
251 222 def test_move_an_orphan_project_to_a_subproject
252 223 sub = Project.find(2)
253 224 assert sub.set_parent!(@ecookbook_sub1)
254 225 end
255 226
256 227 def test_move_a_root_project_to_a_project
257 228 sub = @ecookbook
258 229 assert sub.set_parent!(Project.find(2))
259 230 end
260 231
261 232 def test_should_not_move_a_project_to_its_children
262 233 sub = @ecookbook
263 234 assert !(sub.set_parent!(Project.find(3)))
264 235 end
265 236
266 237 def test_set_parent_should_add_roots_in_alphabetical_order
267 238 ProjectCustomField.delete_all
268 239 Project.delete_all
269 240 Project.create!(:name => 'Project C', :identifier => 'project-c').set_parent!(nil)
270 241 Project.create!(:name => 'Project B', :identifier => 'project-b').set_parent!(nil)
271 242 Project.create!(:name => 'Project D', :identifier => 'project-d').set_parent!(nil)
272 243 Project.create!(:name => 'Project A', :identifier => 'project-a').set_parent!(nil)
273 244
274 245 assert_equal 4, Project.count
275 246 assert_equal Project.all.sort_by(&:name), Project.all.sort_by(&:lft)
276 247 end
277 248
278 249 def test_set_parent_should_add_children_in_alphabetical_order
279 250 ProjectCustomField.delete_all
280 251 parent = Project.create!(:name => 'Parent', :identifier => 'parent')
281 252 Project.create!(:name => 'Project C', :identifier => 'project-c').set_parent!(parent)
282 253 Project.create!(:name => 'Project B', :identifier => 'project-b').set_parent!(parent)
283 254 Project.create!(:name => 'Project D', :identifier => 'project-d').set_parent!(parent)
284 255 Project.create!(:name => 'Project A', :identifier => 'project-a').set_parent!(parent)
285 256
286 257 parent.reload
287 258 assert_equal 4, parent.children.size
288 259 assert_equal parent.children.all.sort_by(&:name), parent.children.all
289 260 end
290 261
291 262 def test_rebuild_should_sort_children_alphabetically
292 263 ProjectCustomField.delete_all
293 264 parent = Project.create!(:name => 'Parent', :identifier => 'parent')
294 265 Project.create!(:name => 'Project C', :identifier => 'project-c').move_to_child_of(parent)
295 266 Project.create!(:name => 'Project B', :identifier => 'project-b').move_to_child_of(parent)
296 267 Project.create!(:name => 'Project D', :identifier => 'project-d').move_to_child_of(parent)
297 268 Project.create!(:name => 'Project A', :identifier => 'project-a').move_to_child_of(parent)
298 269
299 270 Project.update_all("lft = NULL, rgt = NULL")
300 271 Project.rebuild!
301 272
302 273 parent.reload
303 274 assert_equal 4, parent.children.size
304 275 assert_equal parent.children.all.sort_by(&:name), parent.children.all
305 276 end
306 277
307 278
308 279 def test_set_parent_should_update_issue_fixed_version_associations_when_a_fixed_version_is_moved_out_of_the_hierarchy
309 280 # Parent issue with a hierarchy project's fixed version
310 281 parent_issue = Issue.find(1)
311 282 parent_issue.update_attribute(:fixed_version_id, 4)
312 283 parent_issue.reload
313 284 assert_equal 4, parent_issue.fixed_version_id
314 285
315 286 # Should keep fixed versions for the issues
316 287 issue_with_local_fixed_version = Issue.find(5)
317 288 issue_with_local_fixed_version.update_attribute(:fixed_version_id, 4)
318 289 issue_with_local_fixed_version.reload
319 290 assert_equal 4, issue_with_local_fixed_version.fixed_version_id
320 291
321 292 # Local issue with hierarchy fixed_version
322 293 issue_with_hierarchy_fixed_version = Issue.find(13)
323 294 issue_with_hierarchy_fixed_version.update_attribute(:fixed_version_id, 6)
324 295 issue_with_hierarchy_fixed_version.reload
325 296 assert_equal 6, issue_with_hierarchy_fixed_version.fixed_version_id
326 297
327 298 # Move project out of the issue's hierarchy
328 299 moved_project = Project.find(3)
329 300 moved_project.set_parent!(Project.find(2))
330 301 parent_issue.reload
331 302 issue_with_local_fixed_version.reload
332 303 issue_with_hierarchy_fixed_version.reload
333 304
334 305 assert_equal 4, issue_with_local_fixed_version.fixed_version_id, "Fixed version was not keep on an issue local to the moved project"
335 306 assert_equal nil, issue_with_hierarchy_fixed_version.fixed_version_id, "Fixed version is still set after moving the Project out of the hierarchy where the version is defined in"
336 307 assert_equal nil, parent_issue.fixed_version_id, "Fixed version is still set after moving the Version out of the hierarchy for the issue."
337 308 end
338 309
339 310 def test_parent
340 311 p = Project.find(6).parent
341 312 assert p.is_a?(Project)
342 313 assert_equal 5, p.id
343 314 end
344 315
345 316 def test_ancestors
346 317 a = Project.find(6).ancestors
347 318 assert a.first.is_a?(Project)
348 319 assert_equal [1, 5], a.collect(&:id)
349 320 end
350 321
351 322 def test_root
352 323 r = Project.find(6).root
353 324 assert r.is_a?(Project)
354 325 assert_equal 1, r.id
355 326 end
356 327
357 328 def test_children
358 329 c = Project.find(1).children
359 330 assert c.first.is_a?(Project)
360 331 assert_equal [5, 3, 4], c.collect(&:id)
361 332 end
362 333
363 334 def test_descendants
364 335 d = Project.find(1).descendants
365 336 assert d.first.is_a?(Project)
366 337 assert_equal [5, 6, 3, 4], d.collect(&:id)
367 338 end
368 339
369 340 def test_allowed_parents_should_be_empty_for_non_member_user
370 341 Role.non_member.add_permission!(:add_project)
371 342 user = User.find(9)
372 343 assert user.memberships.empty?
373 344 User.current = user
374 345 assert Project.new.allowed_parents.compact.empty?
375 346 end
376 347
377 348 def test_allowed_parents_with_add_subprojects_permission
378 349 Role.find(1).remove_permission!(:add_project)
379 350 Role.find(1).add_permission!(:add_subprojects)
380 351 User.current = User.find(2)
381 352 # new project
382 353 assert !Project.new.allowed_parents.include?(nil)
383 354 assert Project.new.allowed_parents.include?(Project.find(1))
384 355 # existing root project
385 356 assert Project.find(1).allowed_parents.include?(nil)
386 357 # existing child
387 358 assert Project.find(3).allowed_parents.include?(Project.find(1))
388 359 assert !Project.find(3).allowed_parents.include?(nil)
389 360 end
390 361
391 362 def test_allowed_parents_with_add_project_permission
392 363 Role.find(1).add_permission!(:add_project)
393 364 Role.find(1).remove_permission!(:add_subprojects)
394 365 User.current = User.find(2)
395 366 # new project
396 367 assert Project.new.allowed_parents.include?(nil)
397 368 assert !Project.new.allowed_parents.include?(Project.find(1))
398 369 # existing root project
399 370 assert Project.find(1).allowed_parents.include?(nil)
400 371 # existing child
401 372 assert Project.find(3).allowed_parents.include?(Project.find(1))
402 373 assert Project.find(3).allowed_parents.include?(nil)
403 374 end
404 375
405 376 def test_allowed_parents_with_add_project_and_subprojects_permission
406 377 Role.find(1).add_permission!(:add_project)
407 378 Role.find(1).add_permission!(:add_subprojects)
408 379 User.current = User.find(2)
409 380 # new project
410 381 assert Project.new.allowed_parents.include?(nil)
411 382 assert Project.new.allowed_parents.include?(Project.find(1))
412 383 # existing root project
413 384 assert Project.find(1).allowed_parents.include?(nil)
414 385 # existing child
415 386 assert Project.find(3).allowed_parents.include?(Project.find(1))
416 387 assert Project.find(3).allowed_parents.include?(nil)
417 388 end
418 389
419 390 def test_users_by_role
420 391 users_by_role = Project.find(1).users_by_role
421 392 assert_kind_of Hash, users_by_role
422 393 role = Role.find(1)
423 394 assert_kind_of Array, users_by_role[role]
424 395 assert users_by_role[role].include?(User.find(2))
425 396 end
426 397
427 398 def test_rolled_up_trackers
428 399 parent = Project.find(1)
429 400 parent.trackers = Tracker.find([1,2])
430 401 child = parent.children.find(3)
431 402
432 403 assert_equal [1, 2], parent.tracker_ids
433 404 assert_equal [2, 3], child.trackers.collect(&:id)
434 405
435 406 assert_kind_of Tracker, parent.rolled_up_trackers.first
436 407 assert_equal Tracker.find(1), parent.rolled_up_trackers.first
437 408
438 409 assert_equal [1, 2, 3], parent.rolled_up_trackers.collect(&:id)
439 410 assert_equal [2, 3], child.rolled_up_trackers.collect(&:id)
440 411 end
441 412
442 413 def test_rolled_up_trackers_should_ignore_archived_subprojects
443 414 parent = Project.find(1)
444 415 parent.trackers = Tracker.find([1,2])
445 416 child = parent.children.find(3)
446 417 child.trackers = Tracker.find([1,3])
447 418 parent.children.each(&:archive)
448 419
449 420 assert_equal [1,2], parent.rolled_up_trackers.collect(&:id)
450 421 end
451 422
452 423 context "#rolled_up_versions" do
453 424 setup do
454 425 @project = Project.generate!
455 426 @parent_version_1 = Version.generate!(:project => @project)
456 427 @parent_version_2 = Version.generate!(:project => @project)
457 428 end
458 429
459 430 should "include the versions for the current project" do
460 431 assert_same_elements [@parent_version_1, @parent_version_2], @project.rolled_up_versions
461 432 end
462 433
463 434 should "include versions for a subproject" do
464 435 @subproject = Project.generate!
465 436 @subproject.set_parent!(@project)
466 437 @subproject_version = Version.generate!(:project => @subproject)
467 438
468 439 assert_same_elements [
469 440 @parent_version_1,
470 441 @parent_version_2,
471 442 @subproject_version
472 443 ], @project.rolled_up_versions
473 444 end
474 445
475 446 should "include versions for a sub-subproject" do
476 447 @subproject = Project.generate!
477 448 @subproject.set_parent!(@project)
478 449 @sub_subproject = Project.generate!
479 450 @sub_subproject.set_parent!(@subproject)
480 451 @sub_subproject_version = Version.generate!(:project => @sub_subproject)
481 452
482 453 @project.reload
483 454
484 455 assert_same_elements [
485 456 @parent_version_1,
486 457 @parent_version_2,
487 458 @sub_subproject_version
488 459 ], @project.rolled_up_versions
489 460 end
490 461
491 462 should "only check active projects" do
492 463 @subproject = Project.generate!
493 464 @subproject.set_parent!(@project)
494 465 @subproject_version = Version.generate!(:project => @subproject)
495 466 assert @subproject.archive
496 467
497 468 @project.reload
498 469
499 470 assert !@subproject.active?
500 471 assert_same_elements [@parent_version_1, @parent_version_2], @project.rolled_up_versions
501 472 end
502 473 end
503 474
504 475 def test_shared_versions_none_sharing
505 476 p = Project.find(5)
506 477 v = Version.create!(:name => 'none_sharing', :project => p, :sharing => 'none')
507 478 assert p.shared_versions.include?(v)
508 479 assert !p.children.first.shared_versions.include?(v)
509 480 assert !p.root.shared_versions.include?(v)
510 481 assert !p.siblings.first.shared_versions.include?(v)
511 482 assert !p.root.siblings.first.shared_versions.include?(v)
512 483 end
513 484
514 485 def test_shared_versions_descendants_sharing
515 486 p = Project.find(5)
516 487 v = Version.create!(:name => 'descendants_sharing', :project => p, :sharing => 'descendants')
517 488 assert p.shared_versions.include?(v)
518 489 assert p.children.first.shared_versions.include?(v)
519 490 assert !p.root.shared_versions.include?(v)
520 491 assert !p.siblings.first.shared_versions.include?(v)
521 492 assert !p.root.siblings.first.shared_versions.include?(v)
522 493 end
523 494
524 495 def test_shared_versions_hierarchy_sharing
525 496 p = Project.find(5)
526 497 v = Version.create!(:name => 'hierarchy_sharing', :project => p, :sharing => 'hierarchy')
527 498 assert p.shared_versions.include?(v)
528 499 assert p.children.first.shared_versions.include?(v)
529 500 assert p.root.shared_versions.include?(v)
530 501 assert !p.siblings.first.shared_versions.include?(v)
531 502 assert !p.root.siblings.first.shared_versions.include?(v)
532 503 end
533 504
534 505 def test_shared_versions_tree_sharing
535 506 p = Project.find(5)
536 507 v = Version.create!(:name => 'tree_sharing', :project => p, :sharing => 'tree')
537 508 assert p.shared_versions.include?(v)
538 509 assert p.children.first.shared_versions.include?(v)
539 510 assert p.root.shared_versions.include?(v)
540 511 assert p.siblings.first.shared_versions.include?(v)
541 512 assert !p.root.siblings.first.shared_versions.include?(v)
542 513 end
543 514
544 515 def test_shared_versions_system_sharing
545 516 p = Project.find(5)
546 517 v = Version.create!(:name => 'system_sharing', :project => p, :sharing => 'system')
547 518 assert p.shared_versions.include?(v)
548 519 assert p.children.first.shared_versions.include?(v)
549 520 assert p.root.shared_versions.include?(v)
550 521 assert p.siblings.first.shared_versions.include?(v)
551 522 assert p.root.siblings.first.shared_versions.include?(v)
552 523 end
553 524
554 525 def test_shared_versions
555 526 parent = Project.find(1)
556 527 child = parent.children.find(3)
557 528 private_child = parent.children.find(5)
558 529
559 530 assert_equal [1,2,3], parent.version_ids.sort
560 531 assert_equal [4], child.version_ids
561 532 assert_equal [6], private_child.version_ids
562 533 assert_equal [7], Version.find_all_by_sharing('system').collect(&:id)
563 534
564 535 assert_equal 6, parent.shared_versions.size
565 536 parent.shared_versions.each do |version|
566 537 assert_kind_of Version, version
567 538 end
568 539
569 540 assert_equal [1,2,3,4,6,7], parent.shared_versions.collect(&:id).sort
570 541 end
571 542
572 543 def test_shared_versions_should_ignore_archived_subprojects
573 544 parent = Project.find(1)
574 545 child = parent.children.find(3)
575 546 child.archive
576 547 parent.reload
577 548
578 549 assert_equal [1,2,3], parent.version_ids.sort
579 550 assert_equal [4], child.version_ids
580 551 assert !parent.shared_versions.collect(&:id).include?(4)
581 552 end
582 553
583 554 def test_shared_versions_visible_to_user
584 555 user = User.find(3)
585 556 parent = Project.find(1)
586 557 child = parent.children.find(5)
587 558
588 559 assert_equal [1,2,3], parent.version_ids.sort
589 560 assert_equal [6], child.version_ids
590 561
591 562 versions = parent.shared_versions.visible(user)
592 563
593 564 assert_equal 4, versions.size
594 565 versions.each do |version|
595 566 assert_kind_of Version, version
596 567 end
597 568
598 569 assert !versions.collect(&:id).include?(6)
599 570 end
600 571
601 572 def test_shared_versions_for_new_project_should_include_system_shared_versions
602 573 p = Project.find(5)
603 574 v = Version.create!(:name => 'system_sharing', :project => p, :sharing => 'system')
604 575
605 576 assert_include v, Project.new.shared_versions
606 577 end
607 578
608 579 def test_next_identifier
609 580 ProjectCustomField.delete_all
610 581 Project.create!(:name => 'last', :identifier => 'p2008040')
611 582 assert_equal 'p2008041', Project.next_identifier
612 583 end
613 584
614 585 def test_next_identifier_first_project
615 586 Project.delete_all
616 587 assert_nil Project.next_identifier
617 588 end
618 589
619 590 def test_enabled_module_names
620 591 with_settings :default_projects_modules => ['issue_tracking', 'repository'] do
621 592 project = Project.new
622 593
623 594 project.enabled_module_names = %w(issue_tracking news)
624 595 assert_equal %w(issue_tracking news), project.enabled_module_names.sort
625 596 end
626 597 end
627 598
628 599 context "enabled_modules" do
629 600 setup do
630 601 @project = Project.find(1)
631 602 end
632 603
633 604 should "define module by names and preserve ids" do
634 605 # Remove one module
635 606 modules = @project.enabled_modules.slice(0..-2)
636 607 assert modules.any?
637 608 assert_difference 'EnabledModule.count', -1 do
638 609 @project.enabled_module_names = modules.collect(&:name)
639 610 end
640 611 @project.reload
641 612 # Ids should be preserved
642 613 assert_equal @project.enabled_module_ids.sort, modules.collect(&:id).sort
643 614 end
644 615
645 616 should "enable a module" do
646 617 @project.enabled_module_names = []
647 618 @project.reload
648 619 assert_equal [], @project.enabled_module_names
649 620 #with string
650 621 @project.enable_module!("issue_tracking")
651 622 assert_equal ["issue_tracking"], @project.enabled_module_names
652 623 #with symbol
653 624 @project.enable_module!(:gantt)
654 625 assert_equal ["issue_tracking", "gantt"], @project.enabled_module_names
655 626 #don't add a module twice
656 627 @project.enable_module!("issue_tracking")
657 628 assert_equal ["issue_tracking", "gantt"], @project.enabled_module_names
658 629 end
659 630
660 631 should "disable a module" do
661 632 #with string
662 633 assert @project.enabled_module_names.include?("issue_tracking")
663 634 @project.disable_module!("issue_tracking")
664 635 assert ! @project.reload.enabled_module_names.include?("issue_tracking")
665 636 #with symbol
666 637 assert @project.enabled_module_names.include?("gantt")
667 638 @project.disable_module!(:gantt)
668 639 assert ! @project.reload.enabled_module_names.include?("gantt")
669 640 #with EnabledModule object
670 641 first_module = @project.enabled_modules.first
671 642 @project.disable_module!(first_module)
672 643 assert ! @project.reload.enabled_module_names.include?(first_module.name)
673 644 end
674 645 end
675 646
676 647 def test_enabled_module_names_should_not_recreate_enabled_modules
677 648 project = Project.find(1)
678 649 # Remove one module
679 650 modules = project.enabled_modules.slice(0..-2)
680 651 assert modules.any?
681 652 assert_difference 'EnabledModule.count', -1 do
682 653 project.enabled_module_names = modules.collect(&:name)
683 654 end
684 655 project.reload
685 656 # Ids should be preserved
686 657 assert_equal project.enabled_module_ids.sort, modules.collect(&:id).sort
687 658 end
688 659
689 660 def test_copy_from_existing_project
690 661 source_project = Project.find(1)
691 662 copied_project = Project.copy_from(1)
692 663
693 664 assert copied_project
694 665 # Cleared attributes
695 666 assert copied_project.id.blank?
696 667 assert copied_project.name.blank?
697 668 assert copied_project.identifier.blank?
698 669
699 670 # Duplicated attributes
700 671 assert_equal source_project.description, copied_project.description
701 672 assert_equal source_project.enabled_modules, copied_project.enabled_modules
702 673 assert_equal source_project.trackers, copied_project.trackers
703 674
704 675 # Default attributes
705 676 assert_equal 1, copied_project.status
706 677 end
707 678
708 679 def test_activities_should_use_the_system_activities
709 680 project = Project.find(1)
710 681 assert_equal project.activities, TimeEntryActivity.find(:all, :conditions => {:active => true} )
711 682 end
712 683
713 684
714 685 def test_activities_should_use_the_project_specific_activities
715 686 project = Project.find(1)
716 687 overridden_activity = TimeEntryActivity.new({:name => "Project", :project => project})
717 688 assert overridden_activity.save!
718 689
719 690 assert project.activities.include?(overridden_activity), "Project specific Activity not found"
720 691 end
721 692
722 693 def test_activities_should_not_include_the_inactive_project_specific_activities
723 694 project = Project.find(1)
724 695 overridden_activity = TimeEntryActivity.new({:name => "Project", :project => project, :parent => TimeEntryActivity.find(:first), :active => false})
725 696 assert overridden_activity.save!
726 697
727 698 assert !project.activities.include?(overridden_activity), "Inactive Project specific Activity found"
728 699 end
729 700
730 701 def test_activities_should_not_include_project_specific_activities_from_other_projects
731 702 project = Project.find(1)
732 703 overridden_activity = TimeEntryActivity.new({:name => "Project", :project => Project.find(2)})
733 704 assert overridden_activity.save!
734 705
735 706 assert !project.activities.include?(overridden_activity), "Project specific Activity found on a different project"
736 707 end
737 708
738 709 def test_activities_should_handle_nils
739 710 overridden_activity = TimeEntryActivity.new({:name => "Project", :project => Project.find(1), :parent => TimeEntryActivity.find(:first)})
740 711 TimeEntryActivity.delete_all
741 712
742 713 # No activities
743 714 project = Project.find(1)
744 715 assert project.activities.empty?
745 716
746 717 # No system, one overridden
747 718 assert overridden_activity.save!
748 719 project.reload
749 720 assert_equal [overridden_activity], project.activities
750 721 end
751 722
752 723 def test_activities_should_override_system_activities_with_project_activities
753 724 project = Project.find(1)
754 725 parent_activity = TimeEntryActivity.find(:first)
755 726 overridden_activity = TimeEntryActivity.new({:name => "Project", :project => project, :parent => parent_activity})
756 727 assert overridden_activity.save!
757 728
758 729 assert project.activities.include?(overridden_activity), "Project specific Activity not found"
759 730 assert !project.activities.include?(parent_activity), "System Activity found when it should have been overridden"
760 731 end
761 732
762 733 def test_activities_should_include_inactive_activities_if_specified
763 734 project = Project.find(1)
764 735 overridden_activity = TimeEntryActivity.new({:name => "Project", :project => project, :parent => TimeEntryActivity.find(:first), :active => false})
765 736 assert overridden_activity.save!
766 737
767 738 assert project.activities(true).include?(overridden_activity), "Inactive Project specific Activity not found"
768 739 end
769 740
770 741 test 'activities should not include active System activities if the project has an override that is inactive' do
771 742 project = Project.find(1)
772 743 system_activity = TimeEntryActivity.find_by_name('Design')
773 744 assert system_activity.active?
774 745 overridden_activity = TimeEntryActivity.generate!(:project => project, :parent => system_activity, :active => false)
775 746 assert overridden_activity.save!
776 747
777 748 assert !project.activities.include?(overridden_activity), "Inactive Project specific Activity not found"
778 749 assert !project.activities.include?(system_activity), "System activity found when the project has an inactive override"
779 750 end
780 751
781 752 def test_close_completed_versions
782 753 Version.update_all("status = 'open'")
783 754 project = Project.find(1)
784 755 assert_not_nil project.versions.detect {|v| v.completed? && v.status == 'open'}
785 756 assert_not_nil project.versions.detect {|v| !v.completed? && v.status == 'open'}
786 757 project.close_completed_versions
787 758 project.reload
788 759 assert_nil project.versions.detect {|v| v.completed? && v.status != 'closed'}
789 760 assert_not_nil project.versions.detect {|v| !v.completed? && v.status == 'open'}
790 761 end
791 762
792 763 context "Project#copy" do
793 764 setup do
794 765 ProjectCustomField.destroy_all # Custom values are a mess to isolate in tests
795 766 Project.destroy_all :identifier => "copy-test"
796 767 @source_project = Project.find(2)
797 768 @project = Project.new(:name => 'Copy Test', :identifier => 'copy-test')
798 769 @project.trackers = @source_project.trackers
799 770 @project.enabled_module_names = @source_project.enabled_modules.collect(&:name)
800 771 end
801 772
802 773 should "copy issues" do
803 774 @source_project.issues << Issue.generate!(:status => IssueStatus.find_by_name('Closed'),
804 775 :subject => "copy issue status",
805 776 :tracker_id => 1,
806 777 :assigned_to_id => 2,
807 778 :project_id => @source_project.id)
808 779 assert @project.valid?
809 780 assert @project.issues.empty?
810 781 assert @project.copy(@source_project)
811 782
812 783 assert_equal @source_project.issues.size, @project.issues.size
813 784 @project.issues.each do |issue|
814 785 assert issue.valid?
815 786 assert ! issue.assigned_to.blank?
816 787 assert_equal @project, issue.project
817 788 end
818 789
819 790 copied_issue = @project.issues.first(:conditions => {:subject => "copy issue status"})
820 791 assert copied_issue
821 792 assert copied_issue.status
822 793 assert_equal "Closed", copied_issue.status.name
823 794 end
824 795
825 796 should "change the new issues to use the copied version" do
826 797 User.current = User.find(1)
827 798 assigned_version = Version.generate!(:name => "Assigned Issues", :status => 'open')
828 799 @source_project.versions << assigned_version
829 800 assert_equal 3, @source_project.versions.size
830 801 Issue.generate_for_project!(@source_project,
831 802 :fixed_version_id => assigned_version.id,
832 803 :subject => "change the new issues to use the copied version",
833 804 :tracker_id => 1,
834 805 :project_id => @source_project.id)
835 806
836 807 assert @project.copy(@source_project)
837 808 @project.reload
838 809 copied_issue = @project.issues.first(:conditions => {:subject => "change the new issues to use the copied version"})
839 810
840 811 assert copied_issue
841 812 assert copied_issue.fixed_version
842 813 assert_equal "Assigned Issues", copied_issue.fixed_version.name # Same name
843 814 assert_not_equal assigned_version.id, copied_issue.fixed_version.id # Different record
844 815 end
845 816
846 817 should "copy issue relations" do
847 818 Setting.cross_project_issue_relations = '1'
848 819
849 820 second_issue = Issue.generate!(:status_id => 5,
850 821 :subject => "copy issue relation",
851 822 :tracker_id => 1,
852 823 :assigned_to_id => 2,
853 824 :project_id => @source_project.id)
854 825 source_relation = IssueRelation.generate!(:issue_from => Issue.find(4),
855 826 :issue_to => second_issue,
856 827 :relation_type => "relates")
857 828 source_relation_cross_project = IssueRelation.generate!(:issue_from => Issue.find(1),
858 829 :issue_to => second_issue,
859 830 :relation_type => "duplicates")
860 831
861 832 assert @project.copy(@source_project)
862 833 assert_equal @source_project.issues.count, @project.issues.count
863 834 copied_issue = @project.issues.find_by_subject("Issue on project 2") # Was #4
864 835 copied_second_issue = @project.issues.find_by_subject("copy issue relation")
865 836
866 837 # First issue with a relation on project
867 838 assert_equal 1, copied_issue.relations.size, "Relation not copied"
868 839 copied_relation = copied_issue.relations.first
869 840 assert_equal "relates", copied_relation.relation_type
870 841 assert_equal copied_second_issue.id, copied_relation.issue_to_id
871 842 assert_not_equal source_relation.id, copied_relation.id
872 843
873 844 # Second issue with a cross project relation
874 845 assert_equal 2, copied_second_issue.relations.size, "Relation not copied"
875 846 copied_relation = copied_second_issue.relations.select {|r| r.relation_type == 'duplicates'}.first
876 847 assert_equal "duplicates", copied_relation.relation_type
877 848 assert_equal 1, copied_relation.issue_from_id, "Cross project relation not kept"
878 849 assert_not_equal source_relation_cross_project.id, copied_relation.id
879 850 end
880 851
881 852 should "copy issue attachments" do
882 853 issue = Issue.generate!(:subject => "copy with attachment", :tracker_id => 1, :project_id => @source_project.id)
883 854 Attachment.create!(:container => issue, :file => uploaded_test_file("testfile.txt", "text/plain"), :author_id => 1)
884 855 @source_project.issues << issue
885 856 assert @project.copy(@source_project)
886 857
887 858 copied_issue = @project.issues.first(:conditions => {:subject => "copy with attachment"})
888 859 assert_not_nil copied_issue
889 860 assert_equal 1, copied_issue.attachments.count, "Attachment not copied"
890 861 assert_equal "testfile.txt", copied_issue.attachments.first.filename
891 862 end
892 863
893 864 should "copy memberships" do
894 865 assert @project.valid?
895 866 assert @project.members.empty?
896 867 assert @project.copy(@source_project)
897 868
898 869 assert_equal @source_project.memberships.size, @project.memberships.size
899 870 @project.memberships.each do |membership|
900 871 assert membership
901 872 assert_equal @project, membership.project
902 873 end
903 874 end
904 875
905 876 should "copy memberships with groups and additional roles" do
906 877 group = Group.create!(:lastname => "Copy group")
907 878 user = User.find(7)
908 879 group.users << user
909 880 # group role
910 881 Member.create!(:project_id => @source_project.id, :principal => group, :role_ids => [2])
911 882 member = Member.find_by_user_id_and_project_id(user.id, @source_project.id)
912 883 # additional role
913 884 member.role_ids = [1]
914 885
915 886 assert @project.copy(@source_project)
916 887 member = Member.find_by_user_id_and_project_id(user.id, @project.id)
917 888 assert_not_nil member
918 889 assert_equal [1, 2], member.role_ids.sort
919 890 end
920 891
921 892 should "copy project specific queries" do
922 893 assert @project.valid?
923 894 assert @project.queries.empty?
924 895 assert @project.copy(@source_project)
925 896
926 897 assert_equal @source_project.queries.size, @project.queries.size
927 898 @project.queries.each do |query|
928 899 assert query
929 900 assert_equal @project, query.project
930 901 end
931 902 assert_equal @source_project.queries.map(&:user_id).sort, @project.queries.map(&:user_id).sort
932 903 end
933 904
934 905 should "copy versions" do
935 906 @source_project.versions << Version.generate!
936 907 @source_project.versions << Version.generate!
937 908
938 909 assert @project.versions.empty?
939 910 assert @project.copy(@source_project)
940 911
941 912 assert_equal @source_project.versions.size, @project.versions.size
942 913 @project.versions.each do |version|
943 914 assert version
944 915 assert_equal @project, version.project
945 916 end
946 917 end
947 918
948 919 should "copy wiki" do
949 920 assert_difference 'Wiki.count' do
950 921 assert @project.copy(@source_project)
951 922 end
952 923
953 924 assert @project.wiki
954 925 assert_not_equal @source_project.wiki, @project.wiki
955 926 assert_equal "Start page", @project.wiki.start_page
956 927 end
957 928
958 929 should "copy wiki pages and content with hierarchy" do
959 930 assert_difference 'WikiPage.count', @source_project.wiki.pages.size do
960 931 assert @project.copy(@source_project)
961 932 end
962 933
963 934 assert @project.wiki
964 935 assert_equal @source_project.wiki.pages.size, @project.wiki.pages.size
965 936
966 937 @project.wiki.pages.each do |wiki_page|
967 938 assert wiki_page.content
968 939 assert !@source_project.wiki.pages.include?(wiki_page)
969 940 end
970 941
971 942 parent = @project.wiki.find_page('Parent_page')
972 943 child1 = @project.wiki.find_page('Child_page_1')
973 944 child2 = @project.wiki.find_page('Child_page_2')
974 945 assert_equal parent, child1.parent
975 946 assert_equal parent, child2.parent
976 947 end
977 948
978 949 should "copy issue categories" do
979 950 assert @project.copy(@source_project)
980 951
981 952 assert_equal 2, @project.issue_categories.size
982 953 @project.issue_categories.each do |issue_category|
983 954 assert !@source_project.issue_categories.include?(issue_category)
984 955 end
985 956 end
986 957
987 958 should "copy boards" do
988 959 assert @project.copy(@source_project)
989 960
990 961 assert_equal 1, @project.boards.size
991 962 @project.boards.each do |board|
992 963 assert !@source_project.boards.include?(board)
993 964 end
994 965 end
995 966
996 967 should "change the new issues to use the copied issue categories" do
997 968 issue = Issue.find(4)
998 969 issue.update_attribute(:category_id, 3)
999 970
1000 971 assert @project.copy(@source_project)
1001 972
1002 973 @project.issues.each do |issue|
1003 974 assert issue.category
1004 975 assert_equal "Stock management", issue.category.name # Same name
1005 976 assert_not_equal IssueCategory.find(3), issue.category # Different record
1006 977 end
1007 978 end
1008 979
1009 980 should "limit copy with :only option" do
1010 981 assert @project.members.empty?
1011 982 assert @project.issue_categories.empty?
1012 983 assert @source_project.issues.any?
1013 984
1014 985 assert @project.copy(@source_project, :only => ['members', 'issue_categories'])
1015 986
1016 987 assert @project.members.any?
1017 988 assert @project.issue_categories.any?
1018 989 assert @project.issues.empty?
1019 990 end
1020 991
1021 992 end
1022 993
1023 994 context "#start_date" do
1024 995 setup do
1025 996 ProjectCustomField.destroy_all # Custom values are a mess to isolate in tests
1026 997 @project = Project.generate!(:identifier => 'test0')
1027 998 @project.trackers << Tracker.generate!
1028 999 end
1029 1000
1030 1001 should "be nil if there are no issues on the project" do
1031 1002 assert_nil @project.start_date
1032 1003 end
1033 1004
1034 1005 should "be tested when issues have no start date"
1035 1006
1036 1007 should "be the earliest start date of it's issues" do
1037 1008 early = 7.days.ago.to_date
1038 1009 Issue.generate_for_project!(@project, :start_date => Date.today)
1039 1010 Issue.generate_for_project!(@project, :start_date => early)
1040 1011
1041 1012 assert_equal early, @project.start_date
1042 1013 end
1043 1014
1044 1015 end
1045 1016
1046 1017 context "#due_date" do
1047 1018 setup do
1048 1019 ProjectCustomField.destroy_all # Custom values are a mess to isolate in tests
1049 1020 @project = Project.generate!(:identifier => 'test0')
1050 1021 @project.trackers << Tracker.generate!
1051 1022 end
1052 1023
1053 1024 should "be nil if there are no issues on the project" do
1054 1025 assert_nil @project.due_date
1055 1026 end
1056 1027
1057 1028 should "be tested when issues have no due date"
1058 1029
1059 1030 should "be the latest due date of it's issues" do
1060 1031 future = 7.days.from_now.to_date
1061 1032 Issue.generate_for_project!(@project, :due_date => future)
1062 1033 Issue.generate_for_project!(@project, :due_date => Date.today)
1063 1034
1064 1035 assert_equal future, @project.due_date
1065 1036 end
1066 1037
1067 1038 should "be the latest due date of it's versions" do
1068 1039 future = 7.days.from_now.to_date
1069 1040 @project.versions << Version.generate!(:effective_date => future)
1070 1041 @project.versions << Version.generate!(:effective_date => Date.today)
1071 1042
1072 1043
1073 1044 assert_equal future, @project.due_date
1074 1045
1075 1046 end
1076 1047
1077 1048 should "pick the latest date from it's issues and versions" do
1078 1049 future = 7.days.from_now.to_date
1079 1050 far_future = 14.days.from_now.to_date
1080 1051 Issue.generate_for_project!(@project, :due_date => far_future)
1081 1052 @project.versions << Version.generate!(:effective_date => future)
1082 1053
1083 1054 assert_equal far_future, @project.due_date
1084 1055 end
1085 1056
1086 1057 end
1087 1058
1088 1059 context "Project#completed_percent" do
1089 1060 setup do
1090 1061 ProjectCustomField.destroy_all # Custom values are a mess to isolate in tests
1091 1062 @project = Project.generate!(:identifier => 'test0')
1092 1063 @project.trackers << Tracker.generate!
1093 1064 end
1094 1065
1095 1066 context "no versions" do
1096 1067 should "be 100" do
1097 1068 assert_equal 100, @project.completed_percent
1098 1069 end
1099 1070 end
1100 1071
1101 1072 context "with versions" do
1102 1073 should "return 0 if the versions have no issues" do
1103 1074 Version.generate!(:project => @project)
1104 1075 Version.generate!(:project => @project)
1105 1076
1106 1077 assert_equal 0, @project.completed_percent
1107 1078 end
1108 1079
1109 1080 should "return 100 if the version has only closed issues" do
1110 1081 v1 = Version.generate!(:project => @project)
1111 1082 Issue.generate_for_project!(@project, :status => IssueStatus.find_by_name('Closed'), :fixed_version => v1)
1112 1083 v2 = Version.generate!(:project => @project)
1113 1084 Issue.generate_for_project!(@project, :status => IssueStatus.find_by_name('Closed'), :fixed_version => v2)
1114 1085
1115 1086 assert_equal 100, @project.completed_percent
1116 1087 end
1117 1088
1118 1089 should "return the averaged completed percent of the versions (not weighted)" do
1119 1090 v1 = Version.generate!(:project => @project)
1120 1091 Issue.generate_for_project!(@project, :status => IssueStatus.find_by_name('New'), :estimated_hours => 10, :done_ratio => 50, :fixed_version => v1)
1121 1092 v2 = Version.generate!(:project => @project)
1122 1093 Issue.generate_for_project!(@project, :status => IssueStatus.find_by_name('New'), :estimated_hours => 10, :done_ratio => 50, :fixed_version => v2)
1123 1094
1124 1095 assert_equal 50, @project.completed_percent
1125 1096 end
1126 1097
1127 1098 end
1128 1099 end
1129 1100
1130 1101 context "#notified_users" do
1131 1102 setup do
1132 1103 @project = Project.generate!
1133 1104 @role = Role.generate!
1134 1105
1135 1106 @user_with_membership_notification = User.generate!(:mail_notification => 'selected')
1136 1107 Member.generate!(:project => @project, :roles => [@role], :principal => @user_with_membership_notification, :mail_notification => true)
1137 1108
1138 1109 @all_events_user = User.generate!(:mail_notification => 'all')
1139 1110 Member.generate!(:project => @project, :roles => [@role], :principal => @all_events_user)
1140 1111
1141 1112 @no_events_user = User.generate!(:mail_notification => 'none')
1142 1113 Member.generate!(:project => @project, :roles => [@role], :principal => @no_events_user)
1143 1114
1144 1115 @only_my_events_user = User.generate!(:mail_notification => 'only_my_events')
1145 1116 Member.generate!(:project => @project, :roles => [@role], :principal => @only_my_events_user)
1146 1117
1147 1118 @only_assigned_user = User.generate!(:mail_notification => 'only_assigned')
1148 1119 Member.generate!(:project => @project, :roles => [@role], :principal => @only_assigned_user)
1149 1120
1150 1121 @only_owned_user = User.generate!(:mail_notification => 'only_owner')
1151 1122 Member.generate!(:project => @project, :roles => [@role], :principal => @only_owned_user)
1152 1123 end
1153 1124
1154 1125 should "include members with a mail notification" do
1155 1126 assert @project.notified_users.include?(@user_with_membership_notification)
1156 1127 end
1157 1128
1158 1129 should "include users with the 'all' notification option" do
1159 1130 assert @project.notified_users.include?(@all_events_user)
1160 1131 end
1161 1132
1162 1133 should "not include users with the 'none' notification option" do
1163 1134 assert !@project.notified_users.include?(@no_events_user)
1164 1135 end
1165 1136
1166 1137 should "not include users with the 'only_my_events' notification option" do
1167 1138 assert !@project.notified_users.include?(@only_my_events_user)
1168 1139 end
1169 1140
1170 1141 should "not include users with the 'only_assigned' notification option" do
1171 1142 assert !@project.notified_users.include?(@only_assigned_user)
1172 1143 end
1173 1144
1174 1145 should "not include users with the 'only_owner' notification option" do
1175 1146 assert !@project.notified_users.include?(@only_owned_user)
1176 1147 end
1177 1148 end
1178 1149
1179 1150 end
@@ -1,892 +1,887
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2011 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, :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 :workflows
30 30
31 31 def setup
32 32 @admin = User.find(1)
33 33 @jsmith = User.find(2)
34 34 @dlopper = User.find(3)
35 35 end
36 36
37 37 test 'object_daddy creation' do
38 38 User.generate_with_protected!(:firstname => 'Testing connection')
39 39 User.generate_with_protected!(:firstname => 'Testing connection')
40 40 assert_equal 2, User.count(:all, :conditions => {:firstname => 'Testing connection'})
41 41 end
42 42
43 43 def test_truth
44 44 assert_kind_of User, @jsmith
45 45 end
46 46
47 47 def test_mail_should_be_stripped
48 48 u = User.new
49 49 u.mail = " foo@bar.com "
50 50 assert_equal "foo@bar.com", u.mail
51 51 end
52 52
53 53 def test_mail_validation
54 54 u = User.new
55 55 u.mail = ''
56 56 assert !u.valid?
57 57 assert_equal I18n.translate('activerecord.errors.messages.blank'),
58 58 u.errors[:mail].to_s
59 59 end
60 60
61 61 def test_login_length_validation
62 62 user = User.new(:firstname => "new", :lastname => "user", :mail => "newuser@somenet.foo")
63 63 user.login = "x" * (User::LOGIN_LENGTH_LIMIT+1)
64 64 assert !user.valid?
65 65
66 66 user.login = "x" * (User::LOGIN_LENGTH_LIMIT)
67 67 assert user.valid?
68 68 assert user.save
69 69 end
70 70
71 71 def test_create
72 72 user = User.new(:firstname => "new", :lastname => "user", :mail => "newuser@somenet.foo")
73 73
74 74 user.login = "jsmith"
75 75 user.password, user.password_confirmation = "password", "password"
76 76 # login uniqueness
77 77 assert !user.save
78 78 assert_equal 1, user.errors.count
79 79
80 80 user.login = "newuser"
81 81 user.password, user.password_confirmation = "passwd", "password"
82 82 # password confirmation
83 83 assert !user.save
84 84 assert_equal 1, user.errors.count
85 85
86 86 user.password, user.password_confirmation = "password", "password"
87 87 assert user.save
88 88 end
89 89
90 90 context "User#before_create" do
91 91 should "set the mail_notification to the default Setting" do
92 92 @user1 = User.generate_with_protected!
93 93 assert_equal 'only_my_events', @user1.mail_notification
94 94
95 95 with_settings :default_notification_option => 'all' do
96 96 @user2 = User.generate_with_protected!
97 97 assert_equal 'all', @user2.mail_notification
98 98 end
99 99 end
100 100 end
101 101
102 102 context "User.login" do
103 103 should "be case-insensitive." do
104 104 u = User.new(:firstname => "new", :lastname => "user", :mail => "newuser@somenet.foo")
105 105 u.login = 'newuser'
106 106 u.password, u.password_confirmation = "password", "password"
107 107 assert u.save
108 108
109 109 u = User.new(:firstname => "Similar", :lastname => "User", :mail => "similaruser@somenet.foo")
110 110 u.login = 'NewUser'
111 111 u.password, u.password_confirmation = "password", "password"
112 112 assert !u.save
113 113 assert_equal I18n.translate('activerecord.errors.messages.taken'),
114 114 u.errors[:login].to_s
115 115 end
116 116 end
117 117
118 118 def test_mail_uniqueness_should_not_be_case_sensitive
119 119 u = User.new(:firstname => "new", :lastname => "user", :mail => "newuser@somenet.foo")
120 120 u.login = 'newuser1'
121 121 u.password, u.password_confirmation = "password", "password"
122 122 assert u.save
123 123
124 124 u = User.new(:firstname => "new", :lastname => "user", :mail => "newUser@Somenet.foo")
125 125 u.login = 'newuser2'
126 126 u.password, u.password_confirmation = "password", "password"
127 127 assert !u.save
128 128 assert_equal I18n.translate('activerecord.errors.messages.taken'),
129 129 u.errors[:mail].to_s
130 130 end
131 131
132 132 def test_update
133 133 assert_equal "admin", @admin.login
134 134 @admin.login = "john"
135 135 assert @admin.save, @admin.errors.full_messages.join("; ")
136 136 @admin.reload
137 137 assert_equal "john", @admin.login
138 138 end
139 139
140 140 def test_destroy_should_delete_members_and_roles
141 141 members = Member.find_all_by_user_id(2)
142 142 ms = members.size
143 143 rs = members.collect(&:roles).flatten.size
144 144
145 145 assert_difference 'Member.count', - ms do
146 146 assert_difference 'MemberRole.count', - rs do
147 147 User.find(2).destroy
148 148 end
149 149 end
150 150
151 151 assert_nil User.find_by_id(2)
152 152 assert Member.find_all_by_user_id(2).empty?
153 153 end
154 154
155 155 def test_destroy_should_update_attachments
156 156 attachment = Attachment.create!(:container => Project.find(1),
157 157 :file => uploaded_test_file("testfile.txt", "text/plain"),
158 158 :author_id => 2)
159 159
160 160 User.find(2).destroy
161 161 assert_nil User.find_by_id(2)
162 162 assert_equal User.anonymous, attachment.reload.author
163 163 end
164 164
165 165 def test_destroy_should_update_comments
166 166 comment = Comment.create!(
167 167 :commented => News.create!(:project_id => 1, :author_id => 1, :title => 'foo', :description => 'foo'),
168 168 :author => User.find(2),
169 169 :comments => 'foo'
170 170 )
171 171
172 172 User.find(2).destroy
173 173 assert_nil User.find_by_id(2)
174 174 assert_equal User.anonymous, comment.reload.author
175 175 end
176 176
177 177 def test_destroy_should_update_issues
178 178 issue = Issue.create!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'foo')
179 179
180 180 User.find(2).destroy
181 181 assert_nil User.find_by_id(2)
182 182 assert_equal User.anonymous, issue.reload.author
183 183 end
184 184
185 185 def test_destroy_should_unassign_issues
186 186 issue = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'foo', :assigned_to_id => 2)
187 187
188 188 User.find(2).destroy
189 189 assert_nil User.find_by_id(2)
190 190 assert_nil issue.reload.assigned_to
191 191 end
192 192
193 193 def test_destroy_should_update_journals
194 194 issue = Issue.create!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'foo')
195 195 issue.init_journal(User.find(2), "update")
196 196 issue.save!
197 197
198 198 User.find(2).destroy
199 199 assert_nil User.find_by_id(2)
200 200 assert_equal User.anonymous, issue.journals.first.reload.user
201 201 end
202 202
203 203 def test_destroy_should_update_journal_details_old_value
204 204 issue = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'foo', :assigned_to_id => 2)
205 205 issue.init_journal(User.find(1), "update")
206 206 issue.assigned_to_id = nil
207 207 assert_difference 'JournalDetail.count' do
208 208 issue.save!
209 209 end
210 210 journal_detail = JournalDetail.first(:order => 'id DESC')
211 211 assert_equal '2', journal_detail.old_value
212 212
213 213 User.find(2).destroy
214 214 assert_nil User.find_by_id(2)
215 215 assert_equal User.anonymous.id.to_s, journal_detail.reload.old_value
216 216 end
217 217
218 218 def test_destroy_should_update_journal_details_value
219 219 issue = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'foo')
220 220 issue.init_journal(User.find(1), "update")
221 221 issue.assigned_to_id = 2
222 222 assert_difference 'JournalDetail.count' do
223 223 issue.save!
224 224 end
225 225 journal_detail = JournalDetail.first(:order => 'id DESC')
226 226 assert_equal '2', journal_detail.value
227 227
228 228 User.find(2).destroy
229 229 assert_nil User.find_by_id(2)
230 230 assert_equal User.anonymous.id.to_s, journal_detail.reload.value
231 231 end
232 232
233 233 def test_destroy_should_update_messages
234 234 board = Board.create!(:project_id => 1, :name => 'Board', :description => 'Board')
235 235 message = Message.create!(:board_id => board.id, :author_id => 2, :subject => 'foo', :content => 'foo')
236 236
237 237 User.find(2).destroy
238 238 assert_nil User.find_by_id(2)
239 239 assert_equal User.anonymous, message.reload.author
240 240 end
241 241
242 242 def test_destroy_should_update_news
243 243 news = News.create!(:project_id => 1, :author_id => 2, :title => 'foo', :description => 'foo')
244 244
245 245 User.find(2).destroy
246 246 assert_nil User.find_by_id(2)
247 247 assert_equal User.anonymous, news.reload.author
248 248 end
249 249
250 250 def test_destroy_should_delete_private_queries
251 251 query = Query.new(:name => 'foo', :is_public => false)
252 252 query.project_id = 1
253 253 query.user_id = 2
254 254 query.save!
255 255
256 256 User.find(2).destroy
257 257 assert_nil User.find_by_id(2)
258 258 assert_nil Query.find_by_id(query.id)
259 259 end
260 260
261 261 def test_destroy_should_update_public_queries
262 262 query = Query.new(:name => 'foo', :is_public => true)
263 263 query.project_id = 1
264 264 query.user_id = 2
265 265 query.save!
266 266
267 267 User.find(2).destroy
268 268 assert_nil User.find_by_id(2)
269 269 assert_equal User.anonymous, query.reload.user
270 270 end
271 271
272 272 def test_destroy_should_update_time_entries
273 273 entry = TimeEntry.new(:hours => '2', :spent_on => Date.today, :activity => TimeEntryActivity.create!(:name => 'foo'))
274 274 entry.project_id = 1
275 275 entry.user_id = 2
276 276 entry.save!
277 277
278 278 User.find(2).destroy
279 279 assert_nil User.find_by_id(2)
280 280 assert_equal User.anonymous, entry.reload.user
281 281 end
282 282
283 283 def test_destroy_should_delete_tokens
284 284 token = Token.create!(:user_id => 2, :value => 'foo')
285 285
286 286 User.find(2).destroy
287 287 assert_nil User.find_by_id(2)
288 288 assert_nil Token.find_by_id(token.id)
289 289 end
290 290
291 291 def test_destroy_should_delete_watchers
292 292 issue = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'foo')
293 293 watcher = Watcher.create!(:user_id => 2, :watchable => issue)
294 294
295 295 User.find(2).destroy
296 296 assert_nil User.find_by_id(2)
297 297 assert_nil Watcher.find_by_id(watcher.id)
298 298 end
299 299
300 300 def test_destroy_should_update_wiki_contents
301 301 wiki_content = WikiContent.create!(
302 302 :text => 'foo',
303 303 :author_id => 2,
304 304 :page => WikiPage.create!(:title => 'Foo', :wiki => Wiki.create!(:project_id => 1, :start_page => 'Start'))
305 305 )
306 306 wiki_content.text = 'bar'
307 307 assert_difference 'WikiContent::Version.count' do
308 308 wiki_content.save!
309 309 end
310 310
311 311 User.find(2).destroy
312 312 assert_nil User.find_by_id(2)
313 313 assert_equal User.anonymous, wiki_content.reload.author
314 314 wiki_content.versions.each do |version|
315 315 assert_equal User.anonymous, version.reload.author
316 316 end
317 317 end
318 318
319 319 def test_destroy_should_nullify_issue_categories
320 320 category = IssueCategory.create!(:project_id => 1, :assigned_to_id => 2, :name => 'foo')
321 321
322 322 User.find(2).destroy
323 323 assert_nil User.find_by_id(2)
324 324 assert_nil category.reload.assigned_to_id
325 325 end
326 326
327 327 def test_destroy_should_nullify_changesets
328 328 changeset = Changeset.create!(
329 329 :repository => Repository::Subversion.generate!(
330 330 :project_id => 1
331 331 ),
332 332 :revision => '12',
333 333 :committed_on => Time.now,
334 334 :committer => 'jsmith'
335 335 )
336 336 assert_equal 2, changeset.user_id
337 337
338 338 User.find(2).destroy
339 339 assert_nil User.find_by_id(2)
340 340 assert_nil changeset.reload.user_id
341 341 end
342 342
343 343 def test_anonymous_user_should_not_be_destroyable
344 344 assert_no_difference 'User.count' do
345 345 assert_equal false, User.anonymous.destroy
346 346 end
347 347 end
348 348
349 349 def test_validate_login_presence
350 350 @admin.login = ""
351 351 assert !@admin.save
352 352 assert_equal 1, @admin.errors.count
353 353 end
354 354
355 355 def test_validate_mail_notification_inclusion
356 356 u = User.new
357 357 u.mail_notification = 'foo'
358 358 u.save
359 359 assert_not_nil u.errors[:mail_notification]
360 360 end
361 361
362 362 context "User#try_to_login" do
363 363 should "fall-back to case-insensitive if user login is not found as-typed." do
364 364 user = User.try_to_login("AdMin", "admin")
365 365 assert_kind_of User, user
366 366 assert_equal "admin", user.login
367 367 end
368 368
369 369 should "select the exact matching user first" do
370 370 case_sensitive_user = User.generate_with_protected!(
371 371 :login => 'changed', :password => 'admin',
372 372 :password_confirmation => 'admin')
373 373 # bypass validations to make it appear like existing data
374 374 case_sensitive_user.update_attribute(:login, 'ADMIN')
375 375
376 376 user = User.try_to_login("ADMIN", "admin")
377 377 assert_kind_of User, user
378 378 assert_equal "ADMIN", user.login
379 379
380 380 end
381 381 end
382 382
383 383 def test_password
384 384 user = User.try_to_login("admin", "admin")
385 385 assert_kind_of User, user
386 386 assert_equal "admin", user.login
387 387 user.password = "hello"
388 388 assert user.save
389 389
390 390 user = User.try_to_login("admin", "hello")
391 391 assert_kind_of User, user
392 392 assert_equal "admin", user.login
393 393 end
394 394
395 395 def test_validate_password_length
396 396 with_settings :password_min_length => '100' do
397 397 user = User.new(:firstname => "new100", :lastname => "user100", :mail => "newuser100@somenet.foo")
398 398 user.login = "newuser100"
399 399 user.password, user.password_confirmation = "password100", "password100"
400 400 assert !user.save
401 401 assert_equal 1, user.errors.count
402 402 end
403 403 end
404 404
405 405 def test_name_format
406 406 assert_equal 'Smith, John', @jsmith.name(:lastname_coma_firstname)
407 407 with_settings :user_format => :firstname_lastname do
408 408 assert_equal 'John Smith', @jsmith.reload.name
409 409 end
410 410 with_settings :user_format => :username do
411 411 assert_equal 'jsmith', @jsmith.reload.name
412 412 end
413 413 end
414 414
415 415 def test_fields_for_order_statement_should_return_fields_according_user_format_setting
416 416 with_settings :user_format => 'lastname_coma_firstname' do
417 417 assert_equal ['users.lastname', 'users.firstname', 'users.id'], User.fields_for_order_statement
418 418 end
419 419 end
420 420
421 421 def test_fields_for_order_statement_width_table_name_should_prepend_table_name
422 422 with_settings :user_format => 'lastname_firstname' do
423 423 assert_equal ['authors.lastname', 'authors.firstname', 'authors.id'], User.fields_for_order_statement('authors')
424 424 end
425 425 end
426 426
427 427 def test_fields_for_order_statement_with_blank_format_should_return_default
428 428 with_settings :user_format => '' do
429 429 assert_equal ['users.firstname', 'users.lastname', 'users.id'], User.fields_for_order_statement
430 430 end
431 431 end
432 432
433 433 def test_fields_for_order_statement_with_invalid_format_should_return_default
434 434 with_settings :user_format => 'foo' do
435 435 assert_equal ['users.firstname', 'users.lastname', 'users.id'], User.fields_for_order_statement
436 436 end
437 437 end
438 438
439 439 def test_lock
440 440 user = User.try_to_login("jsmith", "jsmith")
441 441 assert_equal @jsmith, user
442 442
443 443 @jsmith.status = User::STATUS_LOCKED
444 444 assert @jsmith.save
445 445
446 446 user = User.try_to_login("jsmith", "jsmith")
447 447 assert_equal nil, user
448 448 end
449 449
450 450 context ".try_to_login" do
451 451 context "with good credentials" do
452 452 should "return the user" do
453 453 user = User.try_to_login("admin", "admin")
454 454 assert_kind_of User, user
455 455 assert_equal "admin", user.login
456 456 end
457 457 end
458 458
459 459 context "with wrong credentials" do
460 460 should "return nil" do
461 461 assert_nil User.try_to_login("admin", "foo")
462 462 end
463 463 end
464 464 end
465 465
466 466 if ldap_configured?
467 467 context "#try_to_login using LDAP" do
468 468 context "with failed connection to the LDAP server" do
469 469 should "return nil" do
470 470 @auth_source = AuthSourceLdap.find(1)
471 471 AuthSource.any_instance.stubs(:initialize_ldap_con).raises(Net::LDAP::LdapError, 'Cannot connect')
472 472
473 473 assert_equal nil, User.try_to_login('edavis', 'wrong')
474 474 end
475 475 end
476 476
477 477 context "with an unsuccessful authentication" do
478 478 should "return nil" do
479 479 assert_equal nil, User.try_to_login('edavis', 'wrong')
480 480 end
481 481 end
482 482
483 483 context "on the fly registration" do
484 484 setup do
485 485 @auth_source = AuthSourceLdap.find(1)
486 486 @auth_source.update_attribute :onthefly_register, true
487 487 end
488 488
489 489 context "with a successful authentication" do
490 490 should "create a new user account if it doesn't exist" do
491 491 assert_difference('User.count') do
492 492 user = User.try_to_login('edavis', '123456')
493 493 assert !user.admin?
494 494 end
495 495 end
496 496
497 497 should "retrieve existing user" do
498 498 user = User.try_to_login('edavis', '123456')
499 499 user.admin = true
500 500 user.save!
501 501
502 502 assert_no_difference('User.count') do
503 503 user = User.try_to_login('edavis', '123456')
504 504 assert user.admin?
505 505 end
506 506 end
507 507 end
508 508 end
509 509 end
510 510
511 511 else
512 512 puts "Skipping LDAP tests."
513 513 end
514 514
515 515 def test_create_anonymous
516 516 AnonymousUser.delete_all
517 517 anon = User.anonymous
518 518 assert !anon.new_record?
519 519 assert_kind_of AnonymousUser, anon
520 520 end
521 521
522 522 def test_ensure_single_anonymous_user
523 523 AnonymousUser.delete_all
524 524 anon1 = User.anonymous
525 525 assert !anon1.new_record?
526 526 assert_kind_of AnonymousUser, anon1
527 527 anon2 = AnonymousUser.create(
528 528 :lastname => 'Anonymous', :firstname => '',
529 529 :mail => '', :login => '', :status => 0)
530 530 assert_equal 1, anon2.errors.count
531 531 end
532 532
533 should_have_one :rss_token
534
535 533 def test_rss_key
536 534 assert_nil @jsmith.rss_token
537 535 key = @jsmith.rss_key
538 536 assert_equal 40, key.length
539 537
540 538 @jsmith.reload
541 539 assert_equal key, @jsmith.rss_key
542 540 end
543 541
544
545 should_have_one :api_token
546
547 542 context "User#api_key" do
548 543 should "generate a new one if the user doesn't have one" do
549 544 user = User.generate_with_protected!(:api_token => nil)
550 545 assert_nil user.api_token
551 546
552 547 key = user.api_key
553 548 assert_equal 40, key.length
554 549 user.reload
555 550 assert_equal key, user.api_key
556 551 end
557 552
558 553 should "return the existing api token value" do
559 554 user = User.generate_with_protected!
560 555 token = Token.generate!(:action => 'api')
561 556 user.api_token = token
562 557 assert user.save
563 558
564 559 assert_equal token.value, user.api_key
565 560 end
566 561 end
567 562
568 563 context "User#find_by_api_key" do
569 564 should "return nil if no matching key is found" do
570 565 assert_nil User.find_by_api_key('zzzzzzzzz')
571 566 end
572 567
573 568 should "return nil if the key is found for an inactive user" do
574 569 user = User.generate_with_protected!(:status => User::STATUS_LOCKED)
575 570 token = Token.generate!(:action => 'api')
576 571 user.api_token = token
577 572 user.save
578 573
579 574 assert_nil User.find_by_api_key(token.value)
580 575 end
581 576
582 577 should "return the user if the key is found for an active user" do
583 578 user = User.generate_with_protected!(:status => User::STATUS_ACTIVE)
584 579 token = Token.generate!(:action => 'api')
585 580 user.api_token = token
586 581 user.save
587 582
588 583 assert_equal user, User.find_by_api_key(token.value)
589 584 end
590 585 end
591 586
592 587 def test_roles_for_project
593 588 # user with a role
594 589 roles = @jsmith.roles_for_project(Project.find(1))
595 590 assert_kind_of Role, roles.first
596 591 assert_equal "Manager", roles.first.name
597 592
598 593 # user with no role
599 594 assert_nil @dlopper.roles_for_project(Project.find(2)).detect {|role| role.member?}
600 595 end
601 596
602 597 def test_projects_by_role_for_user_with_role
603 598 user = User.find(2)
604 599 assert_kind_of Hash, user.projects_by_role
605 600 assert_equal 2, user.projects_by_role.size
606 601 assert_equal [1,5], user.projects_by_role[Role.find(1)].collect(&:id).sort
607 602 assert_equal [2], user.projects_by_role[Role.find(2)].collect(&:id).sort
608 603 end
609 604
610 605 def test_projects_by_role_for_user_with_no_role
611 606 user = User.generate!
612 607 assert_equal({}, user.projects_by_role)
613 608 end
614 609
615 610 def test_projects_by_role_for_anonymous
616 611 assert_equal({}, User.anonymous.projects_by_role)
617 612 end
618 613
619 614 def test_valid_notification_options
620 615 # without memberships
621 616 assert_equal 5, User.find(7).valid_notification_options.size
622 617 # with memberships
623 618 assert_equal 6, User.find(2).valid_notification_options.size
624 619 end
625 620
626 621 def test_valid_notification_options_class_method
627 622 assert_equal 5, User.valid_notification_options.size
628 623 assert_equal 5, User.valid_notification_options(User.find(7)).size
629 624 assert_equal 6, User.valid_notification_options(User.find(2)).size
630 625 end
631 626
632 627 def test_mail_notification_all
633 628 @jsmith.mail_notification = 'all'
634 629 @jsmith.notified_project_ids = []
635 630 @jsmith.save
636 631 @jsmith.reload
637 632 assert @jsmith.projects.first.recipients.include?(@jsmith.mail)
638 633 end
639 634
640 635 def test_mail_notification_selected
641 636 @jsmith.mail_notification = 'selected'
642 637 @jsmith.notified_project_ids = [1]
643 638 @jsmith.save
644 639 @jsmith.reload
645 640 assert Project.find(1).recipients.include?(@jsmith.mail)
646 641 end
647 642
648 643 def test_mail_notification_only_my_events
649 644 @jsmith.mail_notification = 'only_my_events'
650 645 @jsmith.notified_project_ids = []
651 646 @jsmith.save
652 647 @jsmith.reload
653 648 assert !@jsmith.projects.first.recipients.include?(@jsmith.mail)
654 649 end
655 650
656 651 def test_comments_sorting_preference
657 652 assert !@jsmith.wants_comments_in_reverse_order?
658 653 @jsmith.pref.comments_sorting = 'asc'
659 654 assert !@jsmith.wants_comments_in_reverse_order?
660 655 @jsmith.pref.comments_sorting = 'desc'
661 656 assert @jsmith.wants_comments_in_reverse_order?
662 657 end
663 658
664 659 def test_find_by_mail_should_be_case_insensitive
665 660 u = User.find_by_mail('JSmith@somenet.foo')
666 661 assert_not_nil u
667 662 assert_equal 'jsmith@somenet.foo', u.mail
668 663 end
669 664
670 665 def test_random_password
671 666 u = User.new
672 667 u.random_password
673 668 assert !u.password.blank?
674 669 assert !u.password_confirmation.blank?
675 670 end
676 671
677 672 context "#change_password_allowed?" do
678 673 should "be allowed if no auth source is set" do
679 674 user = User.generate_with_protected!
680 675 assert user.change_password_allowed?
681 676 end
682 677
683 678 should "delegate to the auth source" do
684 679 user = User.generate_with_protected!
685 680
686 681 allowed_auth_source = AuthSource.generate!
687 682 def allowed_auth_source.allow_password_changes?; true; end
688 683
689 684 denied_auth_source = AuthSource.generate!
690 685 def denied_auth_source.allow_password_changes?; false; end
691 686
692 687 assert user.change_password_allowed?
693 688
694 689 user.auth_source = allowed_auth_source
695 690 assert user.change_password_allowed?, "User not allowed to change password, though auth source does"
696 691
697 692 user.auth_source = denied_auth_source
698 693 assert !user.change_password_allowed?, "User allowed to change password, though auth source does not"
699 694 end
700 695
701 696 end
702 697
703 698 context "#allowed_to?" do
704 699 context "with a unique project" do
705 700 should "return false if project is archived" do
706 701 project = Project.find(1)
707 702 Project.any_instance.stubs(:status).returns(Project::STATUS_ARCHIVED)
708 703 assert ! @admin.allowed_to?(:view_issues, Project.find(1))
709 704 end
710 705
711 706 should "return false if related module is disabled" do
712 707 project = Project.find(1)
713 708 project.enabled_module_names = ["issue_tracking"]
714 709 assert @admin.allowed_to?(:add_issues, project)
715 710 assert ! @admin.allowed_to?(:view_wiki_pages, project)
716 711 end
717 712
718 713 should "authorize nearly everything for admin users" do
719 714 project = Project.find(1)
720 715 assert ! @admin.member_of?(project)
721 716 %w(edit_issues delete_issues manage_news manage_documents manage_wiki).each do |p|
722 717 assert @admin.allowed_to?(p.to_sym, project)
723 718 end
724 719 end
725 720
726 721 should "authorize normal users depending on their roles" do
727 722 project = Project.find(1)
728 723 assert @jsmith.allowed_to?(:delete_messages, project) #Manager
729 724 assert ! @dlopper.allowed_to?(:delete_messages, project) #Developper
730 725 end
731 726 end
732 727
733 728 context "with multiple projects" do
734 729 should "return false if array is empty" do
735 730 assert ! @admin.allowed_to?(:view_project, [])
736 731 end
737 732
738 733 should "return true only if user has permission on all these projects" do
739 734 assert @admin.allowed_to?(:view_project, Project.all)
740 735 assert ! @dlopper.allowed_to?(:view_project, Project.all) #cannot see Project(2)
741 736 assert @jsmith.allowed_to?(:edit_issues, @jsmith.projects) #Manager or Developer everywhere
742 737 assert ! @jsmith.allowed_to?(:delete_issue_watchers, @jsmith.projects) #Dev cannot delete_issue_watchers
743 738 end
744 739
745 740 should "behave correctly with arrays of 1 project" do
746 741 assert ! User.anonymous.allowed_to?(:delete_issues, [Project.first])
747 742 end
748 743 end
749 744
750 745 context "with options[:global]" do
751 746 should "authorize if user has at least one role that has this permission" do
752 747 @dlopper2 = User.find(5) #only Developper on a project, not Manager anywhere
753 748 @anonymous = User.find(6)
754 749 assert @jsmith.allowed_to?(:delete_issue_watchers, nil, :global => true)
755 750 assert ! @dlopper2.allowed_to?(:delete_issue_watchers, nil, :global => true)
756 751 assert @dlopper2.allowed_to?(:add_issues, nil, :global => true)
757 752 assert ! @anonymous.allowed_to?(:add_issues, nil, :global => true)
758 753 assert @anonymous.allowed_to?(:view_issues, nil, :global => true)
759 754 end
760 755 end
761 756 end
762 757
763 758 context "User#notify_about?" do
764 759 context "Issues" do
765 760 setup do
766 761 @project = Project.find(1)
767 762 @author = User.generate_with_protected!
768 763 @assignee = User.generate_with_protected!
769 764 @issue = Issue.generate_for_project!(@project, :assigned_to => @assignee, :author => @author)
770 765 end
771 766
772 767 should "be true for a user with :all" do
773 768 @author.update_attribute(:mail_notification, 'all')
774 769 assert @author.notify_about?(@issue)
775 770 end
776 771
777 772 should "be false for a user with :none" do
778 773 @author.update_attribute(:mail_notification, 'none')
779 774 assert ! @author.notify_about?(@issue)
780 775 end
781 776
782 777 should "be false for a user with :only_my_events and isn't an author, creator, or assignee" do
783 778 @user = User.generate_with_protected!(:mail_notification => 'only_my_events')
784 779 Member.create!(:user => @user, :project => @project, :role_ids => [1])
785 780 assert ! @user.notify_about?(@issue)
786 781 end
787 782
788 783 should "be true for a user with :only_my_events and is the author" do
789 784 @author.update_attribute(:mail_notification, 'only_my_events')
790 785 assert @author.notify_about?(@issue)
791 786 end
792 787
793 788 should "be true for a user with :only_my_events and is the assignee" do
794 789 @assignee.update_attribute(:mail_notification, 'only_my_events')
795 790 assert @assignee.notify_about?(@issue)
796 791 end
797 792
798 793 should "be true for a user with :only_assigned and is the assignee" do
799 794 @assignee.update_attribute(:mail_notification, 'only_assigned')
800 795 assert @assignee.notify_about?(@issue)
801 796 end
802 797
803 798 should "be false for a user with :only_assigned and is not the assignee" do
804 799 @author.update_attribute(:mail_notification, 'only_assigned')
805 800 assert ! @author.notify_about?(@issue)
806 801 end
807 802
808 803 should "be true for a user with :only_owner and is the author" do
809 804 @author.update_attribute(:mail_notification, 'only_owner')
810 805 assert @author.notify_about?(@issue)
811 806 end
812 807
813 808 should "be false for a user with :only_owner and is not the author" do
814 809 @assignee.update_attribute(:mail_notification, 'only_owner')
815 810 assert ! @assignee.notify_about?(@issue)
816 811 end
817 812
818 813 should "be true for a user with :selected and is the author" do
819 814 @author.update_attribute(:mail_notification, 'selected')
820 815 assert @author.notify_about?(@issue)
821 816 end
822 817
823 818 should "be true for a user with :selected and is the assignee" do
824 819 @assignee.update_attribute(:mail_notification, 'selected')
825 820 assert @assignee.notify_about?(@issue)
826 821 end
827 822
828 823 should "be false for a user with :selected and is not the author or assignee" do
829 824 @user = User.generate_with_protected!(:mail_notification => 'selected')
830 825 Member.create!(:user => @user, :project => @project, :role_ids => [1])
831 826 assert ! @user.notify_about?(@issue)
832 827 end
833 828 end
834 829
835 830 context "other events" do
836 831 should 'be added and tested'
837 832 end
838 833 end
839 834
840 835 def test_salt_unsalted_passwords
841 836 # Restore a user with an unsalted password
842 837 user = User.find(1)
843 838 user.salt = nil
844 839 user.hashed_password = User.hash_password("unsalted")
845 840 user.save!
846 841
847 842 User.salt_unsalted_passwords!
848 843
849 844 user.reload
850 845 # Salt added
851 846 assert !user.salt.blank?
852 847 # Password still valid
853 848 assert user.check_password?("unsalted")
854 849 assert_equal user, User.try_to_login(user.login, "unsalted")
855 850 end
856 851
857 852 if Object.const_defined?(:OpenID)
858 853
859 854 def test_setting_identity_url
860 855 normalized_open_id_url = 'http://example.com/'
861 856 u = User.new( :identity_url => 'http://example.com/' )
862 857 assert_equal normalized_open_id_url, u.identity_url
863 858 end
864 859
865 860 def test_setting_identity_url_without_trailing_slash
866 861 normalized_open_id_url = 'http://example.com/'
867 862 u = User.new( :identity_url => 'http://example.com' )
868 863 assert_equal normalized_open_id_url, u.identity_url
869 864 end
870 865
871 866 def test_setting_identity_url_without_protocol
872 867 normalized_open_id_url = 'http://example.com/'
873 868 u = User.new( :identity_url => 'example.com' )
874 869 assert_equal normalized_open_id_url, u.identity_url
875 870 end
876 871
877 872 def test_setting_blank_identity_url
878 873 u = User.new( :identity_url => 'example.com' )
879 874 u.identity_url = ''
880 875 assert u.identity_url.blank?
881 876 end
882 877
883 878 def test_setting_invalid_identity_url
884 879 u = User.new( :identity_url => 'this is not an openid url' )
885 880 assert u.identity_url.blank?
886 881 end
887 882
888 883 else
889 884 puts "Skipping openid tests."
890 885 end
891 886
892 887 end
General Comments 0
You need to be logged in to leave comments. Login now