annotate test/unit/issue_test.rb @ 976:0befb332f41a get_statistics

get stats up to current date
author luisf <luis.figueira@eecs.qmul.ac.uk>
date Thu, 25 Oct 2012 13:50:45 +0100
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