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