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