##// END OF EJS Templates
Make sure that attachments are created in the same order they were selected (#12310)....
Jean-Philippe Lang -
r10571:a17f4c8375d1
parent child
Show More
@@ -1,102 +1,114
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2012 Jean-Philippe Lang
2 # Copyright (C) 2006-2012 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 module Redmine
18 module Redmine
19 module Acts
19 module Acts
20 module Attachable
20 module Attachable
21 def self.included(base)
21 def self.included(base)
22 base.extend ClassMethods
22 base.extend ClassMethods
23 end
23 end
24
24
25 module ClassMethods
25 module ClassMethods
26 def acts_as_attachable(options = {})
26 def acts_as_attachable(options = {})
27 cattr_accessor :attachable_options
27 cattr_accessor :attachable_options
28 self.attachable_options = {}
28 self.attachable_options = {}
29 attachable_options[:view_permission] = options.delete(:view_permission) || "view_#{self.name.pluralize.underscore}".to_sym
29 attachable_options[:view_permission] = options.delete(:view_permission) || "view_#{self.name.pluralize.underscore}".to_sym
30 attachable_options[:delete_permission] = options.delete(:delete_permission) || "edit_#{self.name.pluralize.underscore}".to_sym
30 attachable_options[:delete_permission] = options.delete(:delete_permission) || "edit_#{self.name.pluralize.underscore}".to_sym
31
31
32 has_many :attachments, options.merge(:as => :container,
32 has_many :attachments, options.merge(:as => :container,
33 :order => "#{Attachment.table_name}.created_on ASC, #{Attachment.table_name}.id ASC",
33 :order => "#{Attachment.table_name}.created_on ASC, #{Attachment.table_name}.id ASC",
34 :dependent => :destroy)
34 :dependent => :destroy)
35 send :include, Redmine::Acts::Attachable::InstanceMethods
35 send :include, Redmine::Acts::Attachable::InstanceMethods
36 before_save :attach_saved_attachments
36 before_save :attach_saved_attachments
37 end
37 end
38 end
38 end
39
39
40 module InstanceMethods
40 module InstanceMethods
41 def self.included(base)
41 def self.included(base)
42 base.extend ClassMethods
42 base.extend ClassMethods
43 end
43 end
44
44
45 def attachments_visible?(user=User.current)
45 def attachments_visible?(user=User.current)
46 (respond_to?(:visible?) ? visible?(user) : true) &&
46 (respond_to?(:visible?) ? visible?(user) : true) &&
47 user.allowed_to?(self.class.attachable_options[:view_permission], self.project)
47 user.allowed_to?(self.class.attachable_options[:view_permission], self.project)
48 end
48 end
49
49
50 def attachments_deletable?(user=User.current)
50 def attachments_deletable?(user=User.current)
51 (respond_to?(:visible?) ? visible?(user) : true) &&
51 (respond_to?(:visible?) ? visible?(user) : true) &&
52 user.allowed_to?(self.class.attachable_options[:delete_permission], self.project)
52 user.allowed_to?(self.class.attachable_options[:delete_permission], self.project)
53 end
53 end
54
54
55 def saved_attachments
55 def saved_attachments
56 @saved_attachments ||= []
56 @saved_attachments ||= []
57 end
57 end
58
58
59 def unsaved_attachments
59 def unsaved_attachments
60 @unsaved_attachments ||= []
60 @unsaved_attachments ||= []
61 end
61 end
62
62
63 def save_attachments(attachments, author=User.current)
63 def save_attachments(attachments, author=User.current)
64 if attachments.is_a?(Hash)
64 if attachments.is_a?(Hash)
65 attachments = attachments.values
65 attachments = attachments.stringify_keys
66 attachments = attachments.to_a.sort {|a, b|
67 if a.first.to_i > 0 && b.first.to_i > 0
68 a.first.to_i <=> b.first.to_i
69 elsif a.first.to_i > 0
70 1
71 elsif b.first.to_i > 0
72 -1
73 else
74 a.first <=> b.first
75 end
76 }
77 attachments = attachments.map(&:last)
66 end
78 end
67 if attachments.is_a?(Array)
79 if attachments.is_a?(Array)
68 attachments.each do |attachment|
80 attachments.each do |attachment|
69 a = nil
81 a = nil
70 if file = attachment['file']
82 if file = attachment['file']
71 next unless file.size > 0
83 next unless file.size > 0
72 a = Attachment.create(:file => file, :author => author)
84 a = Attachment.create(:file => file, :author => author)
73 elsif token = attachment['token']
85 elsif token = attachment['token']
74 a = Attachment.find_by_token(token)
86 a = Attachment.find_by_token(token)
75 next unless a
87 next unless a
76 a.filename = attachment['filename'] unless attachment['filename'].blank?
88 a.filename = attachment['filename'] unless attachment['filename'].blank?
77 a.content_type = attachment['content_type']
89 a.content_type = attachment['content_type']
78 end
90 end
79 next unless a
91 next unless a
80 a.description = attachment['description'].to_s.strip
92 a.description = attachment['description'].to_s.strip
81 if a.new_record?
93 if a.new_record?
82 unsaved_attachments << a
94 unsaved_attachments << a
83 else
95 else
84 saved_attachments << a
96 saved_attachments << a
85 end
97 end
86 end
98 end
87 end
99 end
88 {:files => saved_attachments, :unsaved => unsaved_attachments}
100 {:files => saved_attachments, :unsaved => unsaved_attachments}
89 end
101 end
90
102
91 def attach_saved_attachments
103 def attach_saved_attachments
92 saved_attachments.each do |attachment|
104 saved_attachments.each do |attachment|
93 self.attachments << attachment
105 self.attachments << attachment
94 end
106 end
95 end
107 end
96
108
97 module ClassMethods
109 module ClassMethods
98 end
110 end
99 end
111 end
100 end
112 end
101 end
113 end
102 end
114 end
@@ -1,1891 +1,1905
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2012 Jean-Philippe Lang
2 # Copyright (C) 2006-2012 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class IssueTest < ActiveSupport::TestCase
20 class IssueTest < ActiveSupport::TestCase
21 fixtures :projects, :users, :members, :member_roles, :roles,
21 fixtures :projects, :users, :members, :member_roles, :roles,
22 :groups_users,
22 :groups_users,
23 :trackers, :projects_trackers,
23 :trackers, :projects_trackers,
24 :enabled_modules,
24 :enabled_modules,
25 :versions,
25 :versions,
26 :issue_statuses, :issue_categories, :issue_relations, :workflows,
26 :issue_statuses, :issue_categories, :issue_relations, :workflows,
27 :enumerations,
27 :enumerations,
28 :issues, :journals, :journal_details,
28 :issues, :journals, :journal_details,
29 :custom_fields, :custom_fields_projects, :custom_fields_trackers, :custom_values,
29 :custom_fields, :custom_fields_projects, :custom_fields_trackers, :custom_values,
30 :time_entries
30 :time_entries
31
31
32 include Redmine::I18n
32 include Redmine::I18n
33
33
34 def teardown
34 def teardown
35 User.current = nil
35 User.current = nil
36 end
36 end
37
37
38 def test_create
38 def test_create
39 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3,
39 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3,
40 :status_id => 1, :priority => IssuePriority.all.first,
40 :status_id => 1, :priority => IssuePriority.all.first,
41 :subject => 'test_create',
41 :subject => 'test_create',
42 :description => 'IssueTest#test_create', :estimated_hours => '1:30')
42 :description => 'IssueTest#test_create', :estimated_hours => '1:30')
43 assert issue.save
43 assert issue.save
44 issue.reload
44 issue.reload
45 assert_equal 1.5, issue.estimated_hours
45 assert_equal 1.5, issue.estimated_hours
46 end
46 end
47
47
48 def test_create_minimal
48 def test_create_minimal
49 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3,
49 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3,
50 :status_id => 1, :priority => IssuePriority.all.first,
50 :status_id => 1, :priority => IssuePriority.all.first,
51 :subject => 'test_create')
51 :subject => 'test_create')
52 assert issue.save
52 assert issue.save
53 assert issue.description.nil?
53 assert issue.description.nil?
54 assert_nil issue.estimated_hours
54 assert_nil issue.estimated_hours
55 end
55 end
56
56
57 def test_start_date_format_should_be_validated
57 def test_start_date_format_should_be_validated
58 set_language_if_valid 'en'
58 set_language_if_valid 'en'
59 ['2012', 'ABC', '2012-15-20'].each do |invalid_date|
59 ['2012', 'ABC', '2012-15-20'].each do |invalid_date|
60 issue = Issue.new(:start_date => invalid_date)
60 issue = Issue.new(:start_date => invalid_date)
61 assert !issue.valid?
61 assert !issue.valid?
62 assert_include 'Start date is not a valid date', issue.errors.full_messages, "No error found for invalid date #{invalid_date}"
62 assert_include 'Start date is not a valid date', issue.errors.full_messages, "No error found for invalid date #{invalid_date}"
63 end
63 end
64 end
64 end
65
65
66 def test_due_date_format_should_be_validated
66 def test_due_date_format_should_be_validated
67 set_language_if_valid 'en'
67 set_language_if_valid 'en'
68 ['2012', 'ABC', '2012-15-20'].each do |invalid_date|
68 ['2012', 'ABC', '2012-15-20'].each do |invalid_date|
69 issue = Issue.new(:due_date => invalid_date)
69 issue = Issue.new(:due_date => invalid_date)
70 assert !issue.valid?
70 assert !issue.valid?
71 assert_include 'Due date is not a valid date', issue.errors.full_messages, "No error found for invalid date #{invalid_date}"
71 assert_include 'Due date is not a valid date', issue.errors.full_messages, "No error found for invalid date #{invalid_date}"
72 end
72 end
73 end
73 end
74
74
75 def test_due_date_lesser_than_start_date_should_not_validate
75 def test_due_date_lesser_than_start_date_should_not_validate
76 set_language_if_valid 'en'
76 set_language_if_valid 'en'
77 issue = Issue.new(:start_date => '2012-10-06', :due_date => '2012-10-02')
77 issue = Issue.new(:start_date => '2012-10-06', :due_date => '2012-10-02')
78 assert !issue.valid?
78 assert !issue.valid?
79 assert_include 'Due date must be greater than start date', issue.errors.full_messages
79 assert_include 'Due date must be greater than start date', issue.errors.full_messages
80 end
80 end
81
81
82 def test_create_with_required_custom_field
82 def test_create_with_required_custom_field
83 set_language_if_valid 'en'
83 set_language_if_valid 'en'
84 field = IssueCustomField.find_by_name('Database')
84 field = IssueCustomField.find_by_name('Database')
85 field.update_attribute(:is_required, true)
85 field.update_attribute(:is_required, true)
86
86
87 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
87 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
88 :status_id => 1, :subject => 'test_create',
88 :status_id => 1, :subject => 'test_create',
89 :description => 'IssueTest#test_create_with_required_custom_field')
89 :description => 'IssueTest#test_create_with_required_custom_field')
90 assert issue.available_custom_fields.include?(field)
90 assert issue.available_custom_fields.include?(field)
91 # No value for the custom field
91 # No value for the custom field
92 assert !issue.save
92 assert !issue.save
93 assert_equal ["Database can't be blank"], issue.errors.full_messages
93 assert_equal ["Database can't be blank"], issue.errors.full_messages
94 # Blank value
94 # Blank value
95 issue.custom_field_values = { field.id => '' }
95 issue.custom_field_values = { field.id => '' }
96 assert !issue.save
96 assert !issue.save
97 assert_equal ["Database can't be blank"], issue.errors.full_messages
97 assert_equal ["Database can't be blank"], issue.errors.full_messages
98 # Invalid value
98 # Invalid value
99 issue.custom_field_values = { field.id => 'SQLServer' }
99 issue.custom_field_values = { field.id => 'SQLServer' }
100 assert !issue.save
100 assert !issue.save
101 assert_equal ["Database is not included in the list"], issue.errors.full_messages
101 assert_equal ["Database is not included in the list"], issue.errors.full_messages
102 # Valid value
102 # Valid value
103 issue.custom_field_values = { field.id => 'PostgreSQL' }
103 issue.custom_field_values = { field.id => 'PostgreSQL' }
104 assert issue.save
104 assert issue.save
105 issue.reload
105 issue.reload
106 assert_equal 'PostgreSQL', issue.custom_value_for(field).value
106 assert_equal 'PostgreSQL', issue.custom_value_for(field).value
107 end
107 end
108
108
109 def test_create_with_group_assignment
109 def test_create_with_group_assignment
110 with_settings :issue_group_assignment => '1' do
110 with_settings :issue_group_assignment => '1' do
111 assert Issue.new(:project_id => 2, :tracker_id => 1, :author_id => 1,
111 assert Issue.new(:project_id => 2, :tracker_id => 1, :author_id => 1,
112 :subject => 'Group assignment',
112 :subject => 'Group assignment',
113 :assigned_to_id => 11).save
113 :assigned_to_id => 11).save
114 issue = Issue.first(:order => 'id DESC')
114 issue = Issue.first(:order => 'id DESC')
115 assert_kind_of Group, issue.assigned_to
115 assert_kind_of Group, issue.assigned_to
116 assert_equal Group.find(11), issue.assigned_to
116 assert_equal Group.find(11), issue.assigned_to
117 end
117 end
118 end
118 end
119
119
120 def test_create_with_parent_issue_id
120 def test_create_with_parent_issue_id
121 issue = Issue.new(:project_id => 1, :tracker_id => 1,
121 issue = Issue.new(:project_id => 1, :tracker_id => 1,
122 :author_id => 1, :subject => 'Group assignment',
122 :author_id => 1, :subject => 'Group assignment',
123 :parent_issue_id => 1)
123 :parent_issue_id => 1)
124 assert_save issue
124 assert_save issue
125 assert_equal 1, issue.parent_issue_id
125 assert_equal 1, issue.parent_issue_id
126 assert_equal Issue.find(1), issue.parent
126 assert_equal Issue.find(1), issue.parent
127 end
127 end
128
128
129 def test_create_with_sharp_parent_issue_id
129 def test_create_with_sharp_parent_issue_id
130 issue = Issue.new(:project_id => 1, :tracker_id => 1,
130 issue = Issue.new(:project_id => 1, :tracker_id => 1,
131 :author_id => 1, :subject => 'Group assignment',
131 :author_id => 1, :subject => 'Group assignment',
132 :parent_issue_id => "#1")
132 :parent_issue_id => "#1")
133 assert_save issue
133 assert_save issue
134 assert_equal 1, issue.parent_issue_id
134 assert_equal 1, issue.parent_issue_id
135 assert_equal Issue.find(1), issue.parent
135 assert_equal Issue.find(1), issue.parent
136 end
136 end
137
137
138 def test_create_with_invalid_parent_issue_id
138 def test_create_with_invalid_parent_issue_id
139 set_language_if_valid 'en'
139 set_language_if_valid 'en'
140 issue = Issue.new(:project_id => 1, :tracker_id => 1,
140 issue = Issue.new(:project_id => 1, :tracker_id => 1,
141 :author_id => 1, :subject => 'Group assignment',
141 :author_id => 1, :subject => 'Group assignment',
142 :parent_issue_id => '01ABC')
142 :parent_issue_id => '01ABC')
143 assert !issue.save
143 assert !issue.save
144 assert_equal '01ABC', issue.parent_issue_id
144 assert_equal '01ABC', issue.parent_issue_id
145 assert_include 'Parent task is invalid', issue.errors.full_messages
145 assert_include 'Parent task is invalid', issue.errors.full_messages
146 end
146 end
147
147
148 def test_create_with_invalid_sharp_parent_issue_id
148 def test_create_with_invalid_sharp_parent_issue_id
149 set_language_if_valid 'en'
149 set_language_if_valid 'en'
150 issue = Issue.new(:project_id => 1, :tracker_id => 1,
150 issue = Issue.new(:project_id => 1, :tracker_id => 1,
151 :author_id => 1, :subject => 'Group assignment',
151 :author_id => 1, :subject => 'Group assignment',
152 :parent_issue_id => '#01ABC')
152 :parent_issue_id => '#01ABC')
153 assert !issue.save
153 assert !issue.save
154 assert_equal '#01ABC', issue.parent_issue_id
154 assert_equal '#01ABC', issue.parent_issue_id
155 assert_include 'Parent task is invalid', issue.errors.full_messages
155 assert_include 'Parent task is invalid', issue.errors.full_messages
156 end
156 end
157
157
158 def assert_visibility_match(user, issues)
158 def assert_visibility_match(user, issues)
159 assert_equal issues.collect(&:id).sort, Issue.all.select {|issue| issue.visible?(user)}.collect(&:id).sort
159 assert_equal issues.collect(&:id).sort, Issue.all.select {|issue| issue.visible?(user)}.collect(&:id).sort
160 end
160 end
161
161
162 def test_visible_scope_for_anonymous
162 def test_visible_scope_for_anonymous
163 # Anonymous user should see issues of public projects only
163 # Anonymous user should see issues of public projects only
164 issues = Issue.visible(User.anonymous).all
164 issues = Issue.visible(User.anonymous).all
165 assert issues.any?
165 assert issues.any?
166 assert_nil issues.detect {|issue| !issue.project.is_public?}
166 assert_nil issues.detect {|issue| !issue.project.is_public?}
167 assert_nil issues.detect {|issue| issue.is_private?}
167 assert_nil issues.detect {|issue| issue.is_private?}
168 assert_visibility_match User.anonymous, issues
168 assert_visibility_match User.anonymous, issues
169 end
169 end
170
170
171 def test_visible_scope_for_anonymous_without_view_issues_permissions
171 def test_visible_scope_for_anonymous_without_view_issues_permissions
172 # Anonymous user should not see issues without permission
172 # Anonymous user should not see issues without permission
173 Role.anonymous.remove_permission!(:view_issues)
173 Role.anonymous.remove_permission!(:view_issues)
174 issues = Issue.visible(User.anonymous).all
174 issues = Issue.visible(User.anonymous).all
175 assert issues.empty?
175 assert issues.empty?
176 assert_visibility_match User.anonymous, issues
176 assert_visibility_match User.anonymous, issues
177 end
177 end
178
178
179 def test_anonymous_should_not_see_private_issues_with_issues_visibility_set_to_default
179 def test_anonymous_should_not_see_private_issues_with_issues_visibility_set_to_default
180 assert Role.anonymous.update_attribute(:issues_visibility, 'default')
180 assert Role.anonymous.update_attribute(:issues_visibility, 'default')
181 issue = Issue.generate!(:author => User.anonymous, :assigned_to => User.anonymous, :is_private => true)
181 issue = Issue.generate!(:author => User.anonymous, :assigned_to => User.anonymous, :is_private => true)
182 assert_nil Issue.where(:id => issue.id).visible(User.anonymous).first
182 assert_nil Issue.where(:id => issue.id).visible(User.anonymous).first
183 assert !issue.visible?(User.anonymous)
183 assert !issue.visible?(User.anonymous)
184 end
184 end
185
185
186 def test_anonymous_should_not_see_private_issues_with_issues_visibility_set_to_own
186 def test_anonymous_should_not_see_private_issues_with_issues_visibility_set_to_own
187 assert Role.anonymous.update_attribute(:issues_visibility, 'own')
187 assert Role.anonymous.update_attribute(:issues_visibility, 'own')
188 issue = Issue.generate!(:author => User.anonymous, :assigned_to => User.anonymous, :is_private => true)
188 issue = Issue.generate!(:author => User.anonymous, :assigned_to => User.anonymous, :is_private => true)
189 assert_nil Issue.where(:id => issue.id).visible(User.anonymous).first
189 assert_nil Issue.where(:id => issue.id).visible(User.anonymous).first
190 assert !issue.visible?(User.anonymous)
190 assert !issue.visible?(User.anonymous)
191 end
191 end
192
192
193 def test_visible_scope_for_non_member
193 def test_visible_scope_for_non_member
194 user = User.find(9)
194 user = User.find(9)
195 assert user.projects.empty?
195 assert user.projects.empty?
196 # Non member user should see issues of public projects only
196 # Non member user should see issues of public projects only
197 issues = Issue.visible(user).all
197 issues = Issue.visible(user).all
198 assert issues.any?
198 assert issues.any?
199 assert_nil issues.detect {|issue| !issue.project.is_public?}
199 assert_nil issues.detect {|issue| !issue.project.is_public?}
200 assert_nil issues.detect {|issue| issue.is_private?}
200 assert_nil issues.detect {|issue| issue.is_private?}
201 assert_visibility_match user, issues
201 assert_visibility_match user, issues
202 end
202 end
203
203
204 def test_visible_scope_for_non_member_with_own_issues_visibility
204 def test_visible_scope_for_non_member_with_own_issues_visibility
205 Role.non_member.update_attribute :issues_visibility, 'own'
205 Role.non_member.update_attribute :issues_visibility, 'own'
206 Issue.create!(:project_id => 1, :tracker_id => 1, :author_id => 9, :subject => 'Issue by non member')
206 Issue.create!(:project_id => 1, :tracker_id => 1, :author_id => 9, :subject => 'Issue by non member')
207 user = User.find(9)
207 user = User.find(9)
208
208
209 issues = Issue.visible(user).all
209 issues = Issue.visible(user).all
210 assert issues.any?
210 assert issues.any?
211 assert_nil issues.detect {|issue| issue.author != user}
211 assert_nil issues.detect {|issue| issue.author != user}
212 assert_visibility_match user, issues
212 assert_visibility_match user, issues
213 end
213 end
214
214
215 def test_visible_scope_for_non_member_without_view_issues_permissions
215 def test_visible_scope_for_non_member_without_view_issues_permissions
216 # Non member user should not see issues without permission
216 # Non member user should not see issues without permission
217 Role.non_member.remove_permission!(:view_issues)
217 Role.non_member.remove_permission!(:view_issues)
218 user = User.find(9)
218 user = User.find(9)
219 assert user.projects.empty?
219 assert user.projects.empty?
220 issues = Issue.visible(user).all
220 issues = Issue.visible(user).all
221 assert issues.empty?
221 assert issues.empty?
222 assert_visibility_match user, issues
222 assert_visibility_match user, issues
223 end
223 end
224
224
225 def test_visible_scope_for_member
225 def test_visible_scope_for_member
226 user = User.find(9)
226 user = User.find(9)
227 # User should see issues of projects for which he has view_issues permissions only
227 # User should see issues of projects for which he has view_issues permissions only
228 Role.non_member.remove_permission!(:view_issues)
228 Role.non_member.remove_permission!(:view_issues)
229 Member.create!(:principal => user, :project_id => 3, :role_ids => [2])
229 Member.create!(:principal => user, :project_id => 3, :role_ids => [2])
230 issues = Issue.visible(user).all
230 issues = Issue.visible(user).all
231 assert issues.any?
231 assert issues.any?
232 assert_nil issues.detect {|issue| issue.project_id != 3}
232 assert_nil issues.detect {|issue| issue.project_id != 3}
233 assert_nil issues.detect {|issue| issue.is_private?}
233 assert_nil issues.detect {|issue| issue.is_private?}
234 assert_visibility_match user, issues
234 assert_visibility_match user, issues
235 end
235 end
236
236
237 def test_visible_scope_for_member_with_groups_should_return_assigned_issues
237 def test_visible_scope_for_member_with_groups_should_return_assigned_issues
238 user = User.find(8)
238 user = User.find(8)
239 assert user.groups.any?
239 assert user.groups.any?
240 Member.create!(:principal => user.groups.first, :project_id => 1, :role_ids => [2])
240 Member.create!(:principal => user.groups.first, :project_id => 1, :role_ids => [2])
241 Role.non_member.remove_permission!(:view_issues)
241 Role.non_member.remove_permission!(:view_issues)
242
242
243 issue = Issue.create(:project_id => 1, :tracker_id => 1, :author_id => 3,
243 issue = Issue.create(:project_id => 1, :tracker_id => 1, :author_id => 3,
244 :status_id => 1, :priority => IssuePriority.all.first,
244 :status_id => 1, :priority => IssuePriority.all.first,
245 :subject => 'Assignment test',
245 :subject => 'Assignment test',
246 :assigned_to => user.groups.first,
246 :assigned_to => user.groups.first,
247 :is_private => true)
247 :is_private => true)
248
248
249 Role.find(2).update_attribute :issues_visibility, 'default'
249 Role.find(2).update_attribute :issues_visibility, 'default'
250 issues = Issue.visible(User.find(8)).all
250 issues = Issue.visible(User.find(8)).all
251 assert issues.any?
251 assert issues.any?
252 assert issues.include?(issue)
252 assert issues.include?(issue)
253
253
254 Role.find(2).update_attribute :issues_visibility, 'own'
254 Role.find(2).update_attribute :issues_visibility, 'own'
255 issues = Issue.visible(User.find(8)).all
255 issues = Issue.visible(User.find(8)).all
256 assert issues.any?
256 assert issues.any?
257 assert issues.include?(issue)
257 assert issues.include?(issue)
258 end
258 end
259
259
260 def test_visible_scope_for_admin
260 def test_visible_scope_for_admin
261 user = User.find(1)
261 user = User.find(1)
262 user.members.each(&:destroy)
262 user.members.each(&:destroy)
263 assert user.projects.empty?
263 assert user.projects.empty?
264 issues = Issue.visible(user).all
264 issues = Issue.visible(user).all
265 assert issues.any?
265 assert issues.any?
266 # Admin should see issues on private projects that he does not belong to
266 # Admin should see issues on private projects that he does not belong to
267 assert issues.detect {|issue| !issue.project.is_public?}
267 assert issues.detect {|issue| !issue.project.is_public?}
268 # Admin should see private issues of other users
268 # Admin should see private issues of other users
269 assert issues.detect {|issue| issue.is_private? && issue.author != user}
269 assert issues.detect {|issue| issue.is_private? && issue.author != user}
270 assert_visibility_match user, issues
270 assert_visibility_match user, issues
271 end
271 end
272
272
273 def test_visible_scope_with_project
273 def test_visible_scope_with_project
274 project = Project.find(1)
274 project = Project.find(1)
275 issues = Issue.visible(User.find(2), :project => project).all
275 issues = Issue.visible(User.find(2), :project => project).all
276 projects = issues.collect(&:project).uniq
276 projects = issues.collect(&:project).uniq
277 assert_equal 1, projects.size
277 assert_equal 1, projects.size
278 assert_equal project, projects.first
278 assert_equal project, projects.first
279 end
279 end
280
280
281 def test_visible_scope_with_project_and_subprojects
281 def test_visible_scope_with_project_and_subprojects
282 project = Project.find(1)
282 project = Project.find(1)
283 issues = Issue.visible(User.find(2), :project => project, :with_subprojects => true).all
283 issues = Issue.visible(User.find(2), :project => project, :with_subprojects => true).all
284 projects = issues.collect(&:project).uniq
284 projects = issues.collect(&:project).uniq
285 assert projects.size > 1
285 assert projects.size > 1
286 assert_equal [], projects.select {|p| !p.is_or_is_descendant_of?(project)}
286 assert_equal [], projects.select {|p| !p.is_or_is_descendant_of?(project)}
287 end
287 end
288
288
289 def test_visible_and_nested_set_scopes
289 def test_visible_and_nested_set_scopes
290 assert_equal 0, Issue.find(1).descendants.visible.all.size
290 assert_equal 0, Issue.find(1).descendants.visible.all.size
291 end
291 end
292
292
293 def test_open_scope
293 def test_open_scope
294 issues = Issue.open.all
294 issues = Issue.open.all
295 assert_nil issues.detect(&:closed?)
295 assert_nil issues.detect(&:closed?)
296 end
296 end
297
297
298 def test_open_scope_with_arg
298 def test_open_scope_with_arg
299 issues = Issue.open(false).all
299 issues = Issue.open(false).all
300 assert_equal issues, issues.select(&:closed?)
300 assert_equal issues, issues.select(&:closed?)
301 end
301 end
302
302
303 def test_errors_full_messages_should_include_custom_fields_errors
303 def test_errors_full_messages_should_include_custom_fields_errors
304 field = IssueCustomField.find_by_name('Database')
304 field = IssueCustomField.find_by_name('Database')
305
305
306 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
306 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
307 :status_id => 1, :subject => 'test_create',
307 :status_id => 1, :subject => 'test_create',
308 :description => 'IssueTest#test_create_with_required_custom_field')
308 :description => 'IssueTest#test_create_with_required_custom_field')
309 assert issue.available_custom_fields.include?(field)
309 assert issue.available_custom_fields.include?(field)
310 # Invalid value
310 # Invalid value
311 issue.custom_field_values = { field.id => 'SQLServer' }
311 issue.custom_field_values = { field.id => 'SQLServer' }
312
312
313 assert !issue.valid?
313 assert !issue.valid?
314 assert_equal 1, issue.errors.full_messages.size
314 assert_equal 1, issue.errors.full_messages.size
315 assert_equal "Database #{I18n.translate('activerecord.errors.messages.inclusion')}",
315 assert_equal "Database #{I18n.translate('activerecord.errors.messages.inclusion')}",
316 issue.errors.full_messages.first
316 issue.errors.full_messages.first
317 end
317 end
318
318
319 def test_update_issue_with_required_custom_field
319 def test_update_issue_with_required_custom_field
320 field = IssueCustomField.find_by_name('Database')
320 field = IssueCustomField.find_by_name('Database')
321 field.update_attribute(:is_required, true)
321 field.update_attribute(:is_required, true)
322
322
323 issue = Issue.find(1)
323 issue = Issue.find(1)
324 assert_nil issue.custom_value_for(field)
324 assert_nil issue.custom_value_for(field)
325 assert issue.available_custom_fields.include?(field)
325 assert issue.available_custom_fields.include?(field)
326 # No change to custom values, issue can be saved
326 # No change to custom values, issue can be saved
327 assert issue.save
327 assert issue.save
328 # Blank value
328 # Blank value
329 issue.custom_field_values = { field.id => '' }
329 issue.custom_field_values = { field.id => '' }
330 assert !issue.save
330 assert !issue.save
331 # Valid value
331 # Valid value
332 issue.custom_field_values = { field.id => 'PostgreSQL' }
332 issue.custom_field_values = { field.id => 'PostgreSQL' }
333 assert issue.save
333 assert issue.save
334 issue.reload
334 issue.reload
335 assert_equal 'PostgreSQL', issue.custom_value_for(field).value
335 assert_equal 'PostgreSQL', issue.custom_value_for(field).value
336 end
336 end
337
337
338 def test_should_not_update_attributes_if_custom_fields_validation_fails
338 def test_should_not_update_attributes_if_custom_fields_validation_fails
339 issue = Issue.find(1)
339 issue = Issue.find(1)
340 field = IssueCustomField.find_by_name('Database')
340 field = IssueCustomField.find_by_name('Database')
341 assert issue.available_custom_fields.include?(field)
341 assert issue.available_custom_fields.include?(field)
342
342
343 issue.custom_field_values = { field.id => 'Invalid' }
343 issue.custom_field_values = { field.id => 'Invalid' }
344 issue.subject = 'Should be not be saved'
344 issue.subject = 'Should be not be saved'
345 assert !issue.save
345 assert !issue.save
346
346
347 issue.reload
347 issue.reload
348 assert_equal "Can't print recipes", issue.subject
348 assert_equal "Can't print recipes", issue.subject
349 end
349 end
350
350
351 def test_should_not_recreate_custom_values_objects_on_update
351 def test_should_not_recreate_custom_values_objects_on_update
352 field = IssueCustomField.find_by_name('Database')
352 field = IssueCustomField.find_by_name('Database')
353
353
354 issue = Issue.find(1)
354 issue = Issue.find(1)
355 issue.custom_field_values = { field.id => 'PostgreSQL' }
355 issue.custom_field_values = { field.id => 'PostgreSQL' }
356 assert issue.save
356 assert issue.save
357 custom_value = issue.custom_value_for(field)
357 custom_value = issue.custom_value_for(field)
358 issue.reload
358 issue.reload
359 issue.custom_field_values = { field.id => 'MySQL' }
359 issue.custom_field_values = { field.id => 'MySQL' }
360 assert issue.save
360 assert issue.save
361 issue.reload
361 issue.reload
362 assert_equal custom_value.id, issue.custom_value_for(field).id
362 assert_equal custom_value.id, issue.custom_value_for(field).id
363 end
363 end
364
364
365 def test_should_not_update_custom_fields_on_changing_tracker_with_different_custom_fields
365 def test_should_not_update_custom_fields_on_changing_tracker_with_different_custom_fields
366 issue = Issue.create!(:project_id => 1, :tracker_id => 1, :author_id => 1,
366 issue = Issue.create!(:project_id => 1, :tracker_id => 1, :author_id => 1,
367 :status_id => 1, :subject => 'Test',
367 :status_id => 1, :subject => 'Test',
368 :custom_field_values => {'2' => 'Test'})
368 :custom_field_values => {'2' => 'Test'})
369 assert !Tracker.find(2).custom_field_ids.include?(2)
369 assert !Tracker.find(2).custom_field_ids.include?(2)
370
370
371 issue = Issue.find(issue.id)
371 issue = Issue.find(issue.id)
372 issue.attributes = {:tracker_id => 2, :custom_field_values => {'1' => ''}}
372 issue.attributes = {:tracker_id => 2, :custom_field_values => {'1' => ''}}
373
373
374 issue = Issue.find(issue.id)
374 issue = Issue.find(issue.id)
375 custom_value = issue.custom_value_for(2)
375 custom_value = issue.custom_value_for(2)
376 assert_not_nil custom_value
376 assert_not_nil custom_value
377 assert_equal 'Test', custom_value.value
377 assert_equal 'Test', custom_value.value
378 end
378 end
379
379
380 def test_assigning_tracker_id_should_reload_custom_fields_values
380 def test_assigning_tracker_id_should_reload_custom_fields_values
381 issue = Issue.new(:project => Project.find(1))
381 issue = Issue.new(:project => Project.find(1))
382 assert issue.custom_field_values.empty?
382 assert issue.custom_field_values.empty?
383 issue.tracker_id = 1
383 issue.tracker_id = 1
384 assert issue.custom_field_values.any?
384 assert issue.custom_field_values.any?
385 end
385 end
386
386
387 def test_assigning_attributes_should_assign_project_and_tracker_first
387 def test_assigning_attributes_should_assign_project_and_tracker_first
388 seq = sequence('seq')
388 seq = sequence('seq')
389 issue = Issue.new
389 issue = Issue.new
390 issue.expects(:project_id=).in_sequence(seq)
390 issue.expects(:project_id=).in_sequence(seq)
391 issue.expects(:tracker_id=).in_sequence(seq)
391 issue.expects(:tracker_id=).in_sequence(seq)
392 issue.expects(:subject=).in_sequence(seq)
392 issue.expects(:subject=).in_sequence(seq)
393 issue.attributes = {:tracker_id => 2, :project_id => 1, :subject => 'Test'}
393 issue.attributes = {:tracker_id => 2, :project_id => 1, :subject => 'Test'}
394 end
394 end
395
395
396 def test_assigning_tracker_and_custom_fields_should_assign_custom_fields
396 def test_assigning_tracker_and_custom_fields_should_assign_custom_fields
397 attributes = ActiveSupport::OrderedHash.new
397 attributes = ActiveSupport::OrderedHash.new
398 attributes['custom_field_values'] = { '1' => 'MySQL' }
398 attributes['custom_field_values'] = { '1' => 'MySQL' }
399 attributes['tracker_id'] = '1'
399 attributes['tracker_id'] = '1'
400 issue = Issue.new(:project => Project.find(1))
400 issue = Issue.new(:project => Project.find(1))
401 issue.attributes = attributes
401 issue.attributes = attributes
402 assert_equal 'MySQL', issue.custom_field_value(1)
402 assert_equal 'MySQL', issue.custom_field_value(1)
403 end
403 end
404
404
405 def test_should_update_issue_with_disabled_tracker
405 def test_should_update_issue_with_disabled_tracker
406 p = Project.find(1)
406 p = Project.find(1)
407 issue = Issue.find(1)
407 issue = Issue.find(1)
408
408
409 p.trackers.delete(issue.tracker)
409 p.trackers.delete(issue.tracker)
410 assert !p.trackers.include?(issue.tracker)
410 assert !p.trackers.include?(issue.tracker)
411
411
412 issue.reload
412 issue.reload
413 issue.subject = 'New subject'
413 issue.subject = 'New subject'
414 assert issue.save
414 assert issue.save
415 end
415 end
416
416
417 def test_should_not_set_a_disabled_tracker
417 def test_should_not_set_a_disabled_tracker
418 p = Project.find(1)
418 p = Project.find(1)
419 p.trackers.delete(Tracker.find(2))
419 p.trackers.delete(Tracker.find(2))
420
420
421 issue = Issue.find(1)
421 issue = Issue.find(1)
422 issue.tracker_id = 2
422 issue.tracker_id = 2
423 issue.subject = 'New subject'
423 issue.subject = 'New subject'
424 assert !issue.save
424 assert !issue.save
425 assert_not_nil issue.errors[:tracker_id]
425 assert_not_nil issue.errors[:tracker_id]
426 end
426 end
427
427
428 def test_category_based_assignment
428 def test_category_based_assignment
429 issue = Issue.create(:project_id => 1, :tracker_id => 1, :author_id => 3,
429 issue = Issue.create(:project_id => 1, :tracker_id => 1, :author_id => 3,
430 :status_id => 1, :priority => IssuePriority.all.first,
430 :status_id => 1, :priority => IssuePriority.all.first,
431 :subject => 'Assignment test',
431 :subject => 'Assignment test',
432 :description => 'Assignment test', :category_id => 1)
432 :description => 'Assignment test', :category_id => 1)
433 assert_equal IssueCategory.find(1).assigned_to, issue.assigned_to
433 assert_equal IssueCategory.find(1).assigned_to, issue.assigned_to
434 end
434 end
435
435
436 def test_new_statuses_allowed_to
436 def test_new_statuses_allowed_to
437 WorkflowTransition.delete_all
437 WorkflowTransition.delete_all
438 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
438 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
439 :old_status_id => 1, :new_status_id => 2,
439 :old_status_id => 1, :new_status_id => 2,
440 :author => false, :assignee => false)
440 :author => false, :assignee => false)
441 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
441 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
442 :old_status_id => 1, :new_status_id => 3,
442 :old_status_id => 1, :new_status_id => 3,
443 :author => true, :assignee => false)
443 :author => true, :assignee => false)
444 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1,
444 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1,
445 :new_status_id => 4, :author => false,
445 :new_status_id => 4, :author => false,
446 :assignee => true)
446 :assignee => true)
447 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
447 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
448 :old_status_id => 1, :new_status_id => 5,
448 :old_status_id => 1, :new_status_id => 5,
449 :author => true, :assignee => true)
449 :author => true, :assignee => true)
450 status = IssueStatus.find(1)
450 status = IssueStatus.find(1)
451 role = Role.find(1)
451 role = Role.find(1)
452 tracker = Tracker.find(1)
452 tracker = Tracker.find(1)
453 user = User.find(2)
453 user = User.find(2)
454
454
455 issue = Issue.generate!(:tracker => tracker, :status => status,
455 issue = Issue.generate!(:tracker => tracker, :status => status,
456 :project_id => 1, :author_id => 1)
456 :project_id => 1, :author_id => 1)
457 assert_equal [1, 2], issue.new_statuses_allowed_to(user).map(&:id)
457 assert_equal [1, 2], issue.new_statuses_allowed_to(user).map(&:id)
458
458
459 issue = Issue.generate!(:tracker => tracker, :status => status,
459 issue = Issue.generate!(:tracker => tracker, :status => status,
460 :project_id => 1, :author => user)
460 :project_id => 1, :author => user)
461 assert_equal [1, 2, 3, 5], issue.new_statuses_allowed_to(user).map(&:id)
461 assert_equal [1, 2, 3, 5], issue.new_statuses_allowed_to(user).map(&:id)
462
462
463 issue = Issue.generate!(:tracker => tracker, :status => status,
463 issue = Issue.generate!(:tracker => tracker, :status => status,
464 :project_id => 1, :author_id => 1,
464 :project_id => 1, :author_id => 1,
465 :assigned_to => user)
465 :assigned_to => user)
466 assert_equal [1, 2, 4, 5], issue.new_statuses_allowed_to(user).map(&:id)
466 assert_equal [1, 2, 4, 5], issue.new_statuses_allowed_to(user).map(&:id)
467
467
468 issue = Issue.generate!(:tracker => tracker, :status => status,
468 issue = Issue.generate!(:tracker => tracker, :status => status,
469 :project_id => 1, :author => user,
469 :project_id => 1, :author => user,
470 :assigned_to => user)
470 :assigned_to => user)
471 assert_equal [1, 2, 3, 4, 5], issue.new_statuses_allowed_to(user).map(&:id)
471 assert_equal [1, 2, 3, 4, 5], issue.new_statuses_allowed_to(user).map(&:id)
472 end
472 end
473
473
474 def test_new_statuses_allowed_to_should_return_all_transitions_for_admin
474 def test_new_statuses_allowed_to_should_return_all_transitions_for_admin
475 admin = User.find(1)
475 admin = User.find(1)
476 issue = Issue.find(1)
476 issue = Issue.find(1)
477 assert !admin.member_of?(issue.project)
477 assert !admin.member_of?(issue.project)
478 expected_statuses = [issue.status] +
478 expected_statuses = [issue.status] +
479 WorkflowTransition.find_all_by_old_status_id(
479 WorkflowTransition.find_all_by_old_status_id(
480 issue.status_id).map(&:new_status).uniq.sort
480 issue.status_id).map(&:new_status).uniq.sort
481 assert_equal expected_statuses, issue.new_statuses_allowed_to(admin)
481 assert_equal expected_statuses, issue.new_statuses_allowed_to(admin)
482 end
482 end
483
483
484 def test_new_statuses_allowed_to_should_return_default_and_current_status_when_copying
484 def test_new_statuses_allowed_to_should_return_default_and_current_status_when_copying
485 issue = Issue.find(1).copy
485 issue = Issue.find(1).copy
486 assert_equal [1], issue.new_statuses_allowed_to(User.find(2)).map(&:id)
486 assert_equal [1], issue.new_statuses_allowed_to(User.find(2)).map(&:id)
487
487
488 issue = Issue.find(2).copy
488 issue = Issue.find(2).copy
489 assert_equal [1, 2], issue.new_statuses_allowed_to(User.find(2)).map(&:id)
489 assert_equal [1, 2], issue.new_statuses_allowed_to(User.find(2)).map(&:id)
490 end
490 end
491
491
492 def test_safe_attributes_names_should_not_include_disabled_field
492 def test_safe_attributes_names_should_not_include_disabled_field
493 tracker = Tracker.new(:core_fields => %w(assigned_to_id fixed_version_id))
493 tracker = Tracker.new(:core_fields => %w(assigned_to_id fixed_version_id))
494
494
495 issue = Issue.new(:tracker => tracker)
495 issue = Issue.new(:tracker => tracker)
496 assert_include 'tracker_id', issue.safe_attribute_names
496 assert_include 'tracker_id', issue.safe_attribute_names
497 assert_include 'status_id', issue.safe_attribute_names
497 assert_include 'status_id', issue.safe_attribute_names
498 assert_include 'subject', issue.safe_attribute_names
498 assert_include 'subject', issue.safe_attribute_names
499 assert_include 'description', issue.safe_attribute_names
499 assert_include 'description', issue.safe_attribute_names
500 assert_include 'custom_field_values', issue.safe_attribute_names
500 assert_include 'custom_field_values', issue.safe_attribute_names
501 assert_include 'custom_fields', issue.safe_attribute_names
501 assert_include 'custom_fields', issue.safe_attribute_names
502 assert_include 'lock_version', issue.safe_attribute_names
502 assert_include 'lock_version', issue.safe_attribute_names
503
503
504 tracker.core_fields.each do |field|
504 tracker.core_fields.each do |field|
505 assert_include field, issue.safe_attribute_names
505 assert_include field, issue.safe_attribute_names
506 end
506 end
507
507
508 tracker.disabled_core_fields.each do |field|
508 tracker.disabled_core_fields.each do |field|
509 assert_not_include field, issue.safe_attribute_names
509 assert_not_include field, issue.safe_attribute_names
510 end
510 end
511 end
511 end
512
512
513 def test_safe_attributes_should_ignore_disabled_fields
513 def test_safe_attributes_should_ignore_disabled_fields
514 tracker = Tracker.find(1)
514 tracker = Tracker.find(1)
515 tracker.core_fields = %w(assigned_to_id due_date)
515 tracker.core_fields = %w(assigned_to_id due_date)
516 tracker.save!
516 tracker.save!
517
517
518 issue = Issue.new(:tracker => tracker)
518 issue = Issue.new(:tracker => tracker)
519 issue.safe_attributes = {'start_date' => '2012-07-14', 'due_date' => '2012-07-14'}
519 issue.safe_attributes = {'start_date' => '2012-07-14', 'due_date' => '2012-07-14'}
520 assert_nil issue.start_date
520 assert_nil issue.start_date
521 assert_equal Date.parse('2012-07-14'), issue.due_date
521 assert_equal Date.parse('2012-07-14'), issue.due_date
522 end
522 end
523
523
524 def test_safe_attributes_should_accept_target_tracker_enabled_fields
524 def test_safe_attributes_should_accept_target_tracker_enabled_fields
525 source = Tracker.find(1)
525 source = Tracker.find(1)
526 source.core_fields = []
526 source.core_fields = []
527 source.save!
527 source.save!
528 target = Tracker.find(2)
528 target = Tracker.find(2)
529 target.core_fields = %w(assigned_to_id due_date)
529 target.core_fields = %w(assigned_to_id due_date)
530 target.save!
530 target.save!
531
531
532 issue = Issue.new(:tracker => source)
532 issue = Issue.new(:tracker => source)
533 issue.safe_attributes = {'tracker_id' => 2, 'due_date' => '2012-07-14'}
533 issue.safe_attributes = {'tracker_id' => 2, 'due_date' => '2012-07-14'}
534 assert_equal target, issue.tracker
534 assert_equal target, issue.tracker
535 assert_equal Date.parse('2012-07-14'), issue.due_date
535 assert_equal Date.parse('2012-07-14'), issue.due_date
536 end
536 end
537
537
538 def test_safe_attributes_should_not_include_readonly_fields
538 def test_safe_attributes_should_not_include_readonly_fields
539 WorkflowPermission.delete_all
539 WorkflowPermission.delete_all
540 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
540 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
541 :role_id => 1, :field_name => 'due_date',
541 :role_id => 1, :field_name => 'due_date',
542 :rule => 'readonly')
542 :rule => 'readonly')
543 user = User.find(2)
543 user = User.find(2)
544
544
545 issue = Issue.new(:project_id => 1, :tracker_id => 1)
545 issue = Issue.new(:project_id => 1, :tracker_id => 1)
546 assert_equal %w(due_date), issue.read_only_attribute_names(user)
546 assert_equal %w(due_date), issue.read_only_attribute_names(user)
547 assert_not_include 'due_date', issue.safe_attribute_names(user)
547 assert_not_include 'due_date', issue.safe_attribute_names(user)
548
548
549 issue.send :safe_attributes=, {'start_date' => '2012-07-14', 'due_date' => '2012-07-14'}, user
549 issue.send :safe_attributes=, {'start_date' => '2012-07-14', 'due_date' => '2012-07-14'}, user
550 assert_equal Date.parse('2012-07-14'), issue.start_date
550 assert_equal Date.parse('2012-07-14'), issue.start_date
551 assert_nil issue.due_date
551 assert_nil issue.due_date
552 end
552 end
553
553
554 def test_safe_attributes_should_not_include_readonly_custom_fields
554 def test_safe_attributes_should_not_include_readonly_custom_fields
555 cf1 = IssueCustomField.create!(:name => 'Writable field',
555 cf1 = IssueCustomField.create!(:name => 'Writable field',
556 :field_format => 'string',
556 :field_format => 'string',
557 :is_for_all => true, :tracker_ids => [1])
557 :is_for_all => true, :tracker_ids => [1])
558 cf2 = IssueCustomField.create!(:name => 'Readonly field',
558 cf2 = IssueCustomField.create!(:name => 'Readonly field',
559 :field_format => 'string',
559 :field_format => 'string',
560 :is_for_all => true, :tracker_ids => [1])
560 :is_for_all => true, :tracker_ids => [1])
561 WorkflowPermission.delete_all
561 WorkflowPermission.delete_all
562 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
562 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
563 :role_id => 1, :field_name => cf2.id.to_s,
563 :role_id => 1, :field_name => cf2.id.to_s,
564 :rule => 'readonly')
564 :rule => 'readonly')
565 user = User.find(2)
565 user = User.find(2)
566 issue = Issue.new(:project_id => 1, :tracker_id => 1)
566 issue = Issue.new(:project_id => 1, :tracker_id => 1)
567 assert_equal [cf2.id.to_s], issue.read_only_attribute_names(user)
567 assert_equal [cf2.id.to_s], issue.read_only_attribute_names(user)
568 assert_not_include cf2.id.to_s, issue.safe_attribute_names(user)
568 assert_not_include cf2.id.to_s, issue.safe_attribute_names(user)
569
569
570 issue.send :safe_attributes=, {'custom_field_values' => {
570 issue.send :safe_attributes=, {'custom_field_values' => {
571 cf1.id.to_s => 'value1', cf2.id.to_s => 'value2'
571 cf1.id.to_s => 'value1', cf2.id.to_s => 'value2'
572 }}, user
572 }}, user
573 assert_equal 'value1', issue.custom_field_value(cf1)
573 assert_equal 'value1', issue.custom_field_value(cf1)
574 assert_nil issue.custom_field_value(cf2)
574 assert_nil issue.custom_field_value(cf2)
575
575
576 issue.send :safe_attributes=, {'custom_fields' => [
576 issue.send :safe_attributes=, {'custom_fields' => [
577 {'id' => cf1.id.to_s, 'value' => 'valuea'},
577 {'id' => cf1.id.to_s, 'value' => 'valuea'},
578 {'id' => cf2.id.to_s, 'value' => 'valueb'}
578 {'id' => cf2.id.to_s, 'value' => 'valueb'}
579 ]}, user
579 ]}, user
580 assert_equal 'valuea', issue.custom_field_value(cf1)
580 assert_equal 'valuea', issue.custom_field_value(cf1)
581 assert_nil issue.custom_field_value(cf2)
581 assert_nil issue.custom_field_value(cf2)
582 end
582 end
583
583
584 def test_editable_custom_field_values_should_return_non_readonly_custom_values
584 def test_editable_custom_field_values_should_return_non_readonly_custom_values
585 cf1 = IssueCustomField.create!(:name => 'Writable field', :field_format => 'string',
585 cf1 = IssueCustomField.create!(:name => 'Writable field', :field_format => 'string',
586 :is_for_all => true, :tracker_ids => [1, 2])
586 :is_for_all => true, :tracker_ids => [1, 2])
587 cf2 = IssueCustomField.create!(:name => 'Readonly field', :field_format => 'string',
587 cf2 = IssueCustomField.create!(:name => 'Readonly field', :field_format => 'string',
588 :is_for_all => true, :tracker_ids => [1, 2])
588 :is_for_all => true, :tracker_ids => [1, 2])
589 WorkflowPermission.delete_all
589 WorkflowPermission.delete_all
590 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, :role_id => 1,
590 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, :role_id => 1,
591 :field_name => cf2.id.to_s, :rule => 'readonly')
591 :field_name => cf2.id.to_s, :rule => 'readonly')
592 user = User.find(2)
592 user = User.find(2)
593
593
594 issue = Issue.new(:project_id => 1, :tracker_id => 1)
594 issue = Issue.new(:project_id => 1, :tracker_id => 1)
595 values = issue.editable_custom_field_values(user)
595 values = issue.editable_custom_field_values(user)
596 assert values.detect {|value| value.custom_field == cf1}
596 assert values.detect {|value| value.custom_field == cf1}
597 assert_nil values.detect {|value| value.custom_field == cf2}
597 assert_nil values.detect {|value| value.custom_field == cf2}
598
598
599 issue.tracker_id = 2
599 issue.tracker_id = 2
600 values = issue.editable_custom_field_values(user)
600 values = issue.editable_custom_field_values(user)
601 assert values.detect {|value| value.custom_field == cf1}
601 assert values.detect {|value| value.custom_field == cf1}
602 assert values.detect {|value| value.custom_field == cf2}
602 assert values.detect {|value| value.custom_field == cf2}
603 end
603 end
604
604
605 def test_safe_attributes_should_accept_target_tracker_writable_fields
605 def test_safe_attributes_should_accept_target_tracker_writable_fields
606 WorkflowPermission.delete_all
606 WorkflowPermission.delete_all
607 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
607 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
608 :role_id => 1, :field_name => 'due_date',
608 :role_id => 1, :field_name => 'due_date',
609 :rule => 'readonly')
609 :rule => 'readonly')
610 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2,
610 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2,
611 :role_id => 1, :field_name => 'start_date',
611 :role_id => 1, :field_name => 'start_date',
612 :rule => 'readonly')
612 :rule => 'readonly')
613 user = User.find(2)
613 user = User.find(2)
614
614
615 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1)
615 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1)
616
616
617 issue.send :safe_attributes=, {'start_date' => '2012-07-12',
617 issue.send :safe_attributes=, {'start_date' => '2012-07-12',
618 'due_date' => '2012-07-14'}, user
618 'due_date' => '2012-07-14'}, user
619 assert_equal Date.parse('2012-07-12'), issue.start_date
619 assert_equal Date.parse('2012-07-12'), issue.start_date
620 assert_nil issue.due_date
620 assert_nil issue.due_date
621
621
622 issue.send :safe_attributes=, {'start_date' => '2012-07-15',
622 issue.send :safe_attributes=, {'start_date' => '2012-07-15',
623 'due_date' => '2012-07-16',
623 'due_date' => '2012-07-16',
624 'tracker_id' => 2}, user
624 'tracker_id' => 2}, user
625 assert_equal Date.parse('2012-07-12'), issue.start_date
625 assert_equal Date.parse('2012-07-12'), issue.start_date
626 assert_equal Date.parse('2012-07-16'), issue.due_date
626 assert_equal Date.parse('2012-07-16'), issue.due_date
627 end
627 end
628
628
629 def test_safe_attributes_should_accept_target_status_writable_fields
629 def test_safe_attributes_should_accept_target_status_writable_fields
630 WorkflowPermission.delete_all
630 WorkflowPermission.delete_all
631 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
631 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
632 :role_id => 1, :field_name => 'due_date',
632 :role_id => 1, :field_name => 'due_date',
633 :rule => 'readonly')
633 :rule => 'readonly')
634 WorkflowPermission.create!(:old_status_id => 2, :tracker_id => 1,
634 WorkflowPermission.create!(:old_status_id => 2, :tracker_id => 1,
635 :role_id => 1, :field_name => 'start_date',
635 :role_id => 1, :field_name => 'start_date',
636 :rule => 'readonly')
636 :rule => 'readonly')
637 user = User.find(2)
637 user = User.find(2)
638
638
639 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1)
639 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1)
640
640
641 issue.send :safe_attributes=, {'start_date' => '2012-07-12',
641 issue.send :safe_attributes=, {'start_date' => '2012-07-12',
642 'due_date' => '2012-07-14'},
642 'due_date' => '2012-07-14'},
643 user
643 user
644 assert_equal Date.parse('2012-07-12'), issue.start_date
644 assert_equal Date.parse('2012-07-12'), issue.start_date
645 assert_nil issue.due_date
645 assert_nil issue.due_date
646
646
647 issue.send :safe_attributes=, {'start_date' => '2012-07-15',
647 issue.send :safe_attributes=, {'start_date' => '2012-07-15',
648 'due_date' => '2012-07-16',
648 'due_date' => '2012-07-16',
649 'status_id' => 2},
649 'status_id' => 2},
650 user
650 user
651 assert_equal Date.parse('2012-07-12'), issue.start_date
651 assert_equal Date.parse('2012-07-12'), issue.start_date
652 assert_equal Date.parse('2012-07-16'), issue.due_date
652 assert_equal Date.parse('2012-07-16'), issue.due_date
653 end
653 end
654
654
655 def test_required_attributes_should_be_validated
655 def test_required_attributes_should_be_validated
656 cf = IssueCustomField.create!(:name => 'Foo', :field_format => 'string',
656 cf = IssueCustomField.create!(:name => 'Foo', :field_format => 'string',
657 :is_for_all => true, :tracker_ids => [1, 2])
657 :is_for_all => true, :tracker_ids => [1, 2])
658
658
659 WorkflowPermission.delete_all
659 WorkflowPermission.delete_all
660 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
660 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
661 :role_id => 1, :field_name => 'due_date',
661 :role_id => 1, :field_name => 'due_date',
662 :rule => 'required')
662 :rule => 'required')
663 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
663 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
664 :role_id => 1, :field_name => 'category_id',
664 :role_id => 1, :field_name => 'category_id',
665 :rule => 'required')
665 :rule => 'required')
666 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
666 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
667 :role_id => 1, :field_name => cf.id.to_s,
667 :role_id => 1, :field_name => cf.id.to_s,
668 :rule => 'required')
668 :rule => 'required')
669
669
670 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2,
670 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2,
671 :role_id => 1, :field_name => 'start_date',
671 :role_id => 1, :field_name => 'start_date',
672 :rule => 'required')
672 :rule => 'required')
673 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2,
673 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2,
674 :role_id => 1, :field_name => cf.id.to_s,
674 :role_id => 1, :field_name => cf.id.to_s,
675 :rule => 'required')
675 :rule => 'required')
676 user = User.find(2)
676 user = User.find(2)
677
677
678 issue = Issue.new(:project_id => 1, :tracker_id => 1,
678 issue = Issue.new(:project_id => 1, :tracker_id => 1,
679 :status_id => 1, :subject => 'Required fields',
679 :status_id => 1, :subject => 'Required fields',
680 :author => user)
680 :author => user)
681 assert_equal [cf.id.to_s, "category_id", "due_date"],
681 assert_equal [cf.id.to_s, "category_id", "due_date"],
682 issue.required_attribute_names(user).sort
682 issue.required_attribute_names(user).sort
683 assert !issue.save, "Issue was saved"
683 assert !issue.save, "Issue was saved"
684 assert_equal ["Category can't be blank", "Due date can't be blank", "Foo can't be blank"],
684 assert_equal ["Category can't be blank", "Due date can't be blank", "Foo can't be blank"],
685 issue.errors.full_messages.sort
685 issue.errors.full_messages.sort
686
686
687 issue.tracker_id = 2
687 issue.tracker_id = 2
688 assert_equal [cf.id.to_s, "start_date"], issue.required_attribute_names(user).sort
688 assert_equal [cf.id.to_s, "start_date"], issue.required_attribute_names(user).sort
689 assert !issue.save, "Issue was saved"
689 assert !issue.save, "Issue was saved"
690 assert_equal ["Foo can't be blank", "Start date can't be blank"],
690 assert_equal ["Foo can't be blank", "Start date can't be blank"],
691 issue.errors.full_messages.sort
691 issue.errors.full_messages.sort
692
692
693 issue.start_date = Date.today
693 issue.start_date = Date.today
694 issue.custom_field_values = {cf.id.to_s => 'bar'}
694 issue.custom_field_values = {cf.id.to_s => 'bar'}
695 assert issue.save
695 assert issue.save
696 end
696 end
697
697
698 def test_required_attribute_names_for_multiple_roles_should_intersect_rules
698 def test_required_attribute_names_for_multiple_roles_should_intersect_rules
699 WorkflowPermission.delete_all
699 WorkflowPermission.delete_all
700 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
700 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
701 :role_id => 1, :field_name => 'due_date',
701 :role_id => 1, :field_name => 'due_date',
702 :rule => 'required')
702 :rule => 'required')
703 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
703 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
704 :role_id => 1, :field_name => 'start_date',
704 :role_id => 1, :field_name => 'start_date',
705 :rule => 'required')
705 :rule => 'required')
706 user = User.find(2)
706 user = User.find(2)
707 member = Member.find(1)
707 member = Member.find(1)
708 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1)
708 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1)
709
709
710 assert_equal %w(due_date start_date), issue.required_attribute_names(user).sort
710 assert_equal %w(due_date start_date), issue.required_attribute_names(user).sort
711
711
712 member.role_ids = [1, 2]
712 member.role_ids = [1, 2]
713 member.save!
713 member.save!
714 assert_equal [], issue.required_attribute_names(user.reload)
714 assert_equal [], issue.required_attribute_names(user.reload)
715
715
716 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
716 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
717 :role_id => 2, :field_name => 'due_date',
717 :role_id => 2, :field_name => 'due_date',
718 :rule => 'required')
718 :rule => 'required')
719 assert_equal %w(due_date), issue.required_attribute_names(user)
719 assert_equal %w(due_date), issue.required_attribute_names(user)
720
720
721 member.role_ids = [1, 2, 3]
721 member.role_ids = [1, 2, 3]
722 member.save!
722 member.save!
723 assert_equal [], issue.required_attribute_names(user.reload)
723 assert_equal [], issue.required_attribute_names(user.reload)
724
724
725 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
725 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
726 :role_id => 2, :field_name => 'due_date',
726 :role_id => 2, :field_name => 'due_date',
727 :rule => 'readonly')
727 :rule => 'readonly')
728 # required + readonly => required
728 # required + readonly => required
729 assert_equal %w(due_date), issue.required_attribute_names(user)
729 assert_equal %w(due_date), issue.required_attribute_names(user)
730 end
730 end
731
731
732 def test_read_only_attribute_names_for_multiple_roles_should_intersect_rules
732 def test_read_only_attribute_names_for_multiple_roles_should_intersect_rules
733 WorkflowPermission.delete_all
733 WorkflowPermission.delete_all
734 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
734 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
735 :role_id => 1, :field_name => 'due_date',
735 :role_id => 1, :field_name => 'due_date',
736 :rule => 'readonly')
736 :rule => 'readonly')
737 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
737 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
738 :role_id => 1, :field_name => 'start_date',
738 :role_id => 1, :field_name => 'start_date',
739 :rule => 'readonly')
739 :rule => 'readonly')
740 user = User.find(2)
740 user = User.find(2)
741 member = Member.find(1)
741 member = Member.find(1)
742 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1)
742 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1)
743
743
744 assert_equal %w(due_date start_date), issue.read_only_attribute_names(user).sort
744 assert_equal %w(due_date start_date), issue.read_only_attribute_names(user).sort
745
745
746 member.role_ids = [1, 2]
746 member.role_ids = [1, 2]
747 member.save!
747 member.save!
748 assert_equal [], issue.read_only_attribute_names(user.reload)
748 assert_equal [], issue.read_only_attribute_names(user.reload)
749
749
750 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
750 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
751 :role_id => 2, :field_name => 'due_date',
751 :role_id => 2, :field_name => 'due_date',
752 :rule => 'readonly')
752 :rule => 'readonly')
753 assert_equal %w(due_date), issue.read_only_attribute_names(user)
753 assert_equal %w(due_date), issue.read_only_attribute_names(user)
754 end
754 end
755
755
756 def test_copy
756 def test_copy
757 issue = Issue.new.copy_from(1)
757 issue = Issue.new.copy_from(1)
758 assert issue.copy?
758 assert issue.copy?
759 assert issue.save
759 assert issue.save
760 issue.reload
760 issue.reload
761 orig = Issue.find(1)
761 orig = Issue.find(1)
762 assert_equal orig.subject, issue.subject
762 assert_equal orig.subject, issue.subject
763 assert_equal orig.tracker, issue.tracker
763 assert_equal orig.tracker, issue.tracker
764 assert_equal "125", issue.custom_value_for(2).value
764 assert_equal "125", issue.custom_value_for(2).value
765 end
765 end
766
766
767 def test_copy_should_copy_status
767 def test_copy_should_copy_status
768 orig = Issue.find(8)
768 orig = Issue.find(8)
769 assert orig.status != IssueStatus.default
769 assert orig.status != IssueStatus.default
770
770
771 issue = Issue.new.copy_from(orig)
771 issue = Issue.new.copy_from(orig)
772 assert issue.save
772 assert issue.save
773 issue.reload
773 issue.reload
774 assert_equal orig.status, issue.status
774 assert_equal orig.status, issue.status
775 end
775 end
776
776
777 def test_copy_should_add_relation_with_copied_issue
777 def test_copy_should_add_relation_with_copied_issue
778 copied = Issue.find(1)
778 copied = Issue.find(1)
779 issue = Issue.new.copy_from(copied)
779 issue = Issue.new.copy_from(copied)
780 assert issue.save
780 assert issue.save
781 issue.reload
781 issue.reload
782
782
783 assert_equal 1, issue.relations.size
783 assert_equal 1, issue.relations.size
784 relation = issue.relations.first
784 relation = issue.relations.first
785 assert_equal 'copied_to', relation.relation_type
785 assert_equal 'copied_to', relation.relation_type
786 assert_equal copied, relation.issue_from
786 assert_equal copied, relation.issue_from
787 assert_equal issue, relation.issue_to
787 assert_equal issue, relation.issue_to
788 end
788 end
789
789
790 def test_copy_should_copy_subtasks
790 def test_copy_should_copy_subtasks
791 issue = Issue.generate_with_descendants!
791 issue = Issue.generate_with_descendants!
792
792
793 copy = issue.reload.copy
793 copy = issue.reload.copy
794 copy.author = User.find(7)
794 copy.author = User.find(7)
795 assert_difference 'Issue.count', 1+issue.descendants.count do
795 assert_difference 'Issue.count', 1+issue.descendants.count do
796 assert copy.save
796 assert copy.save
797 end
797 end
798 copy.reload
798 copy.reload
799 assert_equal %w(Child1 Child2), copy.children.map(&:subject).sort
799 assert_equal %w(Child1 Child2), copy.children.map(&:subject).sort
800 child_copy = copy.children.detect {|c| c.subject == 'Child1'}
800 child_copy = copy.children.detect {|c| c.subject == 'Child1'}
801 assert_equal %w(Child11), child_copy.children.map(&:subject).sort
801 assert_equal %w(Child11), child_copy.children.map(&:subject).sort
802 assert_equal copy.author, child_copy.author
802 assert_equal copy.author, child_copy.author
803 end
803 end
804
804
805 def test_copy_should_copy_subtasks_to_target_project
805 def test_copy_should_copy_subtasks_to_target_project
806 issue = Issue.generate_with_descendants!
806 issue = Issue.generate_with_descendants!
807
807
808 copy = issue.copy(:project_id => 3)
808 copy = issue.copy(:project_id => 3)
809 assert_difference 'Issue.count', 1+issue.descendants.count do
809 assert_difference 'Issue.count', 1+issue.descendants.count do
810 assert copy.save
810 assert copy.save
811 end
811 end
812 assert_equal [3], copy.reload.descendants.map(&:project_id).uniq
812 assert_equal [3], copy.reload.descendants.map(&:project_id).uniq
813 end
813 end
814
814
815 def test_copy_should_not_copy_subtasks_twice_when_saving_twice
815 def test_copy_should_not_copy_subtasks_twice_when_saving_twice
816 issue = Issue.generate_with_descendants!
816 issue = Issue.generate_with_descendants!
817
817
818 copy = issue.reload.copy
818 copy = issue.reload.copy
819 assert_difference 'Issue.count', 1+issue.descendants.count do
819 assert_difference 'Issue.count', 1+issue.descendants.count do
820 assert copy.save
820 assert copy.save
821 assert copy.save
821 assert copy.save
822 end
822 end
823 end
823 end
824
824
825 def test_should_not_call_after_project_change_on_creation
825 def test_should_not_call_after_project_change_on_creation
826 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1,
826 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1,
827 :subject => 'Test', :author_id => 1)
827 :subject => 'Test', :author_id => 1)
828 issue.expects(:after_project_change).never
828 issue.expects(:after_project_change).never
829 issue.save!
829 issue.save!
830 end
830 end
831
831
832 def test_should_not_call_after_project_change_on_update
832 def test_should_not_call_after_project_change_on_update
833 issue = Issue.find(1)
833 issue = Issue.find(1)
834 issue.project = Project.find(1)
834 issue.project = Project.find(1)
835 issue.subject = 'No project change'
835 issue.subject = 'No project change'
836 issue.expects(:after_project_change).never
836 issue.expects(:after_project_change).never
837 issue.save!
837 issue.save!
838 end
838 end
839
839
840 def test_should_call_after_project_change_on_project_change
840 def test_should_call_after_project_change_on_project_change
841 issue = Issue.find(1)
841 issue = Issue.find(1)
842 issue.project = Project.find(2)
842 issue.project = Project.find(2)
843 issue.expects(:after_project_change).once
843 issue.expects(:after_project_change).once
844 issue.save!
844 issue.save!
845 end
845 end
846
846
847 def test_adding_journal_should_update_timestamp
847 def test_adding_journal_should_update_timestamp
848 issue = Issue.find(1)
848 issue = Issue.find(1)
849 updated_on_was = issue.updated_on
849 updated_on_was = issue.updated_on
850
850
851 issue.init_journal(User.first, "Adding notes")
851 issue.init_journal(User.first, "Adding notes")
852 assert_difference 'Journal.count' do
852 assert_difference 'Journal.count' do
853 assert issue.save
853 assert issue.save
854 end
854 end
855 issue.reload
855 issue.reload
856
856
857 assert_not_equal updated_on_was, issue.updated_on
857 assert_not_equal updated_on_was, issue.updated_on
858 end
858 end
859
859
860 def test_should_close_duplicates
860 def test_should_close_duplicates
861 # Create 3 issues
861 # Create 3 issues
862 issue1 = Issue.generate!
862 issue1 = Issue.generate!
863 issue2 = Issue.generate!
863 issue2 = Issue.generate!
864 issue3 = Issue.generate!
864 issue3 = Issue.generate!
865
865
866 # 2 is a dupe of 1
866 # 2 is a dupe of 1
867 IssueRelation.create!(:issue_from => issue2, :issue_to => issue1,
867 IssueRelation.create!(:issue_from => issue2, :issue_to => issue1,
868 :relation_type => IssueRelation::TYPE_DUPLICATES)
868 :relation_type => IssueRelation::TYPE_DUPLICATES)
869 # And 3 is a dupe of 2
869 # And 3 is a dupe of 2
870 IssueRelation.create!(:issue_from => issue3, :issue_to => issue2,
870 IssueRelation.create!(:issue_from => issue3, :issue_to => issue2,
871 :relation_type => IssueRelation::TYPE_DUPLICATES)
871 :relation_type => IssueRelation::TYPE_DUPLICATES)
872 # And 3 is a dupe of 1 (circular duplicates)
872 # And 3 is a dupe of 1 (circular duplicates)
873 IssueRelation.create!(:issue_from => issue3, :issue_to => issue1,
873 IssueRelation.create!(:issue_from => issue3, :issue_to => issue1,
874 :relation_type => IssueRelation::TYPE_DUPLICATES)
874 :relation_type => IssueRelation::TYPE_DUPLICATES)
875
875
876 assert issue1.reload.duplicates.include?(issue2)
876 assert issue1.reload.duplicates.include?(issue2)
877
877
878 # Closing issue 1
878 # Closing issue 1
879 issue1.init_journal(User.find(:first), "Closing issue1")
879 issue1.init_journal(User.find(:first), "Closing issue1")
880 issue1.status = IssueStatus.find :first, :conditions => {:is_closed => true}
880 issue1.status = IssueStatus.find :first, :conditions => {:is_closed => true}
881 assert issue1.save
881 assert issue1.save
882 # 2 and 3 should be also closed
882 # 2 and 3 should be also closed
883 assert issue2.reload.closed?
883 assert issue2.reload.closed?
884 assert issue3.reload.closed?
884 assert issue3.reload.closed?
885 end
885 end
886
886
887 def test_should_not_close_duplicated_issue
887 def test_should_not_close_duplicated_issue
888 issue1 = Issue.generate!
888 issue1 = Issue.generate!
889 issue2 = Issue.generate!
889 issue2 = Issue.generate!
890
890
891 # 2 is a dupe of 1
891 # 2 is a dupe of 1
892 IssueRelation.create(:issue_from => issue2, :issue_to => issue1,
892 IssueRelation.create(:issue_from => issue2, :issue_to => issue1,
893 :relation_type => IssueRelation::TYPE_DUPLICATES)
893 :relation_type => IssueRelation::TYPE_DUPLICATES)
894 # 2 is a dup of 1 but 1 is not a duplicate of 2
894 # 2 is a dup of 1 but 1 is not a duplicate of 2
895 assert !issue2.reload.duplicates.include?(issue1)
895 assert !issue2.reload.duplicates.include?(issue1)
896
896
897 # Closing issue 2
897 # Closing issue 2
898 issue2.init_journal(User.find(:first), "Closing issue2")
898 issue2.init_journal(User.find(:first), "Closing issue2")
899 issue2.status = IssueStatus.find :first, :conditions => {:is_closed => true}
899 issue2.status = IssueStatus.find :first, :conditions => {:is_closed => true}
900 assert issue2.save
900 assert issue2.save
901 # 1 should not be also closed
901 # 1 should not be also closed
902 assert !issue1.reload.closed?
902 assert !issue1.reload.closed?
903 end
903 end
904
904
905 def test_assignable_versions
905 def test_assignable_versions
906 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
906 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
907 :status_id => 1, :fixed_version_id => 1,
907 :status_id => 1, :fixed_version_id => 1,
908 :subject => 'New issue')
908 :subject => 'New issue')
909 assert_equal ['open'], issue.assignable_versions.collect(&:status).uniq
909 assert_equal ['open'], issue.assignable_versions.collect(&:status).uniq
910 end
910 end
911
911
912 def test_should_not_be_able_to_assign_a_new_issue_to_a_closed_version
912 def test_should_not_be_able_to_assign_a_new_issue_to_a_closed_version
913 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
913 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
914 :status_id => 1, :fixed_version_id => 1,
914 :status_id => 1, :fixed_version_id => 1,
915 :subject => 'New issue')
915 :subject => 'New issue')
916 assert !issue.save
916 assert !issue.save
917 assert_not_nil issue.errors[:fixed_version_id]
917 assert_not_nil issue.errors[:fixed_version_id]
918 end
918 end
919
919
920 def test_should_not_be_able_to_assign_a_new_issue_to_a_locked_version
920 def test_should_not_be_able_to_assign_a_new_issue_to_a_locked_version
921 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
921 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
922 :status_id => 1, :fixed_version_id => 2,
922 :status_id => 1, :fixed_version_id => 2,
923 :subject => 'New issue')
923 :subject => 'New issue')
924 assert !issue.save
924 assert !issue.save
925 assert_not_nil issue.errors[:fixed_version_id]
925 assert_not_nil issue.errors[:fixed_version_id]
926 end
926 end
927
927
928 def test_should_be_able_to_assign_a_new_issue_to_an_open_version
928 def test_should_be_able_to_assign_a_new_issue_to_an_open_version
929 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
929 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
930 :status_id => 1, :fixed_version_id => 3,
930 :status_id => 1, :fixed_version_id => 3,
931 :subject => 'New issue')
931 :subject => 'New issue')
932 assert issue.save
932 assert issue.save
933 end
933 end
934
934
935 def test_should_be_able_to_update_an_issue_assigned_to_a_closed_version
935 def test_should_be_able_to_update_an_issue_assigned_to_a_closed_version
936 issue = Issue.find(11)
936 issue = Issue.find(11)
937 assert_equal 'closed', issue.fixed_version.status
937 assert_equal 'closed', issue.fixed_version.status
938 issue.subject = 'Subject changed'
938 issue.subject = 'Subject changed'
939 assert issue.save
939 assert issue.save
940 end
940 end
941
941
942 def test_should_not_be_able_to_reopen_an_issue_assigned_to_a_closed_version
942 def test_should_not_be_able_to_reopen_an_issue_assigned_to_a_closed_version
943 issue = Issue.find(11)
943 issue = Issue.find(11)
944 issue.status_id = 1
944 issue.status_id = 1
945 assert !issue.save
945 assert !issue.save
946 assert_not_nil issue.errors[:base]
946 assert_not_nil issue.errors[:base]
947 end
947 end
948
948
949 def test_should_be_able_to_reopen_and_reassign_an_issue_assigned_to_a_closed_version
949 def test_should_be_able_to_reopen_and_reassign_an_issue_assigned_to_a_closed_version
950 issue = Issue.find(11)
950 issue = Issue.find(11)
951 issue.status_id = 1
951 issue.status_id = 1
952 issue.fixed_version_id = 3
952 issue.fixed_version_id = 3
953 assert issue.save
953 assert issue.save
954 end
954 end
955
955
956 def test_should_be_able_to_reopen_an_issue_assigned_to_a_locked_version
956 def test_should_be_able_to_reopen_an_issue_assigned_to_a_locked_version
957 issue = Issue.find(12)
957 issue = Issue.find(12)
958 assert_equal 'locked', issue.fixed_version.status
958 assert_equal 'locked', issue.fixed_version.status
959 issue.status_id = 1
959 issue.status_id = 1
960 assert issue.save
960 assert issue.save
961 end
961 end
962
962
963 def test_should_not_be_able_to_keep_unshared_version_when_changing_project
963 def test_should_not_be_able_to_keep_unshared_version_when_changing_project
964 issue = Issue.find(2)
964 issue = Issue.find(2)
965 assert_equal 2, issue.fixed_version_id
965 assert_equal 2, issue.fixed_version_id
966 issue.project_id = 3
966 issue.project_id = 3
967 assert_nil issue.fixed_version_id
967 assert_nil issue.fixed_version_id
968 issue.fixed_version_id = 2
968 issue.fixed_version_id = 2
969 assert !issue.save
969 assert !issue.save
970 assert_include 'Target version is not included in the list', issue.errors.full_messages
970 assert_include 'Target version is not included in the list', issue.errors.full_messages
971 end
971 end
972
972
973 def test_should_keep_shared_version_when_changing_project
973 def test_should_keep_shared_version_when_changing_project
974 Version.find(2).update_attribute :sharing, 'tree'
974 Version.find(2).update_attribute :sharing, 'tree'
975
975
976 issue = Issue.find(2)
976 issue = Issue.find(2)
977 assert_equal 2, issue.fixed_version_id
977 assert_equal 2, issue.fixed_version_id
978 issue.project_id = 3
978 issue.project_id = 3
979 assert_equal 2, issue.fixed_version_id
979 assert_equal 2, issue.fixed_version_id
980 assert issue.save
980 assert issue.save
981 end
981 end
982
982
983 def test_allowed_target_projects_on_move_should_include_projects_with_issue_tracking_enabled
983 def test_allowed_target_projects_on_move_should_include_projects_with_issue_tracking_enabled
984 assert_include Project.find(2), Issue.allowed_target_projects_on_move(User.find(2))
984 assert_include Project.find(2), Issue.allowed_target_projects_on_move(User.find(2))
985 end
985 end
986
986
987 def test_allowed_target_projects_on_move_should_not_include_projects_with_issue_tracking_disabled
987 def test_allowed_target_projects_on_move_should_not_include_projects_with_issue_tracking_disabled
988 Project.find(2).disable_module! :issue_tracking
988 Project.find(2).disable_module! :issue_tracking
989 assert_not_include Project.find(2), Issue.allowed_target_projects_on_move(User.find(2))
989 assert_not_include Project.find(2), Issue.allowed_target_projects_on_move(User.find(2))
990 end
990 end
991
991
992 def test_move_to_another_project_with_same_category
992 def test_move_to_another_project_with_same_category
993 issue = Issue.find(1)
993 issue = Issue.find(1)
994 issue.project = Project.find(2)
994 issue.project = Project.find(2)
995 assert issue.save
995 assert issue.save
996 issue.reload
996 issue.reload
997 assert_equal 2, issue.project_id
997 assert_equal 2, issue.project_id
998 # Category changes
998 # Category changes
999 assert_equal 4, issue.category_id
999 assert_equal 4, issue.category_id
1000 # Make sure time entries were move to the target project
1000 # Make sure time entries were move to the target project
1001 assert_equal 2, issue.time_entries.first.project_id
1001 assert_equal 2, issue.time_entries.first.project_id
1002 end
1002 end
1003
1003
1004 def test_move_to_another_project_without_same_category
1004 def test_move_to_another_project_without_same_category
1005 issue = Issue.find(2)
1005 issue = Issue.find(2)
1006 issue.project = Project.find(2)
1006 issue.project = Project.find(2)
1007 assert issue.save
1007 assert issue.save
1008 issue.reload
1008 issue.reload
1009 assert_equal 2, issue.project_id
1009 assert_equal 2, issue.project_id
1010 # Category cleared
1010 # Category cleared
1011 assert_nil issue.category_id
1011 assert_nil issue.category_id
1012 end
1012 end
1013
1013
1014 def test_move_to_another_project_should_clear_fixed_version_when_not_shared
1014 def test_move_to_another_project_should_clear_fixed_version_when_not_shared
1015 issue = Issue.find(1)
1015 issue = Issue.find(1)
1016 issue.update_attribute(:fixed_version_id, 1)
1016 issue.update_attribute(:fixed_version_id, 1)
1017 issue.project = Project.find(2)
1017 issue.project = Project.find(2)
1018 assert issue.save
1018 assert issue.save
1019 issue.reload
1019 issue.reload
1020 assert_equal 2, issue.project_id
1020 assert_equal 2, issue.project_id
1021 # Cleared fixed_version
1021 # Cleared fixed_version
1022 assert_equal nil, issue.fixed_version
1022 assert_equal nil, issue.fixed_version
1023 end
1023 end
1024
1024
1025 def test_move_to_another_project_should_keep_fixed_version_when_shared_with_the_target_project
1025 def test_move_to_another_project_should_keep_fixed_version_when_shared_with_the_target_project
1026 issue = Issue.find(1)
1026 issue = Issue.find(1)
1027 issue.update_attribute(:fixed_version_id, 4)
1027 issue.update_attribute(:fixed_version_id, 4)
1028 issue.project = Project.find(5)
1028 issue.project = Project.find(5)
1029 assert issue.save
1029 assert issue.save
1030 issue.reload
1030 issue.reload
1031 assert_equal 5, issue.project_id
1031 assert_equal 5, issue.project_id
1032 # Keep fixed_version
1032 # Keep fixed_version
1033 assert_equal 4, issue.fixed_version_id
1033 assert_equal 4, issue.fixed_version_id
1034 end
1034 end
1035
1035
1036 def test_move_to_another_project_should_clear_fixed_version_when_not_shared_with_the_target_project
1036 def test_move_to_another_project_should_clear_fixed_version_when_not_shared_with_the_target_project
1037 issue = Issue.find(1)
1037 issue = Issue.find(1)
1038 issue.update_attribute(:fixed_version_id, 1)
1038 issue.update_attribute(:fixed_version_id, 1)
1039 issue.project = Project.find(5)
1039 issue.project = Project.find(5)
1040 assert issue.save
1040 assert issue.save
1041 issue.reload
1041 issue.reload
1042 assert_equal 5, issue.project_id
1042 assert_equal 5, issue.project_id
1043 # Cleared fixed_version
1043 # Cleared fixed_version
1044 assert_equal nil, issue.fixed_version
1044 assert_equal nil, issue.fixed_version
1045 end
1045 end
1046
1046
1047 def test_move_to_another_project_should_keep_fixed_version_when_shared_systemwide
1047 def test_move_to_another_project_should_keep_fixed_version_when_shared_systemwide
1048 issue = Issue.find(1)
1048 issue = Issue.find(1)
1049 issue.update_attribute(:fixed_version_id, 7)
1049 issue.update_attribute(:fixed_version_id, 7)
1050 issue.project = Project.find(2)
1050 issue.project = Project.find(2)
1051 assert issue.save
1051 assert issue.save
1052 issue.reload
1052 issue.reload
1053 assert_equal 2, issue.project_id
1053 assert_equal 2, issue.project_id
1054 # Keep fixed_version
1054 # Keep fixed_version
1055 assert_equal 7, issue.fixed_version_id
1055 assert_equal 7, issue.fixed_version_id
1056 end
1056 end
1057
1057
1058 def test_move_to_another_project_should_keep_parent_if_valid
1058 def test_move_to_another_project_should_keep_parent_if_valid
1059 issue = Issue.find(1)
1059 issue = Issue.find(1)
1060 issue.update_attribute(:parent_issue_id, 2)
1060 issue.update_attribute(:parent_issue_id, 2)
1061 issue.project = Project.find(3)
1061 issue.project = Project.find(3)
1062 assert issue.save
1062 assert issue.save
1063 issue.reload
1063 issue.reload
1064 assert_equal 2, issue.parent_id
1064 assert_equal 2, issue.parent_id
1065 end
1065 end
1066
1066
1067 def test_move_to_another_project_should_clear_parent_if_not_valid
1067 def test_move_to_another_project_should_clear_parent_if_not_valid
1068 issue = Issue.find(1)
1068 issue = Issue.find(1)
1069 issue.update_attribute(:parent_issue_id, 2)
1069 issue.update_attribute(:parent_issue_id, 2)
1070 issue.project = Project.find(2)
1070 issue.project = Project.find(2)
1071 assert issue.save
1071 assert issue.save
1072 issue.reload
1072 issue.reload
1073 assert_nil issue.parent_id
1073 assert_nil issue.parent_id
1074 end
1074 end
1075
1075
1076 def test_move_to_another_project_with_disabled_tracker
1076 def test_move_to_another_project_with_disabled_tracker
1077 issue = Issue.find(1)
1077 issue = Issue.find(1)
1078 target = Project.find(2)
1078 target = Project.find(2)
1079 target.tracker_ids = [3]
1079 target.tracker_ids = [3]
1080 target.save
1080 target.save
1081 issue.project = target
1081 issue.project = target
1082 assert issue.save
1082 assert issue.save
1083 issue.reload
1083 issue.reload
1084 assert_equal 2, issue.project_id
1084 assert_equal 2, issue.project_id
1085 assert_equal 3, issue.tracker_id
1085 assert_equal 3, issue.tracker_id
1086 end
1086 end
1087
1087
1088 def test_copy_to_the_same_project
1088 def test_copy_to_the_same_project
1089 issue = Issue.find(1)
1089 issue = Issue.find(1)
1090 copy = issue.copy
1090 copy = issue.copy
1091 assert_difference 'Issue.count' do
1091 assert_difference 'Issue.count' do
1092 copy.save!
1092 copy.save!
1093 end
1093 end
1094 assert_kind_of Issue, copy
1094 assert_kind_of Issue, copy
1095 assert_equal issue.project, copy.project
1095 assert_equal issue.project, copy.project
1096 assert_equal "125", copy.custom_value_for(2).value
1096 assert_equal "125", copy.custom_value_for(2).value
1097 end
1097 end
1098
1098
1099 def test_copy_to_another_project_and_tracker
1099 def test_copy_to_another_project_and_tracker
1100 issue = Issue.find(1)
1100 issue = Issue.find(1)
1101 copy = issue.copy(:project_id => 3, :tracker_id => 2)
1101 copy = issue.copy(:project_id => 3, :tracker_id => 2)
1102 assert_difference 'Issue.count' do
1102 assert_difference 'Issue.count' do
1103 copy.save!
1103 copy.save!
1104 end
1104 end
1105 copy.reload
1105 copy.reload
1106 assert_kind_of Issue, copy
1106 assert_kind_of Issue, copy
1107 assert_equal Project.find(3), copy.project
1107 assert_equal Project.find(3), copy.project
1108 assert_equal Tracker.find(2), copy.tracker
1108 assert_equal Tracker.find(2), copy.tracker
1109 # Custom field #2 is not associated with target tracker
1109 # Custom field #2 is not associated with target tracker
1110 assert_nil copy.custom_value_for(2)
1110 assert_nil copy.custom_value_for(2)
1111 end
1111 end
1112
1112
1113 context "#copy" do
1113 context "#copy" do
1114 setup do
1114 setup do
1115 @issue = Issue.find(1)
1115 @issue = Issue.find(1)
1116 end
1116 end
1117
1117
1118 should "not create a journal" do
1118 should "not create a journal" do
1119 copy = @issue.copy(:project_id => 3, :tracker_id => 2, :assigned_to_id => 3)
1119 copy = @issue.copy(:project_id => 3, :tracker_id => 2, :assigned_to_id => 3)
1120 copy.save!
1120 copy.save!
1121 assert_equal 0, copy.reload.journals.size
1121 assert_equal 0, copy.reload.journals.size
1122 end
1122 end
1123
1123
1124 should "allow assigned_to changes" do
1124 should "allow assigned_to changes" do
1125 copy = @issue.copy(:project_id => 3, :tracker_id => 2, :assigned_to_id => 3)
1125 copy = @issue.copy(:project_id => 3, :tracker_id => 2, :assigned_to_id => 3)
1126 assert_equal 3, copy.assigned_to_id
1126 assert_equal 3, copy.assigned_to_id
1127 end
1127 end
1128
1128
1129 should "allow status changes" do
1129 should "allow status changes" do
1130 copy = @issue.copy(:project_id => 3, :tracker_id => 2, :status_id => 2)
1130 copy = @issue.copy(:project_id => 3, :tracker_id => 2, :status_id => 2)
1131 assert_equal 2, copy.status_id
1131 assert_equal 2, copy.status_id
1132 end
1132 end
1133
1133
1134 should "allow start date changes" do
1134 should "allow start date changes" do
1135 date = Date.today
1135 date = Date.today
1136 copy = @issue.copy(:project_id => 3, :tracker_id => 2, :start_date => date)
1136 copy = @issue.copy(:project_id => 3, :tracker_id => 2, :start_date => date)
1137 assert_equal date, copy.start_date
1137 assert_equal date, copy.start_date
1138 end
1138 end
1139
1139
1140 should "allow due date changes" do
1140 should "allow due date changes" do
1141 date = Date.today
1141 date = Date.today
1142 copy = @issue.copy(:project_id => 3, :tracker_id => 2, :due_date => date)
1142 copy = @issue.copy(:project_id => 3, :tracker_id => 2, :due_date => date)
1143 assert_equal date, copy.due_date
1143 assert_equal date, copy.due_date
1144 end
1144 end
1145
1145
1146 should "set current user as author" do
1146 should "set current user as author" do
1147 User.current = User.find(9)
1147 User.current = User.find(9)
1148 copy = @issue.copy(:project_id => 3, :tracker_id => 2)
1148 copy = @issue.copy(:project_id => 3, :tracker_id => 2)
1149 assert_equal User.current, copy.author
1149 assert_equal User.current, copy.author
1150 end
1150 end
1151
1151
1152 should "create a journal with notes" do
1152 should "create a journal with notes" do
1153 date = Date.today
1153 date = Date.today
1154 notes = "Notes added when copying"
1154 notes = "Notes added when copying"
1155 copy = @issue.copy(:project_id => 3, :tracker_id => 2, :start_date => date)
1155 copy = @issue.copy(:project_id => 3, :tracker_id => 2, :start_date => date)
1156 copy.init_journal(User.current, notes)
1156 copy.init_journal(User.current, notes)
1157 copy.save!
1157 copy.save!
1158
1158
1159 assert_equal 1, copy.journals.size
1159 assert_equal 1, copy.journals.size
1160 journal = copy.journals.first
1160 journal = copy.journals.first
1161 assert_equal 0, journal.details.size
1161 assert_equal 0, journal.details.size
1162 assert_equal notes, journal.notes
1162 assert_equal notes, journal.notes
1163 end
1163 end
1164 end
1164 end
1165
1165
1166 def test_valid_parent_project
1166 def test_valid_parent_project
1167 issue = Issue.find(1)
1167 issue = Issue.find(1)
1168 issue_in_same_project = Issue.find(2)
1168 issue_in_same_project = Issue.find(2)
1169 issue_in_child_project = Issue.find(5)
1169 issue_in_child_project = Issue.find(5)
1170 issue_in_grandchild_project = Issue.generate!(:project_id => 6, :tracker_id => 1)
1170 issue_in_grandchild_project = Issue.generate!(:project_id => 6, :tracker_id => 1)
1171 issue_in_other_child_project = Issue.find(6)
1171 issue_in_other_child_project = Issue.find(6)
1172 issue_in_different_tree = Issue.find(4)
1172 issue_in_different_tree = Issue.find(4)
1173
1173
1174 with_settings :cross_project_subtasks => '' do
1174 with_settings :cross_project_subtasks => '' do
1175 assert_equal true, issue.valid_parent_project?(issue_in_same_project)
1175 assert_equal true, issue.valid_parent_project?(issue_in_same_project)
1176 assert_equal false, issue.valid_parent_project?(issue_in_child_project)
1176 assert_equal false, issue.valid_parent_project?(issue_in_child_project)
1177 assert_equal false, issue.valid_parent_project?(issue_in_grandchild_project)
1177 assert_equal false, issue.valid_parent_project?(issue_in_grandchild_project)
1178 assert_equal false, issue.valid_parent_project?(issue_in_different_tree)
1178 assert_equal false, issue.valid_parent_project?(issue_in_different_tree)
1179 end
1179 end
1180
1180
1181 with_settings :cross_project_subtasks => 'system' do
1181 with_settings :cross_project_subtasks => 'system' do
1182 assert_equal true, issue.valid_parent_project?(issue_in_same_project)
1182 assert_equal true, issue.valid_parent_project?(issue_in_same_project)
1183 assert_equal true, issue.valid_parent_project?(issue_in_child_project)
1183 assert_equal true, issue.valid_parent_project?(issue_in_child_project)
1184 assert_equal true, issue.valid_parent_project?(issue_in_different_tree)
1184 assert_equal true, issue.valid_parent_project?(issue_in_different_tree)
1185 end
1185 end
1186
1186
1187 with_settings :cross_project_subtasks => 'tree' do
1187 with_settings :cross_project_subtasks => 'tree' do
1188 assert_equal true, issue.valid_parent_project?(issue_in_same_project)
1188 assert_equal true, issue.valid_parent_project?(issue_in_same_project)
1189 assert_equal true, issue.valid_parent_project?(issue_in_child_project)
1189 assert_equal true, issue.valid_parent_project?(issue_in_child_project)
1190 assert_equal true, issue.valid_parent_project?(issue_in_grandchild_project)
1190 assert_equal true, issue.valid_parent_project?(issue_in_grandchild_project)
1191 assert_equal false, issue.valid_parent_project?(issue_in_different_tree)
1191 assert_equal false, issue.valid_parent_project?(issue_in_different_tree)
1192
1192
1193 assert_equal true, issue_in_child_project.valid_parent_project?(issue_in_same_project)
1193 assert_equal true, issue_in_child_project.valid_parent_project?(issue_in_same_project)
1194 assert_equal true, issue_in_child_project.valid_parent_project?(issue_in_other_child_project)
1194 assert_equal true, issue_in_child_project.valid_parent_project?(issue_in_other_child_project)
1195 end
1195 end
1196
1196
1197 with_settings :cross_project_subtasks => 'descendants' do
1197 with_settings :cross_project_subtasks => 'descendants' do
1198 assert_equal true, issue.valid_parent_project?(issue_in_same_project)
1198 assert_equal true, issue.valid_parent_project?(issue_in_same_project)
1199 assert_equal false, issue.valid_parent_project?(issue_in_child_project)
1199 assert_equal false, issue.valid_parent_project?(issue_in_child_project)
1200 assert_equal false, issue.valid_parent_project?(issue_in_grandchild_project)
1200 assert_equal false, issue.valid_parent_project?(issue_in_grandchild_project)
1201 assert_equal false, issue.valid_parent_project?(issue_in_different_tree)
1201 assert_equal false, issue.valid_parent_project?(issue_in_different_tree)
1202
1202
1203 assert_equal true, issue_in_child_project.valid_parent_project?(issue)
1203 assert_equal true, issue_in_child_project.valid_parent_project?(issue)
1204 assert_equal false, issue_in_child_project.valid_parent_project?(issue_in_other_child_project)
1204 assert_equal false, issue_in_child_project.valid_parent_project?(issue_in_other_child_project)
1205 end
1205 end
1206 end
1206 end
1207
1207
1208 def test_recipients_should_include_previous_assignee
1208 def test_recipients_should_include_previous_assignee
1209 user = User.find(3)
1209 user = User.find(3)
1210 user.members.update_all ["mail_notification = ?", false]
1210 user.members.update_all ["mail_notification = ?", false]
1211 user.update_attribute :mail_notification, 'only_assigned'
1211 user.update_attribute :mail_notification, 'only_assigned'
1212
1212
1213 issue = Issue.find(2)
1213 issue = Issue.find(2)
1214 issue.assigned_to = nil
1214 issue.assigned_to = nil
1215 assert_include user.mail, issue.recipients
1215 assert_include user.mail, issue.recipients
1216 issue.save!
1216 issue.save!
1217 assert !issue.recipients.include?(user.mail)
1217 assert !issue.recipients.include?(user.mail)
1218 end
1218 end
1219
1219
1220 def test_recipients_should_not_include_users_that_cannot_view_the_issue
1220 def test_recipients_should_not_include_users_that_cannot_view_the_issue
1221 issue = Issue.find(12)
1221 issue = Issue.find(12)
1222 assert issue.recipients.include?(issue.author.mail)
1222 assert issue.recipients.include?(issue.author.mail)
1223 # copy the issue to a private project
1223 # copy the issue to a private project
1224 copy = issue.copy(:project_id => 5, :tracker_id => 2)
1224 copy = issue.copy(:project_id => 5, :tracker_id => 2)
1225 # author is not a member of project anymore
1225 # author is not a member of project anymore
1226 assert !copy.recipients.include?(copy.author.mail)
1226 assert !copy.recipients.include?(copy.author.mail)
1227 end
1227 end
1228
1228
1229 def test_recipients_should_include_the_assigned_group_members
1229 def test_recipients_should_include_the_assigned_group_members
1230 group_member = User.generate!
1230 group_member = User.generate!
1231 group = Group.generate!
1231 group = Group.generate!
1232 group.users << group_member
1232 group.users << group_member
1233
1233
1234 issue = Issue.find(12)
1234 issue = Issue.find(12)
1235 issue.assigned_to = group
1235 issue.assigned_to = group
1236 assert issue.recipients.include?(group_member.mail)
1236 assert issue.recipients.include?(group_member.mail)
1237 end
1237 end
1238
1238
1239 def test_watcher_recipients_should_not_include_users_that_cannot_view_the_issue
1239 def test_watcher_recipients_should_not_include_users_that_cannot_view_the_issue
1240 user = User.find(3)
1240 user = User.find(3)
1241 issue = Issue.find(9)
1241 issue = Issue.find(9)
1242 Watcher.create!(:user => user, :watchable => issue)
1242 Watcher.create!(:user => user, :watchable => issue)
1243 assert issue.watched_by?(user)
1243 assert issue.watched_by?(user)
1244 assert !issue.watcher_recipients.include?(user.mail)
1244 assert !issue.watcher_recipients.include?(user.mail)
1245 end
1245 end
1246
1246
1247 def test_issue_destroy
1247 def test_issue_destroy
1248 Issue.find(1).destroy
1248 Issue.find(1).destroy
1249 assert_nil Issue.find_by_id(1)
1249 assert_nil Issue.find_by_id(1)
1250 assert_nil TimeEntry.find_by_issue_id(1)
1250 assert_nil TimeEntry.find_by_issue_id(1)
1251 end
1251 end
1252
1252
1253 def test_destroying_a_deleted_issue_should_not_raise_an_error
1253 def test_destroying_a_deleted_issue_should_not_raise_an_error
1254 issue = Issue.find(1)
1254 issue = Issue.find(1)
1255 Issue.find(1).destroy
1255 Issue.find(1).destroy
1256
1256
1257 assert_nothing_raised do
1257 assert_nothing_raised do
1258 assert_no_difference 'Issue.count' do
1258 assert_no_difference 'Issue.count' do
1259 issue.destroy
1259 issue.destroy
1260 end
1260 end
1261 assert issue.destroyed?
1261 assert issue.destroyed?
1262 end
1262 end
1263 end
1263 end
1264
1264
1265 def test_destroying_a_stale_issue_should_not_raise_an_error
1265 def test_destroying_a_stale_issue_should_not_raise_an_error
1266 issue = Issue.find(1)
1266 issue = Issue.find(1)
1267 Issue.find(1).update_attribute :subject, "Updated"
1267 Issue.find(1).update_attribute :subject, "Updated"
1268
1268
1269 assert_nothing_raised do
1269 assert_nothing_raised do
1270 assert_difference 'Issue.count', -1 do
1270 assert_difference 'Issue.count', -1 do
1271 issue.destroy
1271 issue.destroy
1272 end
1272 end
1273 assert issue.destroyed?
1273 assert issue.destroyed?
1274 end
1274 end
1275 end
1275 end
1276
1276
1277 def test_blocked
1277 def test_blocked
1278 blocked_issue = Issue.find(9)
1278 blocked_issue = Issue.find(9)
1279 blocking_issue = Issue.find(10)
1279 blocking_issue = Issue.find(10)
1280
1280
1281 assert blocked_issue.blocked?
1281 assert blocked_issue.blocked?
1282 assert !blocking_issue.blocked?
1282 assert !blocking_issue.blocked?
1283 end
1283 end
1284
1284
1285 def test_blocked_issues_dont_allow_closed_statuses
1285 def test_blocked_issues_dont_allow_closed_statuses
1286 blocked_issue = Issue.find(9)
1286 blocked_issue = Issue.find(9)
1287
1287
1288 allowed_statuses = blocked_issue.new_statuses_allowed_to(users(:users_002))
1288 allowed_statuses = blocked_issue.new_statuses_allowed_to(users(:users_002))
1289 assert !allowed_statuses.empty?
1289 assert !allowed_statuses.empty?
1290 closed_statuses = allowed_statuses.select {|st| st.is_closed?}
1290 closed_statuses = allowed_statuses.select {|st| st.is_closed?}
1291 assert closed_statuses.empty?
1291 assert closed_statuses.empty?
1292 end
1292 end
1293
1293
1294 def test_unblocked_issues_allow_closed_statuses
1294 def test_unblocked_issues_allow_closed_statuses
1295 blocking_issue = Issue.find(10)
1295 blocking_issue = Issue.find(10)
1296
1296
1297 allowed_statuses = blocking_issue.new_statuses_allowed_to(users(:users_002))
1297 allowed_statuses = blocking_issue.new_statuses_allowed_to(users(:users_002))
1298 assert !allowed_statuses.empty?
1298 assert !allowed_statuses.empty?
1299 closed_statuses = allowed_statuses.select {|st| st.is_closed?}
1299 closed_statuses = allowed_statuses.select {|st| st.is_closed?}
1300 assert !closed_statuses.empty?
1300 assert !closed_statuses.empty?
1301 end
1301 end
1302
1302
1303 def test_reschedule_an_issue_without_dates
1303 def test_reschedule_an_issue_without_dates
1304 with_settings :non_working_week_days => [] do
1304 with_settings :non_working_week_days => [] do
1305 issue = Issue.new(:start_date => nil, :due_date => nil)
1305 issue = Issue.new(:start_date => nil, :due_date => nil)
1306 issue.reschedule_on '2012-10-09'.to_date
1306 issue.reschedule_on '2012-10-09'.to_date
1307 assert_equal '2012-10-09'.to_date, issue.start_date
1307 assert_equal '2012-10-09'.to_date, issue.start_date
1308 assert_equal '2012-10-09'.to_date, issue.due_date
1308 assert_equal '2012-10-09'.to_date, issue.due_date
1309 end
1309 end
1310
1310
1311 with_settings :non_working_week_days => %w(6 7) do
1311 with_settings :non_working_week_days => %w(6 7) do
1312 issue = Issue.new(:start_date => nil, :due_date => nil)
1312 issue = Issue.new(:start_date => nil, :due_date => nil)
1313 issue.reschedule_on '2012-10-09'.to_date
1313 issue.reschedule_on '2012-10-09'.to_date
1314 assert_equal '2012-10-09'.to_date, issue.start_date
1314 assert_equal '2012-10-09'.to_date, issue.start_date
1315 assert_equal '2012-10-09'.to_date, issue.due_date
1315 assert_equal '2012-10-09'.to_date, issue.due_date
1316
1316
1317 issue = Issue.new(:start_date => nil, :due_date => nil)
1317 issue = Issue.new(:start_date => nil, :due_date => nil)
1318 issue.reschedule_on '2012-10-13'.to_date
1318 issue.reschedule_on '2012-10-13'.to_date
1319 assert_equal '2012-10-15'.to_date, issue.start_date
1319 assert_equal '2012-10-15'.to_date, issue.start_date
1320 assert_equal '2012-10-15'.to_date, issue.due_date
1320 assert_equal '2012-10-15'.to_date, issue.due_date
1321 end
1321 end
1322 end
1322 end
1323
1323
1324 def test_reschedule_an_issue_with_start_date
1324 def test_reschedule_an_issue_with_start_date
1325 with_settings :non_working_week_days => [] do
1325 with_settings :non_working_week_days => [] do
1326 issue = Issue.new(:start_date => '2012-10-09', :due_date => nil)
1326 issue = Issue.new(:start_date => '2012-10-09', :due_date => nil)
1327 issue.reschedule_on '2012-10-13'.to_date
1327 issue.reschedule_on '2012-10-13'.to_date
1328 assert_equal '2012-10-13'.to_date, issue.start_date
1328 assert_equal '2012-10-13'.to_date, issue.start_date
1329 assert_equal '2012-10-13'.to_date, issue.due_date
1329 assert_equal '2012-10-13'.to_date, issue.due_date
1330 end
1330 end
1331
1331
1332 with_settings :non_working_week_days => %w(6 7) do
1332 with_settings :non_working_week_days => %w(6 7) do
1333 issue = Issue.new(:start_date => '2012-10-09', :due_date => nil)
1333 issue = Issue.new(:start_date => '2012-10-09', :due_date => nil)
1334 issue.reschedule_on '2012-10-11'.to_date
1334 issue.reschedule_on '2012-10-11'.to_date
1335 assert_equal '2012-10-11'.to_date, issue.start_date
1335 assert_equal '2012-10-11'.to_date, issue.start_date
1336 assert_equal '2012-10-11'.to_date, issue.due_date
1336 assert_equal '2012-10-11'.to_date, issue.due_date
1337
1337
1338 issue = Issue.new(:start_date => '2012-10-09', :due_date => nil)
1338 issue = Issue.new(:start_date => '2012-10-09', :due_date => nil)
1339 issue.reschedule_on '2012-10-13'.to_date
1339 issue.reschedule_on '2012-10-13'.to_date
1340 assert_equal '2012-10-15'.to_date, issue.start_date
1340 assert_equal '2012-10-15'.to_date, issue.start_date
1341 assert_equal '2012-10-15'.to_date, issue.due_date
1341 assert_equal '2012-10-15'.to_date, issue.due_date
1342 end
1342 end
1343 end
1343 end
1344
1344
1345 def test_reschedule_an_issue_with_start_and_due_dates
1345 def test_reschedule_an_issue_with_start_and_due_dates
1346 with_settings :non_working_week_days => [] do
1346 with_settings :non_working_week_days => [] do
1347 issue = Issue.new(:start_date => '2012-10-09', :due_date => '2012-10-15')
1347 issue = Issue.new(:start_date => '2012-10-09', :due_date => '2012-10-15')
1348 issue.reschedule_on '2012-10-13'.to_date
1348 issue.reschedule_on '2012-10-13'.to_date
1349 assert_equal '2012-10-13'.to_date, issue.start_date
1349 assert_equal '2012-10-13'.to_date, issue.start_date
1350 assert_equal '2012-10-19'.to_date, issue.due_date
1350 assert_equal '2012-10-19'.to_date, issue.due_date
1351 end
1351 end
1352
1352
1353 with_settings :non_working_week_days => %w(6 7) do
1353 with_settings :non_working_week_days => %w(6 7) do
1354 issue = Issue.new(:start_date => '2012-10-09', :due_date => '2012-10-19') # 8 working days
1354 issue = Issue.new(:start_date => '2012-10-09', :due_date => '2012-10-19') # 8 working days
1355 issue.reschedule_on '2012-10-11'.to_date
1355 issue.reschedule_on '2012-10-11'.to_date
1356 assert_equal '2012-10-11'.to_date, issue.start_date
1356 assert_equal '2012-10-11'.to_date, issue.start_date
1357 assert_equal '2012-10-23'.to_date, issue.due_date
1357 assert_equal '2012-10-23'.to_date, issue.due_date
1358
1358
1359 issue = Issue.new(:start_date => '2012-10-09', :due_date => '2012-10-19')
1359 issue = Issue.new(:start_date => '2012-10-09', :due_date => '2012-10-19')
1360 issue.reschedule_on '2012-10-13'.to_date
1360 issue.reschedule_on '2012-10-13'.to_date
1361 assert_equal '2012-10-15'.to_date, issue.start_date
1361 assert_equal '2012-10-15'.to_date, issue.start_date
1362 assert_equal '2012-10-25'.to_date, issue.due_date
1362 assert_equal '2012-10-25'.to_date, issue.due_date
1363 end
1363 end
1364 end
1364 end
1365
1365
1366 def test_rescheduling_an_issue_should_reschedule_following_issue
1366 def test_rescheduling_an_issue_should_reschedule_following_issue
1367 issue1 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1367 issue1 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1368 issue2 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1368 issue2 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1369 IssueRelation.create!(:issue_from => issue1, :issue_to => issue2,
1369 IssueRelation.create!(:issue_from => issue1, :issue_to => issue2,
1370 :relation_type => IssueRelation::TYPE_PRECEDES)
1370 :relation_type => IssueRelation::TYPE_PRECEDES)
1371 assert_equal Date.parse('2012-10-18'), issue2.reload.start_date
1371 assert_equal Date.parse('2012-10-18'), issue2.reload.start_date
1372
1372
1373 issue1.due_date = '2012-10-23'
1373 issue1.due_date = '2012-10-23'
1374 issue1.save!
1374 issue1.save!
1375 issue2.reload
1375 issue2.reload
1376 assert_equal Date.parse('2012-10-24'), issue2.start_date
1376 assert_equal Date.parse('2012-10-24'), issue2.start_date
1377 assert_equal Date.parse('2012-10-26'), issue2.due_date
1377 assert_equal Date.parse('2012-10-26'), issue2.due_date
1378 end
1378 end
1379
1379
1380 def test_rescheduling_a_stale_issue_should_not_raise_an_error
1380 def test_rescheduling_a_stale_issue_should_not_raise_an_error
1381 with_settings :non_working_week_days => [] do
1381 with_settings :non_working_week_days => [] do
1382 stale = Issue.find(1)
1382 stale = Issue.find(1)
1383 issue = Issue.find(1)
1383 issue = Issue.find(1)
1384 issue.subject = "Updated"
1384 issue.subject = "Updated"
1385 issue.save!
1385 issue.save!
1386 date = 10.days.from_now.to_date
1386 date = 10.days.from_now.to_date
1387 assert_nothing_raised do
1387 assert_nothing_raised do
1388 stale.reschedule_on!(date)
1388 stale.reschedule_on!(date)
1389 end
1389 end
1390 assert_equal date, stale.reload.start_date
1390 assert_equal date, stale.reload.start_date
1391 end
1391 end
1392 end
1392 end
1393
1393
1394 def test_overdue
1394 def test_overdue
1395 assert Issue.new(:due_date => 1.day.ago.to_date).overdue?
1395 assert Issue.new(:due_date => 1.day.ago.to_date).overdue?
1396 assert !Issue.new(:due_date => Date.today).overdue?
1396 assert !Issue.new(:due_date => Date.today).overdue?
1397 assert !Issue.new(:due_date => 1.day.from_now.to_date).overdue?
1397 assert !Issue.new(:due_date => 1.day.from_now.to_date).overdue?
1398 assert !Issue.new(:due_date => nil).overdue?
1398 assert !Issue.new(:due_date => nil).overdue?
1399 assert !Issue.new(:due_date => 1.day.ago.to_date,
1399 assert !Issue.new(:due_date => 1.day.ago.to_date,
1400 :status => IssueStatus.find(:first,
1400 :status => IssueStatus.find(:first,
1401 :conditions => {:is_closed => true})
1401 :conditions => {:is_closed => true})
1402 ).overdue?
1402 ).overdue?
1403 end
1403 end
1404
1404
1405 context "#behind_schedule?" do
1405 context "#behind_schedule?" do
1406 should "be false if the issue has no start_date" do
1406 should "be false if the issue has no start_date" do
1407 assert !Issue.new(:start_date => nil,
1407 assert !Issue.new(:start_date => nil,
1408 :due_date => 1.day.from_now.to_date,
1408 :due_date => 1.day.from_now.to_date,
1409 :done_ratio => 0).behind_schedule?
1409 :done_ratio => 0).behind_schedule?
1410 end
1410 end
1411
1411
1412 should "be false if the issue has no end_date" do
1412 should "be false if the issue has no end_date" do
1413 assert !Issue.new(:start_date => 1.day.from_now.to_date,
1413 assert !Issue.new(:start_date => 1.day.from_now.to_date,
1414 :due_date => nil,
1414 :due_date => nil,
1415 :done_ratio => 0).behind_schedule?
1415 :done_ratio => 0).behind_schedule?
1416 end
1416 end
1417
1417
1418 should "be false if the issue has more done than it's calendar time" do
1418 should "be false if the issue has more done than it's calendar time" do
1419 assert !Issue.new(:start_date => 50.days.ago.to_date,
1419 assert !Issue.new(:start_date => 50.days.ago.to_date,
1420 :due_date => 50.days.from_now.to_date,
1420 :due_date => 50.days.from_now.to_date,
1421 :done_ratio => 90).behind_schedule?
1421 :done_ratio => 90).behind_schedule?
1422 end
1422 end
1423
1423
1424 should "be true if the issue hasn't been started at all" do
1424 should "be true if the issue hasn't been started at all" do
1425 assert Issue.new(:start_date => 1.day.ago.to_date,
1425 assert Issue.new(:start_date => 1.day.ago.to_date,
1426 :due_date => 1.day.from_now.to_date,
1426 :due_date => 1.day.from_now.to_date,
1427 :done_ratio => 0).behind_schedule?
1427 :done_ratio => 0).behind_schedule?
1428 end
1428 end
1429
1429
1430 should "be true if the issue has used more calendar time than it's done ratio" do
1430 should "be true if the issue has used more calendar time than it's done ratio" do
1431 assert Issue.new(:start_date => 100.days.ago.to_date,
1431 assert Issue.new(:start_date => 100.days.ago.to_date,
1432 :due_date => Date.today,
1432 :due_date => Date.today,
1433 :done_ratio => 90).behind_schedule?
1433 :done_ratio => 90).behind_schedule?
1434 end
1434 end
1435 end
1435 end
1436
1436
1437 context "#assignable_users" do
1437 context "#assignable_users" do
1438 should "be Users" do
1438 should "be Users" do
1439 assert_kind_of User, Issue.find(1).assignable_users.first
1439 assert_kind_of User, Issue.find(1).assignable_users.first
1440 end
1440 end
1441
1441
1442 should "include the issue author" do
1442 should "include the issue author" do
1443 non_project_member = User.generate!
1443 non_project_member = User.generate!
1444 issue = Issue.generate!(:author => non_project_member)
1444 issue = Issue.generate!(:author => non_project_member)
1445
1445
1446 assert issue.assignable_users.include?(non_project_member)
1446 assert issue.assignable_users.include?(non_project_member)
1447 end
1447 end
1448
1448
1449 should "include the current assignee" do
1449 should "include the current assignee" do
1450 user = User.generate!
1450 user = User.generate!
1451 issue = Issue.generate!(:assigned_to => user)
1451 issue = Issue.generate!(:assigned_to => user)
1452 user.lock!
1452 user.lock!
1453
1453
1454 assert Issue.find(issue.id).assignable_users.include?(user)
1454 assert Issue.find(issue.id).assignable_users.include?(user)
1455 end
1455 end
1456
1456
1457 should "not show the issue author twice" do
1457 should "not show the issue author twice" do
1458 assignable_user_ids = Issue.find(1).assignable_users.collect(&:id)
1458 assignable_user_ids = Issue.find(1).assignable_users.collect(&:id)
1459 assert_equal 2, assignable_user_ids.length
1459 assert_equal 2, assignable_user_ids.length
1460
1460
1461 assignable_user_ids.each do |user_id|
1461 assignable_user_ids.each do |user_id|
1462 assert_equal 1, assignable_user_ids.select {|i| i == user_id}.length,
1462 assert_equal 1, assignable_user_ids.select {|i| i == user_id}.length,
1463 "User #{user_id} appears more or less than once"
1463 "User #{user_id} appears more or less than once"
1464 end
1464 end
1465 end
1465 end
1466
1466
1467 context "with issue_group_assignment" do
1467 context "with issue_group_assignment" do
1468 should "include groups" do
1468 should "include groups" do
1469 issue = Issue.new(:project => Project.find(2))
1469 issue = Issue.new(:project => Project.find(2))
1470
1470
1471 with_settings :issue_group_assignment => '1' do
1471 with_settings :issue_group_assignment => '1' do
1472 assert_equal %w(Group User), issue.assignable_users.map {|a| a.class.name}.uniq.sort
1472 assert_equal %w(Group User), issue.assignable_users.map {|a| a.class.name}.uniq.sort
1473 assert issue.assignable_users.include?(Group.find(11))
1473 assert issue.assignable_users.include?(Group.find(11))
1474 end
1474 end
1475 end
1475 end
1476 end
1476 end
1477
1477
1478 context "without issue_group_assignment" do
1478 context "without issue_group_assignment" do
1479 should "not include groups" do
1479 should "not include groups" do
1480 issue = Issue.new(:project => Project.find(2))
1480 issue = Issue.new(:project => Project.find(2))
1481
1481
1482 with_settings :issue_group_assignment => '0' do
1482 with_settings :issue_group_assignment => '0' do
1483 assert_equal %w(User), issue.assignable_users.map {|a| a.class.name}.uniq.sort
1483 assert_equal %w(User), issue.assignable_users.map {|a| a.class.name}.uniq.sort
1484 assert !issue.assignable_users.include?(Group.find(11))
1484 assert !issue.assignable_users.include?(Group.find(11))
1485 end
1485 end
1486 end
1486 end
1487 end
1487 end
1488 end
1488 end
1489
1489
1490 def test_create_should_send_email_notification
1490 def test_create_should_send_email_notification
1491 ActionMailer::Base.deliveries.clear
1491 ActionMailer::Base.deliveries.clear
1492 issue = Issue.new(:project_id => 1, :tracker_id => 1,
1492 issue = Issue.new(:project_id => 1, :tracker_id => 1,
1493 :author_id => 3, :status_id => 1,
1493 :author_id => 3, :status_id => 1,
1494 :priority => IssuePriority.all.first,
1494 :priority => IssuePriority.all.first,
1495 :subject => 'test_create', :estimated_hours => '1:30')
1495 :subject => 'test_create', :estimated_hours => '1:30')
1496
1496
1497 assert issue.save
1497 assert issue.save
1498 assert_equal 1, ActionMailer::Base.deliveries.size
1498 assert_equal 1, ActionMailer::Base.deliveries.size
1499 end
1499 end
1500
1500
1501 def test_stale_issue_should_not_send_email_notification
1501 def test_stale_issue_should_not_send_email_notification
1502 ActionMailer::Base.deliveries.clear
1502 ActionMailer::Base.deliveries.clear
1503 issue = Issue.find(1)
1503 issue = Issue.find(1)
1504 stale = Issue.find(1)
1504 stale = Issue.find(1)
1505
1505
1506 issue.init_journal(User.find(1))
1506 issue.init_journal(User.find(1))
1507 issue.subject = 'Subjet update'
1507 issue.subject = 'Subjet update'
1508 assert issue.save
1508 assert issue.save
1509 assert_equal 1, ActionMailer::Base.deliveries.size
1509 assert_equal 1, ActionMailer::Base.deliveries.size
1510 ActionMailer::Base.deliveries.clear
1510 ActionMailer::Base.deliveries.clear
1511
1511
1512 stale.init_journal(User.find(1))
1512 stale.init_journal(User.find(1))
1513 stale.subject = 'Another subjet update'
1513 stale.subject = 'Another subjet update'
1514 assert_raise ActiveRecord::StaleObjectError do
1514 assert_raise ActiveRecord::StaleObjectError do
1515 stale.save
1515 stale.save
1516 end
1516 end
1517 assert ActionMailer::Base.deliveries.empty?
1517 assert ActionMailer::Base.deliveries.empty?
1518 end
1518 end
1519
1519
1520 def test_journalized_description
1520 def test_journalized_description
1521 IssueCustomField.delete_all
1521 IssueCustomField.delete_all
1522
1522
1523 i = Issue.first
1523 i = Issue.first
1524 old_description = i.description
1524 old_description = i.description
1525 new_description = "This is the new description"
1525 new_description = "This is the new description"
1526
1526
1527 i.init_journal(User.find(2))
1527 i.init_journal(User.find(2))
1528 i.description = new_description
1528 i.description = new_description
1529 assert_difference 'Journal.count', 1 do
1529 assert_difference 'Journal.count', 1 do
1530 assert_difference 'JournalDetail.count', 1 do
1530 assert_difference 'JournalDetail.count', 1 do
1531 i.save!
1531 i.save!
1532 end
1532 end
1533 end
1533 end
1534
1534
1535 detail = JournalDetail.first(:order => 'id DESC')
1535 detail = JournalDetail.first(:order => 'id DESC')
1536 assert_equal i, detail.journal.journalized
1536 assert_equal i, detail.journal.journalized
1537 assert_equal 'attr', detail.property
1537 assert_equal 'attr', detail.property
1538 assert_equal 'description', detail.prop_key
1538 assert_equal 'description', detail.prop_key
1539 assert_equal old_description, detail.old_value
1539 assert_equal old_description, detail.old_value
1540 assert_equal new_description, detail.value
1540 assert_equal new_description, detail.value
1541 end
1541 end
1542
1542
1543 def test_blank_descriptions_should_not_be_journalized
1543 def test_blank_descriptions_should_not_be_journalized
1544 IssueCustomField.delete_all
1544 IssueCustomField.delete_all
1545 Issue.update_all("description = NULL", "id=1")
1545 Issue.update_all("description = NULL", "id=1")
1546
1546
1547 i = Issue.find(1)
1547 i = Issue.find(1)
1548 i.init_journal(User.find(2))
1548 i.init_journal(User.find(2))
1549 i.subject = "blank description"
1549 i.subject = "blank description"
1550 i.description = "\r\n"
1550 i.description = "\r\n"
1551
1551
1552 assert_difference 'Journal.count', 1 do
1552 assert_difference 'Journal.count', 1 do
1553 assert_difference 'JournalDetail.count', 1 do
1553 assert_difference 'JournalDetail.count', 1 do
1554 i.save!
1554 i.save!
1555 end
1555 end
1556 end
1556 end
1557 end
1557 end
1558
1558
1559 def test_journalized_multi_custom_field
1559 def test_journalized_multi_custom_field
1560 field = IssueCustomField.create!(:name => 'filter', :field_format => 'list',
1560 field = IssueCustomField.create!(:name => 'filter', :field_format => 'list',
1561 :is_filter => true, :is_for_all => true,
1561 :is_filter => true, :is_for_all => true,
1562 :tracker_ids => [1],
1562 :tracker_ids => [1],
1563 :possible_values => ['value1', 'value2', 'value3'],
1563 :possible_values => ['value1', 'value2', 'value3'],
1564 :multiple => true)
1564 :multiple => true)
1565
1565
1566 issue = Issue.create!(:project_id => 1, :tracker_id => 1,
1566 issue = Issue.create!(:project_id => 1, :tracker_id => 1,
1567 :subject => 'Test', :author_id => 1)
1567 :subject => 'Test', :author_id => 1)
1568
1568
1569 assert_difference 'Journal.count' do
1569 assert_difference 'Journal.count' do
1570 assert_difference 'JournalDetail.count' do
1570 assert_difference 'JournalDetail.count' do
1571 issue.init_journal(User.first)
1571 issue.init_journal(User.first)
1572 issue.custom_field_values = {field.id => ['value1']}
1572 issue.custom_field_values = {field.id => ['value1']}
1573 issue.save!
1573 issue.save!
1574 end
1574 end
1575 assert_difference 'JournalDetail.count' do
1575 assert_difference 'JournalDetail.count' do
1576 issue.init_journal(User.first)
1576 issue.init_journal(User.first)
1577 issue.custom_field_values = {field.id => ['value1', 'value2']}
1577 issue.custom_field_values = {field.id => ['value1', 'value2']}
1578 issue.save!
1578 issue.save!
1579 end
1579 end
1580 assert_difference 'JournalDetail.count', 2 do
1580 assert_difference 'JournalDetail.count', 2 do
1581 issue.init_journal(User.first)
1581 issue.init_journal(User.first)
1582 issue.custom_field_values = {field.id => ['value3', 'value2']}
1582 issue.custom_field_values = {field.id => ['value3', 'value2']}
1583 issue.save!
1583 issue.save!
1584 end
1584 end
1585 assert_difference 'JournalDetail.count', 2 do
1585 assert_difference 'JournalDetail.count', 2 do
1586 issue.init_journal(User.first)
1586 issue.init_journal(User.first)
1587 issue.custom_field_values = {field.id => nil}
1587 issue.custom_field_values = {field.id => nil}
1588 issue.save!
1588 issue.save!
1589 end
1589 end
1590 end
1590 end
1591 end
1591 end
1592
1592
1593 def test_description_eol_should_be_normalized
1593 def test_description_eol_should_be_normalized
1594 i = Issue.new(:description => "CR \r LF \n CRLF \r\n")
1594 i = Issue.new(:description => "CR \r LF \n CRLF \r\n")
1595 assert_equal "CR \r\n LF \r\n CRLF \r\n", i.description
1595 assert_equal "CR \r\n LF \r\n CRLF \r\n", i.description
1596 end
1596 end
1597
1597
1598 def test_saving_twice_should_not_duplicate_journal_details
1598 def test_saving_twice_should_not_duplicate_journal_details
1599 i = Issue.find(:first)
1599 i = Issue.find(:first)
1600 i.init_journal(User.find(2), 'Some notes')
1600 i.init_journal(User.find(2), 'Some notes')
1601 # initial changes
1601 # initial changes
1602 i.subject = 'New subject'
1602 i.subject = 'New subject'
1603 i.done_ratio = i.done_ratio + 10
1603 i.done_ratio = i.done_ratio + 10
1604 assert_difference 'Journal.count' do
1604 assert_difference 'Journal.count' do
1605 assert i.save
1605 assert i.save
1606 end
1606 end
1607 # 1 more change
1607 # 1 more change
1608 i.priority = IssuePriority.find(:first, :conditions => ["id <> ?", i.priority_id])
1608 i.priority = IssuePriority.find(:first, :conditions => ["id <> ?", i.priority_id])
1609 assert_no_difference 'Journal.count' do
1609 assert_no_difference 'Journal.count' do
1610 assert_difference 'JournalDetail.count', 1 do
1610 assert_difference 'JournalDetail.count', 1 do
1611 i.save
1611 i.save
1612 end
1612 end
1613 end
1613 end
1614 # no more change
1614 # no more change
1615 assert_no_difference 'Journal.count' do
1615 assert_no_difference 'Journal.count' do
1616 assert_no_difference 'JournalDetail.count' do
1616 assert_no_difference 'JournalDetail.count' do
1617 i.save
1617 i.save
1618 end
1618 end
1619 end
1619 end
1620 end
1620 end
1621
1621
1622 def test_all_dependent_issues
1622 def test_all_dependent_issues
1623 IssueRelation.delete_all
1623 IssueRelation.delete_all
1624 assert IssueRelation.create!(:issue_from => Issue.find(1),
1624 assert IssueRelation.create!(:issue_from => Issue.find(1),
1625 :issue_to => Issue.find(2),
1625 :issue_to => Issue.find(2),
1626 :relation_type => IssueRelation::TYPE_PRECEDES)
1626 :relation_type => IssueRelation::TYPE_PRECEDES)
1627 assert IssueRelation.create!(:issue_from => Issue.find(2),
1627 assert IssueRelation.create!(:issue_from => Issue.find(2),
1628 :issue_to => Issue.find(3),
1628 :issue_to => Issue.find(3),
1629 :relation_type => IssueRelation::TYPE_PRECEDES)
1629 :relation_type => IssueRelation::TYPE_PRECEDES)
1630 assert IssueRelation.create!(:issue_from => Issue.find(3),
1630 assert IssueRelation.create!(:issue_from => Issue.find(3),
1631 :issue_to => Issue.find(8),
1631 :issue_to => Issue.find(8),
1632 :relation_type => IssueRelation::TYPE_PRECEDES)
1632 :relation_type => IssueRelation::TYPE_PRECEDES)
1633
1633
1634 assert_equal [2, 3, 8], Issue.find(1).all_dependent_issues.collect(&:id).sort
1634 assert_equal [2, 3, 8], Issue.find(1).all_dependent_issues.collect(&:id).sort
1635 end
1635 end
1636
1636
1637 def test_all_dependent_issues_with_persistent_circular_dependency
1637 def test_all_dependent_issues_with_persistent_circular_dependency
1638 IssueRelation.delete_all
1638 IssueRelation.delete_all
1639 assert IssueRelation.create!(:issue_from => Issue.find(1),
1639 assert IssueRelation.create!(:issue_from => Issue.find(1),
1640 :issue_to => Issue.find(2),
1640 :issue_to => Issue.find(2),
1641 :relation_type => IssueRelation::TYPE_PRECEDES)
1641 :relation_type => IssueRelation::TYPE_PRECEDES)
1642 assert IssueRelation.create!(:issue_from => Issue.find(2),
1642 assert IssueRelation.create!(:issue_from => Issue.find(2),
1643 :issue_to => Issue.find(3),
1643 :issue_to => Issue.find(3),
1644 :relation_type => IssueRelation::TYPE_PRECEDES)
1644 :relation_type => IssueRelation::TYPE_PRECEDES)
1645
1645
1646 r = IssueRelation.create!(:issue_from => Issue.find(3),
1646 r = IssueRelation.create!(:issue_from => Issue.find(3),
1647 :issue_to => Issue.find(7),
1647 :issue_to => Issue.find(7),
1648 :relation_type => IssueRelation::TYPE_PRECEDES)
1648 :relation_type => IssueRelation::TYPE_PRECEDES)
1649 IssueRelation.update_all("issue_to_id = 1", ["id = ?", r.id])
1649 IssueRelation.update_all("issue_to_id = 1", ["id = ?", r.id])
1650
1650
1651 assert_equal [2, 3], Issue.find(1).all_dependent_issues.collect(&:id).sort
1651 assert_equal [2, 3], Issue.find(1).all_dependent_issues.collect(&:id).sort
1652 end
1652 end
1653
1653
1654 def test_all_dependent_issues_with_persistent_multiple_circular_dependencies
1654 def test_all_dependent_issues_with_persistent_multiple_circular_dependencies
1655 IssueRelation.delete_all
1655 IssueRelation.delete_all
1656 assert IssueRelation.create!(:issue_from => Issue.find(1),
1656 assert IssueRelation.create!(:issue_from => Issue.find(1),
1657 :issue_to => Issue.find(2),
1657 :issue_to => Issue.find(2),
1658 :relation_type => IssueRelation::TYPE_RELATES)
1658 :relation_type => IssueRelation::TYPE_RELATES)
1659 assert IssueRelation.create!(:issue_from => Issue.find(2),
1659 assert IssueRelation.create!(:issue_from => Issue.find(2),
1660 :issue_to => Issue.find(3),
1660 :issue_to => Issue.find(3),
1661 :relation_type => IssueRelation::TYPE_RELATES)
1661 :relation_type => IssueRelation::TYPE_RELATES)
1662 assert IssueRelation.create!(:issue_from => Issue.find(3),
1662 assert IssueRelation.create!(:issue_from => Issue.find(3),
1663 :issue_to => Issue.find(8),
1663 :issue_to => Issue.find(8),
1664 :relation_type => IssueRelation::TYPE_RELATES)
1664 :relation_type => IssueRelation::TYPE_RELATES)
1665
1665
1666 r = IssueRelation.create!(:issue_from => Issue.find(8),
1666 r = IssueRelation.create!(:issue_from => Issue.find(8),
1667 :issue_to => Issue.find(7),
1667 :issue_to => Issue.find(7),
1668 :relation_type => IssueRelation::TYPE_RELATES)
1668 :relation_type => IssueRelation::TYPE_RELATES)
1669 IssueRelation.update_all("issue_to_id = 2", ["id = ?", r.id])
1669 IssueRelation.update_all("issue_to_id = 2", ["id = ?", r.id])
1670
1670
1671 r = IssueRelation.create!(:issue_from => Issue.find(3),
1671 r = IssueRelation.create!(:issue_from => Issue.find(3),
1672 :issue_to => Issue.find(7),
1672 :issue_to => Issue.find(7),
1673 :relation_type => IssueRelation::TYPE_RELATES)
1673 :relation_type => IssueRelation::TYPE_RELATES)
1674 IssueRelation.update_all("issue_to_id = 1", ["id = ?", r.id])
1674 IssueRelation.update_all("issue_to_id = 1", ["id = ?", r.id])
1675
1675
1676 assert_equal [2, 3, 8], Issue.find(1).all_dependent_issues.collect(&:id).sort
1676 assert_equal [2, 3, 8], Issue.find(1).all_dependent_issues.collect(&:id).sort
1677 end
1677 end
1678
1678
1679 context "#done_ratio" do
1679 context "#done_ratio" do
1680 setup do
1680 setup do
1681 @issue = Issue.find(1)
1681 @issue = Issue.find(1)
1682 @issue_status = IssueStatus.find(1)
1682 @issue_status = IssueStatus.find(1)
1683 @issue_status.update_attribute(:default_done_ratio, 50)
1683 @issue_status.update_attribute(:default_done_ratio, 50)
1684 @issue2 = Issue.find(2)
1684 @issue2 = Issue.find(2)
1685 @issue_status2 = IssueStatus.find(2)
1685 @issue_status2 = IssueStatus.find(2)
1686 @issue_status2.update_attribute(:default_done_ratio, 0)
1686 @issue_status2.update_attribute(:default_done_ratio, 0)
1687 end
1687 end
1688
1688
1689 teardown do
1689 teardown do
1690 Setting.issue_done_ratio = 'issue_field'
1690 Setting.issue_done_ratio = 'issue_field'
1691 end
1691 end
1692
1692
1693 context "with Setting.issue_done_ratio using the issue_field" do
1693 context "with Setting.issue_done_ratio using the issue_field" do
1694 setup do
1694 setup do
1695 Setting.issue_done_ratio = 'issue_field'
1695 Setting.issue_done_ratio = 'issue_field'
1696 end
1696 end
1697
1697
1698 should "read the issue's field" do
1698 should "read the issue's field" do
1699 assert_equal 0, @issue.done_ratio
1699 assert_equal 0, @issue.done_ratio
1700 assert_equal 30, @issue2.done_ratio
1700 assert_equal 30, @issue2.done_ratio
1701 end
1701 end
1702 end
1702 end
1703
1703
1704 context "with Setting.issue_done_ratio using the issue_status" do
1704 context "with Setting.issue_done_ratio using the issue_status" do
1705 setup do
1705 setup do
1706 Setting.issue_done_ratio = 'issue_status'
1706 Setting.issue_done_ratio = 'issue_status'
1707 end
1707 end
1708
1708
1709 should "read the Issue Status's default done ratio" do
1709 should "read the Issue Status's default done ratio" do
1710 assert_equal 50, @issue.done_ratio
1710 assert_equal 50, @issue.done_ratio
1711 assert_equal 0, @issue2.done_ratio
1711 assert_equal 0, @issue2.done_ratio
1712 end
1712 end
1713 end
1713 end
1714 end
1714 end
1715
1715
1716 context "#update_done_ratio_from_issue_status" do
1716 context "#update_done_ratio_from_issue_status" do
1717 setup do
1717 setup do
1718 @issue = Issue.find(1)
1718 @issue = Issue.find(1)
1719 @issue_status = IssueStatus.find(1)
1719 @issue_status = IssueStatus.find(1)
1720 @issue_status.update_attribute(:default_done_ratio, 50)
1720 @issue_status.update_attribute(:default_done_ratio, 50)
1721 @issue2 = Issue.find(2)
1721 @issue2 = Issue.find(2)
1722 @issue_status2 = IssueStatus.find(2)
1722 @issue_status2 = IssueStatus.find(2)
1723 @issue_status2.update_attribute(:default_done_ratio, 0)
1723 @issue_status2.update_attribute(:default_done_ratio, 0)
1724 end
1724 end
1725
1725
1726 context "with Setting.issue_done_ratio using the issue_field" do
1726 context "with Setting.issue_done_ratio using the issue_field" do
1727 setup do
1727 setup do
1728 Setting.issue_done_ratio = 'issue_field'
1728 Setting.issue_done_ratio = 'issue_field'
1729 end
1729 end
1730
1730
1731 should "not change the issue" do
1731 should "not change the issue" do
1732 @issue.update_done_ratio_from_issue_status
1732 @issue.update_done_ratio_from_issue_status
1733 @issue2.update_done_ratio_from_issue_status
1733 @issue2.update_done_ratio_from_issue_status
1734
1734
1735 assert_equal 0, @issue.read_attribute(:done_ratio)
1735 assert_equal 0, @issue.read_attribute(:done_ratio)
1736 assert_equal 30, @issue2.read_attribute(:done_ratio)
1736 assert_equal 30, @issue2.read_attribute(:done_ratio)
1737 end
1737 end
1738 end
1738 end
1739
1739
1740 context "with Setting.issue_done_ratio using the issue_status" do
1740 context "with Setting.issue_done_ratio using the issue_status" do
1741 setup do
1741 setup do
1742 Setting.issue_done_ratio = 'issue_status'
1742 Setting.issue_done_ratio = 'issue_status'
1743 end
1743 end
1744
1744
1745 should "change the issue's done ratio" do
1745 should "change the issue's done ratio" do
1746 @issue.update_done_ratio_from_issue_status
1746 @issue.update_done_ratio_from_issue_status
1747 @issue2.update_done_ratio_from_issue_status
1747 @issue2.update_done_ratio_from_issue_status
1748
1748
1749 assert_equal 50, @issue.read_attribute(:done_ratio)
1749 assert_equal 50, @issue.read_attribute(:done_ratio)
1750 assert_equal 0, @issue2.read_attribute(:done_ratio)
1750 assert_equal 0, @issue2.read_attribute(:done_ratio)
1751 end
1751 end
1752 end
1752 end
1753 end
1753 end
1754
1754
1755 test "#by_tracker" do
1755 test "#by_tracker" do
1756 User.current = User.anonymous
1756 User.current = User.anonymous
1757 groups = Issue.by_tracker(Project.find(1))
1757 groups = Issue.by_tracker(Project.find(1))
1758 assert_equal 3, groups.size
1758 assert_equal 3, groups.size
1759 assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i}
1759 assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i}
1760 end
1760 end
1761
1761
1762 test "#by_version" do
1762 test "#by_version" do
1763 User.current = User.anonymous
1763 User.current = User.anonymous
1764 groups = Issue.by_version(Project.find(1))
1764 groups = Issue.by_version(Project.find(1))
1765 assert_equal 3, groups.size
1765 assert_equal 3, groups.size
1766 assert_equal 3, groups.inject(0) {|sum, group| sum + group['total'].to_i}
1766 assert_equal 3, groups.inject(0) {|sum, group| sum + group['total'].to_i}
1767 end
1767 end
1768
1768
1769 test "#by_priority" do
1769 test "#by_priority" do
1770 User.current = User.anonymous
1770 User.current = User.anonymous
1771 groups = Issue.by_priority(Project.find(1))
1771 groups = Issue.by_priority(Project.find(1))
1772 assert_equal 4, groups.size
1772 assert_equal 4, groups.size
1773 assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i}
1773 assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i}
1774 end
1774 end
1775
1775
1776 test "#by_category" do
1776 test "#by_category" do
1777 User.current = User.anonymous
1777 User.current = User.anonymous
1778 groups = Issue.by_category(Project.find(1))
1778 groups = Issue.by_category(Project.find(1))
1779 assert_equal 2, groups.size
1779 assert_equal 2, groups.size
1780 assert_equal 3, groups.inject(0) {|sum, group| sum + group['total'].to_i}
1780 assert_equal 3, groups.inject(0) {|sum, group| sum + group['total'].to_i}
1781 end
1781 end
1782
1782
1783 test "#by_assigned_to" do
1783 test "#by_assigned_to" do
1784 User.current = User.anonymous
1784 User.current = User.anonymous
1785 groups = Issue.by_assigned_to(Project.find(1))
1785 groups = Issue.by_assigned_to(Project.find(1))
1786 assert_equal 2, groups.size
1786 assert_equal 2, groups.size
1787 assert_equal 2, groups.inject(0) {|sum, group| sum + group['total'].to_i}
1787 assert_equal 2, groups.inject(0) {|sum, group| sum + group['total'].to_i}
1788 end
1788 end
1789
1789
1790 test "#by_author" do
1790 test "#by_author" do
1791 User.current = User.anonymous
1791 User.current = User.anonymous
1792 groups = Issue.by_author(Project.find(1))
1792 groups = Issue.by_author(Project.find(1))
1793 assert_equal 4, groups.size
1793 assert_equal 4, groups.size
1794 assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i}
1794 assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i}
1795 end
1795 end
1796
1796
1797 test "#by_subproject" do
1797 test "#by_subproject" do
1798 User.current = User.anonymous
1798 User.current = User.anonymous
1799 groups = Issue.by_subproject(Project.find(1))
1799 groups = Issue.by_subproject(Project.find(1))
1800 # Private descendant not visible
1800 # Private descendant not visible
1801 assert_equal 1, groups.size
1801 assert_equal 1, groups.size
1802 assert_equal 2, groups.inject(0) {|sum, group| sum + group['total'].to_i}
1802 assert_equal 2, groups.inject(0) {|sum, group| sum + group['total'].to_i}
1803 end
1803 end
1804
1804
1805 def test_recently_updated_scope
1805 def test_recently_updated_scope
1806 #should return the last updated issue
1806 #should return the last updated issue
1807 assert_equal Issue.reorder("updated_on DESC").first, Issue.recently_updated.limit(1).first
1807 assert_equal Issue.reorder("updated_on DESC").first, Issue.recently_updated.limit(1).first
1808 end
1808 end
1809
1809
1810 def test_on_active_projects_scope
1810 def test_on_active_projects_scope
1811 assert Project.find(2).archive
1811 assert Project.find(2).archive
1812
1812
1813 before = Issue.on_active_project.length
1813 before = Issue.on_active_project.length
1814 # test inclusion to results
1814 # test inclusion to results
1815 issue = Issue.generate!(:tracker => Project.find(2).trackers.first)
1815 issue = Issue.generate!(:tracker => Project.find(2).trackers.first)
1816 assert_equal before + 1, Issue.on_active_project.length
1816 assert_equal before + 1, Issue.on_active_project.length
1817
1817
1818 # Move to an archived project
1818 # Move to an archived project
1819 issue.project = Project.find(2)
1819 issue.project = Project.find(2)
1820 assert issue.save
1820 assert issue.save
1821 assert_equal before, Issue.on_active_project.length
1821 assert_equal before, Issue.on_active_project.length
1822 end
1822 end
1823
1823
1824 context "Issue#recipients" do
1824 context "Issue#recipients" do
1825 setup do
1825 setup do
1826 @project = Project.find(1)
1826 @project = Project.find(1)
1827 @author = User.generate!
1827 @author = User.generate!
1828 @assignee = User.generate!
1828 @assignee = User.generate!
1829 @issue = Issue.generate!(:project => @project, :assigned_to => @assignee, :author => @author)
1829 @issue = Issue.generate!(:project => @project, :assigned_to => @assignee, :author => @author)
1830 end
1830 end
1831
1831
1832 should "include project recipients" do
1832 should "include project recipients" do
1833 assert @project.recipients.present?
1833 assert @project.recipients.present?
1834 @project.recipients.each do |project_recipient|
1834 @project.recipients.each do |project_recipient|
1835 assert @issue.recipients.include?(project_recipient)
1835 assert @issue.recipients.include?(project_recipient)
1836 end
1836 end
1837 end
1837 end
1838
1838
1839 should "include the author if the author is active" do
1839 should "include the author if the author is active" do
1840 assert @issue.author, "No author set for Issue"
1840 assert @issue.author, "No author set for Issue"
1841 assert @issue.recipients.include?(@issue.author.mail)
1841 assert @issue.recipients.include?(@issue.author.mail)
1842 end
1842 end
1843
1843
1844 should "include the assigned to user if the assigned to user is active" do
1844 should "include the assigned to user if the assigned to user is active" do
1845 assert @issue.assigned_to, "No assigned_to set for Issue"
1845 assert @issue.assigned_to, "No assigned_to set for Issue"
1846 assert @issue.recipients.include?(@issue.assigned_to.mail)
1846 assert @issue.recipients.include?(@issue.assigned_to.mail)
1847 end
1847 end
1848
1848
1849 should "not include users who opt out of all email" do
1849 should "not include users who opt out of all email" do
1850 @author.update_attribute(:mail_notification, :none)
1850 @author.update_attribute(:mail_notification, :none)
1851
1851
1852 assert !@issue.recipients.include?(@issue.author.mail)
1852 assert !@issue.recipients.include?(@issue.author.mail)
1853 end
1853 end
1854
1854
1855 should "not include the issue author if they are only notified of assigned issues" do
1855 should "not include the issue author if they are only notified of assigned issues" do
1856 @author.update_attribute(:mail_notification, :only_assigned)
1856 @author.update_attribute(:mail_notification, :only_assigned)
1857
1857
1858 assert !@issue.recipients.include?(@issue.author.mail)
1858 assert !@issue.recipients.include?(@issue.author.mail)
1859 end
1859 end
1860
1860
1861 should "not include the assigned user if they are only notified of owned issues" do
1861 should "not include the assigned user if they are only notified of owned issues" do
1862 @assignee.update_attribute(:mail_notification, :only_owner)
1862 @assignee.update_attribute(:mail_notification, :only_owner)
1863
1863
1864 assert !@issue.recipients.include?(@issue.assigned_to.mail)
1864 assert !@issue.recipients.include?(@issue.assigned_to.mail)
1865 end
1865 end
1866 end
1866 end
1867
1867
1868 def test_last_journal_id_with_journals_should_return_the_journal_id
1868 def test_last_journal_id_with_journals_should_return_the_journal_id
1869 assert_equal 2, Issue.find(1).last_journal_id
1869 assert_equal 2, Issue.find(1).last_journal_id
1870 end
1870 end
1871
1871
1872 def test_last_journal_id_without_journals_should_return_nil
1872 def test_last_journal_id_without_journals_should_return_nil
1873 assert_nil Issue.find(3).last_journal_id
1873 assert_nil Issue.find(3).last_journal_id
1874 end
1874 end
1875
1875
1876 def test_journals_after_should_return_journals_with_greater_id
1876 def test_journals_after_should_return_journals_with_greater_id
1877 assert_equal [Journal.find(2)], Issue.find(1).journals_after('1')
1877 assert_equal [Journal.find(2)], Issue.find(1).journals_after('1')
1878 assert_equal [], Issue.find(1).journals_after('2')
1878 assert_equal [], Issue.find(1).journals_after('2')
1879 end
1879 end
1880
1880
1881 def test_journals_after_with_blank_arg_should_return_all_journals
1881 def test_journals_after_with_blank_arg_should_return_all_journals
1882 assert_equal [Journal.find(1), Journal.find(2)], Issue.find(1).journals_after('')
1882 assert_equal [Journal.find(1), Journal.find(2)], Issue.find(1).journals_after('')
1883 end
1883 end
1884
1884
1885 def test_css_classes_should_include_priority
1885 def test_css_classes_should_include_priority
1886 issue = Issue.new(:priority => IssuePriority.find(8))
1886 issue = Issue.new(:priority => IssuePriority.find(8))
1887 classes = issue.css_classes.split(' ')
1887 classes = issue.css_classes.split(' ')
1888 assert_include 'priority-8', classes
1888 assert_include 'priority-8', classes
1889 assert_include 'priority-highest', classes
1889 assert_include 'priority-highest', classes
1890 end
1890 end
1891
1892 def test_save_attachments_with_hash_should_save_attachments_in_keys_order
1893 set_tmp_attachments_directory
1894 issue = Issue.generate!
1895 issue.save_attachments({
1896 'p0' => {'file' => mock_file_with_options(:original_filename => 'upload')},
1897 '3' => {'file' => mock_file_with_options(:original_filename => 'bar')},
1898 '1' => {'file' => mock_file_with_options(:original_filename => 'foo')}
1899 })
1900 issue.attach_saved_attachments
1901
1902 assert_equal 3, issue.reload.attachments.count
1903 assert_equal %w(upload foo bar), issue.attachments.map(&:filename)
1904 end
1891 end
1905 end
General Comments 0
You need to be logged in to leave comments. Login now