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