annotate test/unit/issue_test.rb @ 1082:997f6d7738f7 bug_531

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