issue_test.rb
1184 lines
| 42.4 KiB
| text/x-ruby
|
RubyLexer
|
r4834 | # Redmine - project management software | ||
# Copyright (C) 2006-2011 Jean-Philippe Lang | ||||
|
r574 | # | ||
# This program is free software; you can redistribute it and/or | ||||
# modify it under the terms of the GNU General Public License | ||||
# as published by the Free Software Foundation; either version 2 | ||||
# of the License, or (at your option) any later version. | ||||
|
r5686 | # | ||
|
r574 | # This program is distributed in the hope that it will be useful, | ||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
# GNU General Public License for more details. | ||||
|
r5686 | # | ||
|
r574 | # You should have received a copy of the GNU General Public License | ||
# along with this program; if not, write to the Free Software | ||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||||
|
r4395 | require File.expand_path('../../test_helper', __FILE__) | ||
|
r574 | |||
|
r2773 | class IssueTest < ActiveSupport::TestCase | ||
|
r2925 | fixtures :projects, :users, :members, :member_roles, :roles, | ||
|
r1578 | :trackers, :projects_trackers, | ||
|
r3394 | :enabled_modules, | ||
|
r2906 | :versions, | ||
|
r5686 | :issue_statuses, :issue_categories, :issue_relations, :workflows, | ||
|
r1578 | :enumerations, | ||
:issues, | ||||
:custom_fields, :custom_fields_projects, :custom_fields_trackers, :custom_values, | ||||
:time_entries | ||||
|
r574 | |||
|
r1346 | def test_create | ||
|
r7356 | issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3, | ||
:status_id => 1, :priority => IssuePriority.all.first, | ||||
:subject => 'test_create', | ||||
:description => 'IssueTest#test_create', :estimated_hours => '1:30') | ||||
|
r1346 | assert issue.save | ||
issue.reload | ||||
assert_equal 1.5, issue.estimated_hours | ||||
end | ||||
|
r5686 | |||
|
r2244 | def test_create_minimal | ||
|
r7355 | issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3, | ||
:status_id => 1, :priority => IssuePriority.all.first, | ||||
:subject => 'test_create') | ||||
|
r2244 | assert issue.save | ||
assert issue.description.nil? | ||||
end | ||||
|
r5686 | |||
|
r1578 | def test_create_with_required_custom_field | ||
field = IssueCustomField.find_by_name('Database') | ||||
field.update_attribute(:is_required, true) | ||||
|
r5686 | |||
|
r7354 | issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, | ||
:status_id => 1, :subject => 'test_create', | ||||
:description => 'IssueTest#test_create_with_required_custom_field') | ||||
|
r1578 | assert issue.available_custom_fields.include?(field) | ||
# No value for the custom field | ||||
assert !issue.save | ||||
|
r8018 | assert_equal I18n.translate('activerecord.errors.messages.invalid'), | ||
issue.errors[:custom_values].to_s | ||||
|
r1578 | # Blank value | ||
issue.custom_field_values = { field.id => '' } | ||||
assert !issue.save | ||||
|
r8018 | assert_equal I18n.translate('activerecord.errors.messages.invalid'), | ||
issue.errors[:custom_values].to_s | ||||
|
r1578 | # Invalid value | ||
issue.custom_field_values = { field.id => 'SQLServer' } | ||||
assert !issue.save | ||||
|
r8018 | assert_equal I18n.translate('activerecord.errors.messages.invalid'), | ||
issue.errors[:custom_values].to_s | ||||
|
r1578 | # Valid value | ||
issue.custom_field_values = { field.id => 'PostgreSQL' } | ||||
assert issue.save | ||||
issue.reload | ||||
assert_equal 'PostgreSQL', issue.custom_value_for(field).value | ||||
end | ||||
|
r6626 | |||
|
r6186 | def test_create_with_group_assignment | ||
with_settings :issue_group_assignment => '1' do | ||||
|
r7357 | assert Issue.new(:project_id => 2, :tracker_id => 1, :author_id => 1, | ||
:subject => 'Group assignment', | ||||
:assigned_to_id => 11).save | ||||
|
r6186 | issue = Issue.first(:order => 'id DESC') | ||
assert_kind_of Group, issue.assigned_to | ||||
assert_equal Group.find(11), issue.assigned_to | ||||
end | ||||
end | ||||
|
r5686 | |||
|
r5296 | def assert_visibility_match(user, issues) | ||
assert_equal issues.collect(&:id).sort, Issue.all.select {|issue| issue.visible?(user)}.collect(&:id).sort | ||||
end | ||||
|
r2925 | def test_visible_scope_for_anonymous | ||
# Anonymous user should see issues of public projects only | ||||
issues = Issue.visible(User.anonymous).all | ||||
assert issues.any? | ||||
assert_nil issues.detect {|issue| !issue.project.is_public?} | ||||
|
r5346 | assert_nil issues.detect {|issue| issue.is_private?} | ||
|
r5296 | assert_visibility_match User.anonymous, issues | ||
end | ||||
|
r5686 | |||
|
r5296 | def test_visible_scope_for_anonymous_with_own_issues_visibility | ||
Role.anonymous.update_attribute :issues_visibility, 'own' | ||||
|
r7486 | Issue.create!(:project_id => 1, :tracker_id => 1, | ||
:author_id => User.anonymous.id, | ||||
:subject => 'Issue by anonymous') | ||||
|
r5686 | |||
|
r5296 | issues = Issue.visible(User.anonymous).all | ||
assert issues.any? | ||||
assert_nil issues.detect {|issue| issue.author != User.anonymous} | ||||
assert_visibility_match User.anonymous, issues | ||||
end | ||||
|
r5686 | |||
|
r5296 | def test_visible_scope_for_anonymous_without_view_issues_permissions | ||
|
r2925 | # Anonymous user should not see issues without permission | ||
Role.anonymous.remove_permission!(:view_issues) | ||||
issues = Issue.visible(User.anonymous).all | ||||
assert issues.empty? | ||||
|
r5296 | assert_visibility_match User.anonymous, issues | ||
|
r2925 | end | ||
|
r5686 | |||
|
r5296 | def test_visible_scope_for_non_member | ||
|
r2925 | user = User.find(9) | ||
assert user.projects.empty? | ||||
# Non member user should see issues of public projects only | ||||
issues = Issue.visible(user).all | ||||
assert issues.any? | ||||
assert_nil issues.detect {|issue| !issue.project.is_public?} | ||||
|
r5346 | assert_nil issues.detect {|issue| issue.is_private?} | ||
|
r5296 | assert_visibility_match user, issues | ||
end | ||||
|
r5686 | |||
|
r5296 | def test_visible_scope_for_non_member_with_own_issues_visibility | ||
Role.non_member.update_attribute :issues_visibility, 'own' | ||||
Issue.create!(:project_id => 1, :tracker_id => 1, :author_id => 9, :subject => 'Issue by non member') | ||||
user = User.find(9) | ||||
|
r5686 | |||
|
r5296 | issues = Issue.visible(user).all | ||
assert issues.any? | ||||
assert_nil issues.detect {|issue| issue.author != user} | ||||
assert_visibility_match user, issues | ||||
end | ||||
|
r5686 | |||
|
r5296 | def test_visible_scope_for_non_member_without_view_issues_permissions | ||
|
r2925 | # Non member user should not see issues without permission | ||
Role.non_member.remove_permission!(:view_issues) | ||||
|
r5296 | user = User.find(9) | ||
assert user.projects.empty? | ||||
|
r2925 | issues = Issue.visible(user).all | ||
assert issues.empty? | ||||
|
r5296 | assert_visibility_match user, issues | ||
end | ||||
|
r5686 | |||
|
r5296 | def test_visible_scope_for_member | ||
user = User.find(9) | ||||
|
r2925 | # User should see issues of projects for which he has view_issues permissions only | ||
|
r5296 | Role.non_member.remove_permission!(:view_issues) | ||
|
r5346 | Member.create!(:principal => user, :project_id => 3, :role_ids => [2]) | ||
|
r2925 | issues = Issue.visible(user).all | ||
assert issues.any? | ||||
|
r5346 | assert_nil issues.detect {|issue| issue.project_id != 3} | ||
assert_nil issues.detect {|issue| issue.is_private?} | ||||
|
r5296 | assert_visibility_match user, issues | ||
|
r2925 | end | ||
|
r5686 | |||
|
r7651 | def test_visible_scope_for_member_with_groups_should_return_assigned_issues | ||
user = User.find(8) | ||||
assert user.groups.any? | ||||
Member.create!(:principal => user.groups.first, :project_id => 1, :role_ids => [2]) | ||||
Role.non_member.remove_permission!(:view_issues) | ||||
issue = Issue.create(:project_id => 1, :tracker_id => 1, :author_id => 3, | ||||
:status_id => 1, :priority => IssuePriority.all.first, | ||||
:subject => 'Assignment test', | ||||
:assigned_to => user.groups.first, | ||||
:is_private => true) | ||||
Role.find(2).update_attribute :issues_visibility, 'default' | ||||
issues = Issue.visible(User.find(8)).all | ||||
assert issues.any? | ||||
assert issues.include?(issue) | ||||
Role.find(2).update_attribute :issues_visibility, 'own' | ||||
issues = Issue.visible(User.find(8)).all | ||||
assert issues.any? | ||||
assert issues.include?(issue) | ||||
end | ||||
|
r2925 | def test_visible_scope_for_admin | ||
user = User.find(1) | ||||
user.members.each(&:destroy) | ||||
assert user.projects.empty? | ||||
issues = Issue.visible(user).all | ||||
assert issues.any? | ||||
# Admin should see issues on private projects that he does not belong to | ||||
assert issues.detect {|issue| !issue.project.is_public?} | ||||
|
r5346 | # Admin should see private issues of other users | ||
assert issues.detect {|issue| issue.is_private? && issue.author != user} | ||||
|
r5296 | assert_visibility_match user, issues | ||
|
r2925 | end | ||
|
r5686 | |||
|
r5204 | def test_visible_scope_with_project | ||
project = Project.find(1) | ||||
issues = Issue.visible(User.find(2), :project => project).all | ||||
projects = issues.collect(&:project).uniq | ||||
assert_equal 1, projects.size | ||||
assert_equal project, projects.first | ||||
end | ||||
|
r5686 | |||
|
r5204 | def test_visible_scope_with_project_and_subprojects | ||
project = Project.find(1) | ||||
issues = Issue.visible(User.find(2), :project => project, :with_subprojects => true).all | ||||
projects = issues.collect(&:project).uniq | ||||
assert projects.size > 1 | ||||
assert_equal [], projects.select {|p| !p.is_or_is_descendant_of?(project)} | ||||
end | ||||
|
r5686 | |||
|
r5321 | def test_visible_and_nested_set_scopes | ||
assert_equal 0, Issue.find(1).descendants.visible.all.size | ||||
end | ||||
|
r5686 | |||
|
r8165 | def test_open_scope | ||
issues = Issue.open.all | ||||
assert_nil issues.detect(&:closed?) | ||||
end | ||||
def test_open_scope_with_arg | ||||
issues = Issue.open(false).all | ||||
assert_equal issues, issues.select(&:closed?) | ||||
end | ||||
|
r2454 | def test_errors_full_messages_should_include_custom_fields_errors | ||
field = IssueCustomField.find_by_name('Database') | ||||
|
r5686 | |||
|
r7353 | issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, | ||
:status_id => 1, :subject => 'test_create', | ||||
:description => 'IssueTest#test_create_with_required_custom_field') | ||||
|
r2454 | assert issue.available_custom_fields.include?(field) | ||
# Invalid value | ||||
issue.custom_field_values = { field.id => 'SQLServer' } | ||||
|
r5686 | |||
|
r2454 | assert !issue.valid? | ||
assert_equal 1, issue.errors.full_messages.size | ||||
|
r7485 | assert_equal "Database #{I18n.translate('activerecord.errors.messages.inclusion')}", | ||
issue.errors.full_messages.first | ||||
|
r2454 | end | ||
|
r5686 | |||
|
r1578 | def test_update_issue_with_required_custom_field | ||
field = IssueCustomField.find_by_name('Database') | ||||
field.update_attribute(:is_required, true) | ||||
|
r5686 | |||
|
r1578 | issue = Issue.find(1) | ||
assert_nil issue.custom_value_for(field) | ||||
assert issue.available_custom_fields.include?(field) | ||||
# No change to custom values, issue can be saved | ||||
assert issue.save | ||||
# Blank value | ||||
issue.custom_field_values = { field.id => '' } | ||||
assert !issue.save | ||||
# Valid value | ||||
issue.custom_field_values = { field.id => 'PostgreSQL' } | ||||
assert issue.save | ||||
issue.reload | ||||
assert_equal 'PostgreSQL', issue.custom_value_for(field).value | ||||
end | ||||
|
r5686 | |||
|
r1578 | def test_should_not_update_attributes_if_custom_fields_validation_fails | ||
issue = Issue.find(1) | ||||
field = IssueCustomField.find_by_name('Database') | ||||
assert issue.available_custom_fields.include?(field) | ||||
|
r5686 | |||
|
r1578 | issue.custom_field_values = { field.id => 'Invalid' } | ||
issue.subject = 'Should be not be saved' | ||||
assert !issue.save | ||||
|
r5686 | |||
|
r1578 | issue.reload | ||
assert_equal "Can't print recipes", issue.subject | ||||
end | ||||
|
r5686 | |||
|
r1578 | def test_should_not_recreate_custom_values_objects_on_update | ||
field = IssueCustomField.find_by_name('Database') | ||||
|
r5686 | |||
|
r1578 | issue = Issue.find(1) | ||
issue.custom_field_values = { field.id => 'PostgreSQL' } | ||||
assert issue.save | ||||
custom_value = issue.custom_value_for(field) | ||||
issue.reload | ||||
issue.custom_field_values = { field.id => 'MySQL' } | ||||
assert issue.save | ||||
issue.reload | ||||
assert_equal custom_value.id, issue.custom_value_for(field).id | ||||
end | ||||
|
r5686 | |||
|
r7983 | def test_should_not_update_custom_fields_on_changing_tracker_with_different_custom_fields | ||
|
r8011 | issue = Issue.create!(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :subject => 'Test', :custom_field_values => {'2' => 'Test'}) | ||
|
r7983 | assert !Tracker.find(2).custom_field_ids.include?(2) | ||
issue = Issue.find(issue.id) | ||||
issue.attributes = {:tracker_id => 2, :custom_field_values => {'1' => ''}} | ||||
issue = Issue.find(issue.id) | ||||
custom_value = issue.custom_value_for(2) | ||||
assert_not_nil custom_value | ||||
assert_equal 'Test', custom_value.value | ||||
end | ||||
|
r3025 | def test_assigning_tracker_id_should_reload_custom_fields_values | ||
issue = Issue.new(:project => Project.find(1)) | ||||
assert issue.custom_field_values.empty? | ||||
issue.tracker_id = 1 | ||||
assert issue.custom_field_values.any? | ||||
end | ||||
|
r5686 | |||
|
r8011 | def test_assigning_attributes_should_assign_project_and_tracker_first | ||
seq = sequence('seq') | ||||
issue = Issue.new | ||||
issue.expects(:project_id=).in_sequence(seq) | ||||
issue.expects(:tracker_id=).in_sequence(seq) | ||||
issue.expects(:subject=).in_sequence(seq) | ||||
issue.attributes = {:tracker_id => 2, :project_id => 1, :subject => 'Test'} | ||||
end | ||||
def test_assigning_tracker_and_custom_fields_should_assign_custom_fields | ||||
|
r3025 | attributes = ActiveSupport::OrderedHash.new | ||
attributes['custom_field_values'] = { '1' => 'MySQL' } | ||||
attributes['tracker_id'] = '1' | ||||
issue = Issue.new(:project => Project.find(1)) | ||||
issue.attributes = attributes | ||||
assert_not_nil issue.custom_value_for(1) | ||||
assert_equal 'MySQL', issue.custom_value_for(1).value | ||||
end | ||||
|
r5686 | |||
|
r2994 | def test_should_update_issue_with_disabled_tracker | ||
p = Project.find(1) | ||||
issue = Issue.find(1) | ||||
|
r5686 | |||
|
r2994 | p.trackers.delete(issue.tracker) | ||
assert !p.trackers.include?(issue.tracker) | ||||
|
r5686 | |||
|
r2994 | issue.reload | ||
issue.subject = 'New subject' | ||||
assert issue.save | ||||
end | ||||
|
r5686 | |||
|
r2994 | def test_should_not_set_a_disabled_tracker | ||
p = Project.find(1) | ||||
p.trackers.delete(Tracker.find(2)) | ||||
|
r5686 | |||
|
r2994 | issue = Issue.find(1) | ||
issue.tracker_id = 2 | ||||
issue.subject = 'New subject' | ||||
assert !issue.save | ||||
|
r7484 | assert_not_nil issue.errors[:tracker_id] | ||
|
r2994 | end | ||
|
r5686 | |||
|
r574 | def test_category_based_assignment | ||
|
r7352 | issue = Issue.create(:project_id => 1, :tracker_id => 1, :author_id => 3, | ||
:status_id => 1, :priority => IssuePriority.all.first, | ||||
:subject => 'Assignment test', | ||||
:description => 'Assignment test', :category_id => 1) | ||||
|
r574 | assert_equal IssueCategory.find(1).assigned_to, issue.assigned_to | ||
end | ||||
|
r5686 | |||
|
r4775 | def test_new_statuses_allowed_to | ||
Workflow.delete_all | ||||
|
r5686 | |||
|
r4775 | Workflow.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 2, :author => false, :assignee => false) | ||
Workflow.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 3, :author => true, :assignee => false) | ||||
Workflow.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 4, :author => false, :assignee => true) | ||||
Workflow.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 5, :author => true, :assignee => true) | ||||
status = IssueStatus.find(1) | ||||
role = Role.find(1) | ||||
tracker = Tracker.find(1) | ||||
user = User.find(2) | ||||
|
r5686 | |||
|
r4775 | issue = Issue.generate!(:tracker => tracker, :status => status, :project_id => 1) | ||
assert_equal [1, 2], issue.new_statuses_allowed_to(user).map(&:id) | ||||
|
r5686 | |||
|
r4775 | issue = Issue.generate!(:tracker => tracker, :status => status, :project_id => 1, :author => user) | ||
|
r6182 | assert_equal [1, 2, 3, 5], issue.new_statuses_allowed_to(user).map(&:id) | ||
|
r5686 | |||
|
r4775 | issue = Issue.generate!(:tracker => tracker, :status => status, :project_id => 1, :assigned_to => user) | ||
|
r6182 | assert_equal [1, 2, 4, 5], issue.new_statuses_allowed_to(user).map(&:id) | ||
|
r5686 | |||
|
r4775 | issue = Issue.generate!(:tracker => tracker, :status => status, :project_id => 1, :author => user, :assigned_to => user) | ||
assert_equal [1, 2, 3, 4, 5], issue.new_statuses_allowed_to(user).map(&:id) | ||||
end | ||||
|
r5686 | |||
|
r860 | def test_copy | ||
issue = Issue.new.copy_from(1) | ||||
assert issue.save | ||||
issue.reload | ||||
orig = Issue.find(1) | ||||
assert_equal orig.subject, issue.subject | ||||
assert_equal orig.tracker, issue.tracker | ||||
|
r3100 | assert_equal "125", issue.custom_value_for(2).value | ||
|
r860 | end | ||
|
r2961 | |||
def test_copy_should_copy_status | ||||
orig = Issue.find(8) | ||||
assert orig.status != IssueStatus.default | ||||
|
r5686 | |||
|
r2961 | issue = Issue.new.copy_from(orig) | ||
assert issue.save | ||||
issue.reload | ||||
assert_equal orig.status, issue.status | ||||
end | ||||
|
r5686 | |||
|
r8404 | def test_should_not_call_after_project_change_on_creation | ||
issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1, :subject => 'Test', :author_id => 1) | ||||
issue.expects(:after_project_change).never | ||||
issue.save! | ||||
end | ||||
def test_should_not_call_after_project_change_on_update | ||||
issue = Issue.find(1) | ||||
issue.project = Project.find(1) | ||||
issue.subject = 'No project change' | ||||
issue.expects(:after_project_change).never | ||||
issue.save! | ||||
end | ||||
def test_should_call_after_project_change_on_project_change | ||||
issue = Issue.find(1) | ||||
issue.project = Project.find(2) | ||||
issue.expects(:after_project_change).once | ||||
issue.save! | ||||
end | ||||
|
r1474 | def test_should_close_duplicates | ||
|
r657 | # Create 3 issues | ||
|
r8174 | project = Project.find(1) | ||
issue1 = Issue.generate_for_project!(project) | ||||
issue2 = Issue.generate_for_project!(project) | ||||
issue3 = Issue.generate_for_project!(project) | ||||
|
r5686 | |||
|
r657 | # 2 is a dupe of 1 | ||
|
r8174 | IssueRelation.create!(:issue_from => issue2, :issue_to => issue1, :relation_type => IssueRelation::TYPE_DUPLICATES) | ||
|
r657 | # And 3 is a dupe of 2 | ||
|
r8174 | IssueRelation.create!(:issue_from => issue3, :issue_to => issue2, :relation_type => IssueRelation::TYPE_DUPLICATES) | ||
|
r1345 | # And 3 is a dupe of 1 (circular duplicates) | ||
|
r8174 | IssueRelation.create!(:issue_from => issue3, :issue_to => issue1, :relation_type => IssueRelation::TYPE_DUPLICATES) | ||
|
r5686 | |||
|
r657 | assert issue1.reload.duplicates.include?(issue2) | ||
|
r5686 | |||
|
r657 | # Closing issue 1 | ||
issue1.init_journal(User.find(:first), "Closing issue1") | ||||
issue1.status = IssueStatus.find :first, :conditions => {:is_closed => true} | ||||
assert issue1.save | ||||
# 2 and 3 should be also closed | ||||
assert issue2.reload.closed? | ||||
|
r5686 | assert issue3.reload.closed? | ||
|
r657 | end | ||
|
r5686 | |||
|
r1474 | def test_should_not_close_duplicated_issue | ||
|
r8175 | project = Project.find(1) | ||
issue1 = Issue.generate_for_project!(project) | ||||
issue2 = Issue.generate_for_project!(project) | ||||
|
r5686 | |||
|
r1474 | # 2 is a dupe of 1 | ||
IssueRelation.create(:issue_from => issue2, :issue_to => issue1, :relation_type => IssueRelation::TYPE_DUPLICATES) | ||||
# 2 is a dup of 1 but 1 is not a duplicate of 2 | ||||
assert !issue2.reload.duplicates.include?(issue1) | ||||
|
r5686 | |||
|
r1474 | # Closing issue 2 | ||
issue2.init_journal(User.find(:first), "Closing issue2") | ||||
issue2.status = IssueStatus.find :first, :conditions => {:is_closed => true} | ||||
assert issue2.save | ||||
# 1 should not be also closed | ||||
assert !issue1.reload.closed? | ||||
end | ||||
|
r5686 | |||
|
r2906 | def test_assignable_versions | ||
issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :fixed_version_id => 1, :subject => 'New issue') | ||||
assert_equal ['open'], issue.assignable_versions.collect(&:status).uniq | ||||
end | ||||
|
r5686 | |||
|
r2906 | def test_should_not_be_able_to_assign_a_new_issue_to_a_closed_version | ||
issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :fixed_version_id => 1, :subject => 'New issue') | ||||
assert !issue.save | ||||
|
r7489 | assert_not_nil issue.errors[:fixed_version_id] | ||
|
r2906 | end | ||
|
r5686 | |||
|
r2906 | def test_should_not_be_able_to_assign_a_new_issue_to_a_locked_version | ||
issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :fixed_version_id => 2, :subject => 'New issue') | ||||
assert !issue.save | ||||
|
r7490 | assert_not_nil issue.errors[:fixed_version_id] | ||
|
r2906 | end | ||
|
r5686 | |||
|
r2906 | def test_should_be_able_to_assign_a_new_issue_to_an_open_version | ||
issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :fixed_version_id => 3, :subject => 'New issue') | ||||
assert issue.save | ||||
end | ||||
|
r5686 | |||
|
r2906 | def test_should_be_able_to_update_an_issue_assigned_to_a_closed_version | ||
issue = Issue.find(11) | ||||
assert_equal 'closed', issue.fixed_version.status | ||||
issue.subject = 'Subject changed' | ||||
assert issue.save | ||||
end | ||||
|
r5686 | |||
|
r2906 | def test_should_not_be_able_to_reopen_an_issue_assigned_to_a_closed_version | ||
issue = Issue.find(11) | ||||
issue.status_id = 1 | ||||
assert !issue.save | ||||
|
r7491 | assert_not_nil issue.errors[:base] | ||
|
r2906 | end | ||
|
r5686 | |||
|
r2906 | def test_should_be_able_to_reopen_and_reassign_an_issue_assigned_to_a_closed_version | ||
issue = Issue.find(11) | ||||
issue.status_id = 1 | ||||
issue.fixed_version_id = 3 | ||||
assert issue.save | ||||
end | ||||
|
r5686 | |||
|
r2906 | def test_should_be_able_to_reopen_an_issue_assigned_to_a_locked_version | ||
issue = Issue.find(12) | ||||
assert_equal 'locked', issue.fixed_version.status | ||||
issue.status_id = 1 | ||||
assert issue.save | ||||
end | ||||
|
r5686 | |||
|
r1688 | def test_move_to_another_project_with_same_category | ||
|
r896 | issue = Issue.find(1) | ||
|
r3459 | assert issue.move_to_project(Project.find(2)) | ||
|
r896 | issue.reload | ||
assert_equal 2, issue.project_id | ||||
|
r1688 | # Category changes | ||
assert_equal 4, issue.category_id | ||||
|
r896 | # Make sure time entries were move to the target project | ||
assert_equal 2, issue.time_entries.first.project_id | ||||
end | ||||
|
r5686 | |||
|
r1688 | def test_move_to_another_project_without_same_category | ||
issue = Issue.find(2) | ||||
|
r3459 | assert issue.move_to_project(Project.find(2)) | ||
|
r1688 | issue.reload | ||
assert_equal 2, issue.project_id | ||||
# Category cleared | ||||
assert_nil issue.category_id | ||||
end | ||||
|
r5686 | |||
|
r3009 | def test_move_to_another_project_should_clear_fixed_version_when_not_shared | ||
issue = Issue.find(1) | ||||
issue.update_attribute(:fixed_version_id, 1) | ||||
|
r3459 | assert issue.move_to_project(Project.find(2)) | ||
|
r3009 | issue.reload | ||
assert_equal 2, issue.project_id | ||||
# Cleared fixed_version | ||||
assert_equal nil, issue.fixed_version | ||||
end | ||||
|
r5686 | |||
|
r3009 | def test_move_to_another_project_should_keep_fixed_version_when_shared_with_the_target_project | ||
issue = Issue.find(1) | ||||
issue.update_attribute(:fixed_version_id, 4) | ||||
|
r3459 | assert issue.move_to_project(Project.find(5)) | ||
|
r3009 | issue.reload | ||
assert_equal 5, issue.project_id | ||||
# Keep fixed_version | ||||
assert_equal 4, issue.fixed_version_id | ||||
end | ||||
|
r5686 | |||
|
r3009 | def test_move_to_another_project_should_clear_fixed_version_when_not_shared_with_the_target_project | ||
issue = Issue.find(1) | ||||
issue.update_attribute(:fixed_version_id, 1) | ||||
|
r3459 | assert issue.move_to_project(Project.find(5)) | ||
|
r3009 | issue.reload | ||
assert_equal 5, issue.project_id | ||||
# Cleared fixed_version | ||||
assert_equal nil, issue.fixed_version | ||||
end | ||||
|
r5686 | |||
|
r3009 | def test_move_to_another_project_should_keep_fixed_version_when_shared_systemwide | ||
issue = Issue.find(1) | ||||
issue.update_attribute(:fixed_version_id, 7) | ||||
|
r3459 | assert issue.move_to_project(Project.find(2)) | ||
|
r3009 | issue.reload | ||
assert_equal 2, issue.project_id | ||||
# Keep fixed_version | ||||
assert_equal 7, issue.fixed_version_id | ||||
end | ||||
|
r5686 | |||
|
r3452 | def test_move_to_another_project_with_disabled_tracker | ||
issue = Issue.find(1) | ||||
target = Project.find(2) | ||||
target.tracker_ids = [3] | ||||
target.save | ||||
|
r3459 | assert_equal false, issue.move_to_project(target) | ||
|
r3452 | issue.reload | ||
assert_equal 1, issue.project_id | ||||
end | ||||
|
r5686 | |||
|
r2311 | def test_copy_to_the_same_project | ||
issue = Issue.find(1) | ||||
copy = nil | ||||
assert_difference 'Issue.count' do | ||||
|
r3459 | copy = issue.move_to_project(issue.project, nil, :copy => true) | ||
|
r2311 | end | ||
assert_kind_of Issue, copy | ||||
assert_equal issue.project, copy.project | ||||
assert_equal "125", copy.custom_value_for(2).value | ||||
end | ||||
|
r5686 | |||
|
r2311 | def test_copy_to_another_project_and_tracker | ||
issue = Issue.find(1) | ||||
copy = nil | ||||
assert_difference 'Issue.count' do | ||||
|
r3459 | copy = issue.move_to_project(Project.find(3), Tracker.find(2), :copy => true) | ||
|
r2311 | end | ||
|
r3459 | copy.reload | ||
|
r2311 | assert_kind_of Issue, copy | ||
assert_equal Project.find(3), copy.project | ||||
assert_equal Tracker.find(2), copy.tracker | ||||
# Custom field #2 is not associated with target tracker | ||||
assert_nil copy.custom_value_for(2) | ||||
end | ||||
|
r3008 | |||
|
r3459 | context "#move_to_project" do | ||
|
r3008 | context "as a copy" do | ||
setup do | ||||
@issue = Issue.find(1) | ||||
@copy = nil | ||||
end | ||||
|
r5686 | |||
|
r5482 | should "not create a journal" do | ||
@copy = @issue.move_to_project(Project.find(3), Tracker.find(2), {:copy => true, :attributes => {:assigned_to_id => 3}}) | ||||
assert_equal 0, @copy.reload.journals.size | ||||
end | ||||
|
r3008 | |||
should "allow assigned_to changes" do | ||||
|
r3459 | @copy = @issue.move_to_project(Project.find(3), Tracker.find(2), {:copy => true, :attributes => {:assigned_to_id => 3}}) | ||
|
r3008 | assert_equal 3, @copy.assigned_to_id | ||
end | ||||
should "allow status changes" do | ||||
|
r3459 | @copy = @issue.move_to_project(Project.find(3), Tracker.find(2), {:copy => true, :attributes => {:status_id => 2}}) | ||
|
r3008 | assert_equal 2, @copy.status_id | ||
end | ||||
should "allow start date changes" do | ||||
date = Date.today | ||||
|
r3459 | @copy = @issue.move_to_project(Project.find(3), Tracker.find(2), {:copy => true, :attributes => {:start_date => date}}) | ||
|
r3008 | assert_equal date, @copy.start_date | ||
end | ||||
should "allow due date changes" do | ||||
date = Date.today | ||||
|
r3459 | @copy = @issue.move_to_project(Project.find(3), Tracker.find(2), {:copy => true, :attributes => {:due_date => date}}) | ||
|
r3008 | |||
assert_equal date, @copy.due_date | ||||
end | ||||
|
r5686 | |||
|
r5481 | should "set current user as author" do | ||
User.current = User.find(9) | ||||
@copy = @issue.move_to_project(Project.find(3), Tracker.find(2), {:copy => true, :attributes => {}}) | ||||
assert_equal User.current, @copy.author | ||||
end | ||||
|
r5686 | |||
|
r8092 | should "create a journal with notes" do | ||
|
r5482 | date = Date.today | ||
notes = "Notes added when copying" | ||||
|
r8092 | @copy = @issue.move_to_project(Project.find(3), Tracker.find(2), {:copy => true, :notes => notes, :attributes => {:start_date => date}}) | ||
|
r5482 | |||
assert_equal 1, @copy.journals.size | ||||
journal = @copy.journals.first | ||||
assert_equal 0, journal.details.size | ||||
assert_equal notes, journal.notes | ||||
end | ||||
|
r3008 | end | ||
end | ||||
|
r5686 | |||
|
r3007 | def test_recipients_should_not_include_users_that_cannot_view_the_issue | ||
issue = Issue.find(12) | ||||
assert issue.recipients.include?(issue.author.mail) | ||||
# move the issue to a private project | ||||
|
r3459 | copy = issue.move_to_project(Project.find(5), Tracker.find(2), :copy => true) | ||
|
r3007 | # author is not a member of project anymore | ||
assert !copy.recipients.include?(copy.author.mail) | ||||
end | ||||
|
r6626 | |||
|
r6186 | def test_recipients_should_include_the_assigned_group_members | ||
group_member = User.generate_with_protected! | ||||
group = Group.generate! | ||||
group.users << group_member | ||||
|
r6626 | |||
|
r6186 | issue = Issue.find(12) | ||
issue.assigned_to = group | ||||
assert issue.recipients.include?(group_member.mail) | ||||
end | ||||
|
r3007 | |||
def test_watcher_recipients_should_not_include_users_that_cannot_view_the_issue | ||||
user = User.find(3) | ||||
issue = Issue.find(9) | ||||
Watcher.create!(:user => user, :watchable => issue) | ||||
assert issue.watched_by?(user) | ||||
assert !issue.watcher_recipients.include?(user.mail) | ||||
end | ||||
|
r5686 | |||
|
r1168 | def test_issue_destroy | ||
Issue.find(1).destroy | ||||
assert_nil Issue.find_by_id(1) | ||||
assert_nil TimeEntry.find_by_issue_id(1) | ||||
end | ||||
|
r5686 | |||
|
r2700 | def test_blocked | ||
blocked_issue = Issue.find(9) | ||||
blocking_issue = Issue.find(10) | ||||
|
r5686 | |||
|
r2700 | assert blocked_issue.blocked? | ||
assert !blocking_issue.blocked? | ||||
end | ||||
|
r5686 | |||
|
r2700 | def test_blocked_issues_dont_allow_closed_statuses | ||
blocked_issue = Issue.find(9) | ||||
|
r5686 | |||
|
r2700 | allowed_statuses = blocked_issue.new_statuses_allowed_to(users(:users_002)) | ||
assert !allowed_statuses.empty? | ||||
closed_statuses = allowed_statuses.select {|st| st.is_closed?} | ||||
assert closed_statuses.empty? | ||||
end | ||||
|
r5686 | |||
|
r2700 | def test_unblocked_issues_allow_closed_statuses | ||
blocking_issue = Issue.find(10) | ||||
|
r5686 | |||
|
r2700 | allowed_statuses = blocking_issue.new_statuses_allowed_to(users(:users_002)) | ||
assert !allowed_statuses.empty? | ||||
closed_statuses = allowed_statuses.select {|st| st.is_closed?} | ||||
assert !closed_statuses.empty? | ||||
end | ||||
|
r5686 | |||
|
r4149 | def test_rescheduling_an_issue_should_reschedule_following_issue | ||
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) | ||||
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) | ||||
IssueRelation.create!(:issue_from => issue1, :issue_to => issue2, :relation_type => IssueRelation::TYPE_PRECEDES) | ||||
assert_equal issue1.due_date + 1, issue2.reload.start_date | ||||
|
r5686 | |||
|
r4149 | issue1.due_date = Date.today + 5 | ||
issue1.save! | ||||
assert_equal issue1.due_date + 1, issue2.reload.start_date | ||||
end | ||||
|
r5686 | |||
|
r2138 | def test_overdue | ||
|
r2139 | assert Issue.new(:due_date => 1.day.ago.to_date).overdue? | ||
|
r2138 | assert !Issue.new(:due_date => Date.today).overdue? | ||
|
r2139 | assert !Issue.new(:due_date => 1.day.from_now.to_date).overdue? | ||
|
r2138 | assert !Issue.new(:due_date => nil).overdue? | ||
|
r2357 | assert !Issue.new(:due_date => 1.day.ago.to_date, :status => IssueStatus.find(:first, :conditions => {:is_closed => true})).overdue? | ||
|
r2138 | end | ||
|
r3958 | |||
context "#behind_schedule?" do | ||||
should "be false if the issue has no start_date" do | ||||
assert !Issue.new(:start_date => nil, :due_date => 1.day.from_now.to_date, :done_ratio => 0).behind_schedule? | ||||
end | ||||
should "be false if the issue has no end_date" do | ||||
assert !Issue.new(:start_date => 1.day.from_now.to_date, :due_date => nil, :done_ratio => 0).behind_schedule? | ||||
end | ||||
should "be false if the issue has more done than it's calendar time" do | ||||
assert !Issue.new(:start_date => 50.days.ago.to_date, :due_date => 50.days.from_now.to_date, :done_ratio => 90).behind_schedule? | ||||
end | ||||
should "be true if the issue hasn't been started at all" do | ||||
assert Issue.new(:start_date => 1.day.ago.to_date, :due_date => 1.day.from_now.to_date, :done_ratio => 0).behind_schedule? | ||||
end | ||||
should "be true if the issue has used more calendar time than it's done ratio" do | ||||
assert Issue.new(:start_date => 100.days.ago.to_date, :due_date => Date.today, :done_ratio => 90).behind_schedule? | ||||
end | ||||
end | ||||
|
r4126 | |||
context "#assignable_users" do | ||||
should "be Users" do | ||||
assert_kind_of User, Issue.find(1).assignable_users.first | ||||
end | ||||
should "include the issue author" do | ||||
project = Project.find(1) | ||||
non_project_member = User.generate! | ||||
issue = Issue.generate_for_project!(project, :author => non_project_member) | ||||
assert issue.assignable_users.include?(non_project_member) | ||||
end | ||||
|
r4127 | |||
|
r6188 | should "include the current assignee" do | ||
project = Project.find(1) | ||||
user = User.generate! | ||||
issue = Issue.generate_for_project!(project, :assigned_to => user) | ||||
user.lock! | ||||
assert Issue.find(issue.id).assignable_users.include?(user) | ||||
end | ||||
|
r4127 | should "not show the issue author twice" do | ||
assignable_user_ids = Issue.find(1).assignable_users.collect(&:id) | ||||
assert_equal 2, assignable_user_ids.length | ||||
|
r5686 | |||
|
r4127 | assignable_user_ids.each do |user_id| | ||
|
r4294 | assert_equal 1, assignable_user_ids.select {|i| i == user_id}.length, "User #{user_id} appears more or less than once" | ||
|
r4127 | end | ||
end | ||||
|
r6626 | |||
|
r6186 | context "with issue_group_assignment" do | ||
should "include groups" do | ||||
issue = Issue.new(:project => Project.find(2)) | ||||
|
r6626 | |||
|
r6186 | with_settings :issue_group_assignment => '1' do | ||
assert_equal %w(Group User), issue.assignable_users.map {|a| a.class.name}.uniq.sort | ||||
assert issue.assignable_users.include?(Group.find(11)) | ||||
end | ||||
end | ||||
end | ||||
|
r6626 | |||
|
r6186 | context "without issue_group_assignment" do | ||
should "not include groups" do | ||||
issue = Issue.new(:project => Project.find(2)) | ||||
|
r6626 | |||
|
r6186 | with_settings :issue_group_assignment => '0' do | ||
assert_equal %w(User), issue.assignable_users.map {|a| a.class.name}.uniq.sort | ||||
assert !issue.assignable_users.include?(Group.find(11)) | ||||
end | ||||
end | ||||
end | ||||
|
r2627 | end | ||
|
r5686 | |||
|
r2548 | def test_create_should_send_email_notification | ||
ActionMailer::Base.deliveries.clear | ||||
|
r7359 | issue = Issue.new(:project_id => 1, :tracker_id => 1, | ||
:author_id => 3, :status_id => 1, | ||||
:priority => IssuePriority.all.first, | ||||
:subject => 'test_create', :estimated_hours => '1:30') | ||||
|
r2548 | |||
assert issue.save | ||||
assert_equal 1, ActionMailer::Base.deliveries.size | ||||
end | ||||
|
r4103 | |||
|
r2577 | def test_stale_issue_should_not_send_email_notification | ||
ActionMailer::Base.deliveries.clear | ||||
issue = Issue.find(1) | ||||
stale = Issue.find(1) | ||||
|
r5686 | |||
|
r2577 | issue.init_journal(User.find(1)) | ||
issue.subject = 'Subjet update' | ||||
assert issue.save | ||||
assert_equal 1, ActionMailer::Base.deliveries.size | ||||
ActionMailer::Base.deliveries.clear | ||||
|
r5686 | |||
|
r2577 | stale.init_journal(User.find(1)) | ||
stale.subject = 'Another subjet update' | ||||
assert_raise ActiveRecord::StaleObjectError do | ||||
stale.save | ||||
end | ||||
assert ActionMailer::Base.deliveries.empty? | ||||
end | ||||
|
r5686 | |||
|
r4834 | def test_journalized_description | ||
|
r4838 | IssueCustomField.delete_all | ||
|
r5686 | |||
|
r4834 | i = Issue.first | ||
old_description = i.description | ||||
new_description = "This is the new description" | ||||
|
r5686 | |||
|
r4834 | i.init_journal(User.find(2)) | ||
i.description = new_description | ||||
assert_difference 'Journal.count', 1 do | ||||
assert_difference 'JournalDetail.count', 1 do | ||||
i.save! | ||||
end | ||||
end | ||||
|
r5686 | |||
|
r4834 | detail = JournalDetail.first(:order => 'id DESC') | ||
assert_equal i, detail.journal.journalized | ||||
assert_equal 'attr', detail.property | ||||
assert_equal 'description', detail.prop_key | ||||
assert_equal old_description, detail.old_value | ||||
assert_equal new_description, detail.value | ||||
end | ||||
|
r6626 | |||
|
r6027 | def test_blank_descriptions_should_not_be_journalized | ||
IssueCustomField.delete_all | ||||
Issue.update_all("description = NULL", "id=1") | ||||
|
r6626 | |||
|
r6029 | i = Issue.find(1) | ||
|
r6027 | i.init_journal(User.find(2)) | ||
i.subject = "blank description" | ||||
i.description = "\r\n" | ||||
|
r6626 | |||
|
r6027 | assert_difference 'Journal.count', 1 do | ||
assert_difference 'JournalDetail.count', 1 do | ||||
i.save! | ||||
end | ||||
end | ||||
end | ||||
|
r6626 | |||
|
r6029 | def test_description_eol_should_be_normalized | ||
i = Issue.new(:description => "CR \r LF \n CRLF \r\n") | ||||
assert_equal "CR \r\n LF \r\n CRLF \r\n", i.description | ||||
end | ||||
|
r5686 | |||
|
r3385 | def test_saving_twice_should_not_duplicate_journal_details | ||
i = Issue.find(:first) | ||||
i.init_journal(User.find(2), 'Some notes') | ||||
|
r3395 | # initial changes | ||
|
r3385 | i.subject = 'New subject' | ||
i.done_ratio = i.done_ratio + 10 | ||||
assert_difference 'Journal.count' do | ||||
|
r3395 | assert i.save | ||
|
r3385 | end | ||
# 1 more change | ||||
i.priority = IssuePriority.find(:first, :conditions => ["id <> ?", i.priority_id]) | ||||
assert_no_difference 'Journal.count' do | ||||
assert_difference 'JournalDetail.count', 1 do | ||||
i.save | ||||
end | ||||
end | ||||
# no more change | ||||
assert_no_difference 'Journal.count' do | ||||
assert_no_difference 'JournalDetail.count' do | ||||
i.save | ||||
end | ||||
end | ||||
end | ||||
|
r3037 | |||
|
r4603 | def test_all_dependent_issues | ||
IssueRelation.delete_all | ||||
|
r7358 | assert IssueRelation.create!(:issue_from => Issue.find(1), | ||
:issue_to => Issue.find(2), | ||||
:relation_type => IssueRelation::TYPE_PRECEDES) | ||||
assert IssueRelation.create!(:issue_from => Issue.find(2), | ||||
:issue_to => Issue.find(3), | ||||
:relation_type => IssueRelation::TYPE_PRECEDES) | ||||
assert IssueRelation.create!(:issue_from => Issue.find(3), | ||||
:issue_to => Issue.find(8), | ||||
:relation_type => IssueRelation::TYPE_PRECEDES) | ||||
|
r5686 | |||
|
r4603 | assert_equal [2, 3, 8], Issue.find(1).all_dependent_issues.collect(&:id).sort | ||
end | ||||
def test_all_dependent_issues_with_persistent_circular_dependency | ||||
IssueRelation.delete_all | ||||
|
r7341 | assert IssueRelation.create!(:issue_from => Issue.find(1), | ||
:issue_to => Issue.find(2), | ||||
:relation_type => IssueRelation::TYPE_PRECEDES) | ||||
assert IssueRelation.create!(:issue_from => Issue.find(2), | ||||
:issue_to => Issue.find(3), | ||||
:relation_type => IssueRelation::TYPE_PRECEDES) | ||||
|
r4603 | # Validation skipping | ||
|
r7341 | assert IssueRelation.new(:issue_from => Issue.find(3), | ||
:issue_to => Issue.find(1), | ||||
:relation_type => IssueRelation::TYPE_PRECEDES).save(false) | ||||
|
r5686 | |||
|
r4603 | assert_equal [2, 3], Issue.find(1).all_dependent_issues.collect(&:id).sort | ||
end | ||||
|
r4984 | |||
def test_all_dependent_issues_with_persistent_multiple_circular_dependencies | ||||
IssueRelation.delete_all | ||||
|
r7342 | assert IssueRelation.create!(:issue_from => Issue.find(1), | ||
:issue_to => Issue.find(2), | ||||
:relation_type => IssueRelation::TYPE_RELATES) | ||||
assert IssueRelation.create!(:issue_from => Issue.find(2), | ||||
:issue_to => Issue.find(3), | ||||
:relation_type => IssueRelation::TYPE_RELATES) | ||||
assert IssueRelation.create!(:issue_from => Issue.find(3), | ||||
:issue_to => Issue.find(8), | ||||
:relation_type => IssueRelation::TYPE_RELATES) | ||||
|
r4984 | # Validation skipping | ||
|
r7342 | assert IssueRelation.new(:issue_from => Issue.find(8), | ||
:issue_to => Issue.find(2), | ||||
:relation_type => IssueRelation::TYPE_RELATES).save(false) | ||||
assert IssueRelation.new(:issue_from => Issue.find(3), | ||||
:issue_to => Issue.find(1), | ||||
:relation_type => IssueRelation::TYPE_RELATES).save(false) | ||||
|
r5686 | |||
|
r4984 | assert_equal [2, 3, 8], Issue.find(1).all_dependent_issues.collect(&:id).sort | ||
end | ||||
|
r5686 | |||
|
r3037 | context "#done_ratio" do | ||
setup do | ||||
@issue = Issue.find(1) | ||||
@issue_status = IssueStatus.find(1) | ||||
@issue_status.update_attribute(:default_done_ratio, 50) | ||||
|
r4072 | @issue2 = Issue.find(2) | ||
@issue_status2 = IssueStatus.find(2) | ||||
@issue_status2.update_attribute(:default_done_ratio, 0) | ||||
|
r3037 | end | ||
|
r5686 | |||
|
r8106 | teardown do | ||
Setting.issue_done_ratio = 'issue_field' | ||||
end | ||||
|
r3037 | context "with Setting.issue_done_ratio using the issue_field" do | ||
setup do | ||||
Setting.issue_done_ratio = 'issue_field' | ||||
end | ||||
|
r5686 | |||
|
r3037 | should "read the issue's field" do | ||
assert_equal 0, @issue.done_ratio | ||||
|
r4072 | assert_equal 30, @issue2.done_ratio | ||
|
r3037 | end | ||
end | ||||
context "with Setting.issue_done_ratio using the issue_status" do | ||||
setup do | ||||
Setting.issue_done_ratio = 'issue_status' | ||||
end | ||||
|
r5686 | |||
|
r3037 | should "read the Issue Status's default done ratio" do | ||
assert_equal 50, @issue.done_ratio | ||||
|
r4072 | assert_equal 0, @issue2.done_ratio | ||
|
r3037 | end | ||
end | ||||
end | ||||
context "#update_done_ratio_from_issue_status" do | ||||
setup do | ||||
@issue = Issue.find(1) | ||||
@issue_status = IssueStatus.find(1) | ||||
@issue_status.update_attribute(:default_done_ratio, 50) | ||||
|
r4072 | @issue2 = Issue.find(2) | ||
@issue_status2 = IssueStatus.find(2) | ||||
@issue_status2.update_attribute(:default_done_ratio, 0) | ||||
|
r3037 | end | ||
|
r5686 | |||
|
r3037 | context "with Setting.issue_done_ratio using the issue_field" do | ||
setup do | ||||
Setting.issue_done_ratio = 'issue_field' | ||||
end | ||||
|
r5686 | |||
|
r3037 | should "not change the issue" do | ||
@issue.update_done_ratio_from_issue_status | ||||
|
r4072 | @issue2.update_done_ratio_from_issue_status | ||
|
r3037 | |||
|
r4072 | assert_equal 0, @issue.read_attribute(:done_ratio) | ||
assert_equal 30, @issue2.read_attribute(:done_ratio) | ||||
|
r3037 | end | ||
end | ||||
context "with Setting.issue_done_ratio using the issue_status" do | ||||
setup do | ||||
Setting.issue_done_ratio = 'issue_status' | ||||
end | ||||
|
r5686 | |||
|
r4072 | should "change the issue's done ratio" do | ||
|
r3037 | @issue.update_done_ratio_from_issue_status | ||
|
r4072 | @issue2.update_done_ratio_from_issue_status | ||
|
r3037 | |||
|
r4072 | assert_equal 50, @issue.read_attribute(:done_ratio) | ||
assert_equal 0, @issue2.read_attribute(:done_ratio) | ||||
|
r3037 | end | ||
end | ||||
end | ||||
|
r3250 | |||
test "#by_tracker" do | ||||
|
r5245 | User.current = User.anonymous | ||
|
r3250 | groups = Issue.by_tracker(Project.find(1)) | ||
assert_equal 3, groups.size | ||||
assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i} | ||||
end | ||||
test "#by_version" do | ||||
|
r5245 | User.current = User.anonymous | ||
|
r3250 | groups = Issue.by_version(Project.find(1)) | ||
assert_equal 3, groups.size | ||||
assert_equal 3, groups.inject(0) {|sum, group| sum + group['total'].to_i} | ||||
end | ||||
test "#by_priority" do | ||||
|
r5245 | User.current = User.anonymous | ||
|
r3250 | groups = Issue.by_priority(Project.find(1)) | ||
assert_equal 4, groups.size | ||||
assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i} | ||||
end | ||||
test "#by_category" do | ||||
|
r5245 | User.current = User.anonymous | ||
|
r3250 | groups = Issue.by_category(Project.find(1)) | ||
assert_equal 2, groups.size | ||||
assert_equal 3, groups.inject(0) {|sum, group| sum + group['total'].to_i} | ||||
end | ||||
test "#by_assigned_to" do | ||||
|
r5245 | User.current = User.anonymous | ||
|
r3250 | groups = Issue.by_assigned_to(Project.find(1)) | ||
assert_equal 2, groups.size | ||||
assert_equal 2, groups.inject(0) {|sum, group| sum + group['total'].to_i} | ||||
end | ||||
test "#by_author" do | ||||
|
r5245 | User.current = User.anonymous | ||
|
r3250 | groups = Issue.by_author(Project.find(1)) | ||
assert_equal 4, groups.size | ||||
assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i} | ||||
end | ||||
test "#by_subproject" do | ||||
|
r5245 | User.current = User.anonymous | ||
|
r3250 | groups = Issue.by_subproject(Project.find(1)) | ||
|
r5245 | # Private descendant not visible | ||
assert_equal 1, groups.size | ||||
assert_equal 2, groups.inject(0) {|sum, group| sum + group['total'].to_i} | ||||
|
r3250 | end | ||
|
r5686 | |||
|
r3569 | context ".allowed_target_projects_on_move" do | ||
should "return all active projects for admin users" do | ||||
User.current = User.find(1) | ||||
assert_equal Project.active.count, Issue.allowed_target_projects_on_move.size | ||||
end | ||||
|
r5686 | |||
|
r3569 | should "return allowed projects for non admin users" do | ||
User.current = User.find(2) | ||||
Role.non_member.remove_permission! :move_issues | ||||
assert_equal 3, Issue.allowed_target_projects_on_move.size | ||||
|
r5686 | |||
|
r3569 | Role.non_member.add_permission! :move_issues | ||
assert_equal Project.active.count, Issue.allowed_target_projects_on_move.size | ||||
end | ||||
end | ||||
|
r3443 | |||
def test_recently_updated_with_limit_scopes | ||||
#should return the last updated issue | ||||
assert_equal 1, Issue.recently_updated.with_limit(1).length | ||||
assert_equal Issue.find(:first, :order => "updated_on DESC"), Issue.recently_updated.with_limit(1).first | ||||
end | ||||
def test_on_active_projects_scope | ||||
assert Project.find(2).archive | ||||
|
r5686 | |||
|
r3443 | before = Issue.on_active_project.length | ||
# test inclusion to results | ||||
issue = Issue.generate_for_project!(Project.find(1), :tracker => Project.find(2).trackers.first) | ||||
assert_equal before + 1, Issue.on_active_project.length | ||||
# Move to an archived project | ||||
issue.project = Project.find(2) | ||||
assert issue.save | ||||
assert_equal before, Issue.on_active_project.length | ||||
end | ||||
|
r4103 | |||
context "Issue#recipients" do | ||||
setup do | ||||
@project = Project.find(1) | ||||
|
r4104 | @author = User.generate_with_protected! | ||
@assignee = User.generate_with_protected! | ||||
@issue = Issue.generate_for_project!(@project, :assigned_to => @assignee, :author => @author) | ||||
|
r4103 | end | ||
|
r5686 | |||
|
r4103 | should "include project recipients" do | ||
assert @project.recipients.present? | ||||
@project.recipients.each do |project_recipient| | ||||
assert @issue.recipients.include?(project_recipient) | ||||
end | ||||
end | ||||
should "include the author if the author is active" do | ||||
assert @issue.author, "No author set for Issue" | ||||
assert @issue.recipients.include?(@issue.author.mail) | ||||
end | ||||
|
r5686 | |||
|
r4103 | should "include the assigned to user if the assigned to user is active" do | ||
assert @issue.assigned_to, "No assigned_to set for Issue" | ||||
assert @issue.recipients.include?(@issue.assigned_to.mail) | ||||
end | ||||
|
r4104 | |||
should "not include users who opt out of all email" do | ||||
@author.update_attribute(:mail_notification, :none) | ||||
assert !@issue.recipients.include?(@issue.author.mail) | ||||
end | ||||
should "not include the issue author if they are only notified of assigned issues" do | ||||
@author.update_attribute(:mail_notification, :only_assigned) | ||||
assert !@issue.recipients.include?(@issue.author.mail) | ||||
end | ||||
should "not include the assigned user if they are only notified of owned issues" do | ||||
@assignee.update_attribute(:mail_notification, :only_owner) | ||||
assert !@issue.recipients.include?(@issue.assigned_to.mail) | ||||
end | ||||
|
r4103 | end | ||
|
r574 | end | ||