##// END OF EJS Templates
Fixes a failing test....
Jean-Philippe Lang -
r4838:c781cbb2f728
parent child
Show More
@@ -1,883 +1,885
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 :trackers, :projects_trackers,
22 :trackers, :projects_trackers,
23 :enabled_modules,
23 :enabled_modules,
24 :versions,
24 :versions,
25 :issue_statuses, :issue_categories, :issue_relations, :workflows,
25 :issue_statuses, :issue_categories, :issue_relations, :workflows,
26 :enumerations,
26 :enumerations,
27 :issues,
27 :issues,
28 :custom_fields, :custom_fields_projects, :custom_fields_trackers, :custom_values,
28 :custom_fields, :custom_fields_projects, :custom_fields_trackers, :custom_values,
29 :time_entries
29 :time_entries
30
30
31 def test_create
31 def test_create
32 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3, :status_id => 1, :priority => IssuePriority.all.first, :subject => 'test_create', :description => 'IssueTest#test_create', :estimated_hours => '1:30')
32 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3, :status_id => 1, :priority => IssuePriority.all.first, :subject => 'test_create', :description => 'IssueTest#test_create', :estimated_hours => '1:30')
33 assert issue.save
33 assert issue.save
34 issue.reload
34 issue.reload
35 assert_equal 1.5, issue.estimated_hours
35 assert_equal 1.5, issue.estimated_hours
36 end
36 end
37
37
38 def test_create_minimal
38 def test_create_minimal
39 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3, :status_id => 1, :priority => IssuePriority.all.first, :subject => 'test_create')
39 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3, :status_id => 1, :priority => IssuePriority.all.first, :subject => 'test_create')
40 assert issue.save
40 assert issue.save
41 assert issue.description.nil?
41 assert issue.description.nil?
42 end
42 end
43
43
44 def test_create_with_required_custom_field
44 def test_create_with_required_custom_field
45 field = IssueCustomField.find_by_name('Database')
45 field = IssueCustomField.find_by_name('Database')
46 field.update_attribute(:is_required, true)
46 field.update_attribute(:is_required, true)
47
47
48 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :subject => 'test_create', :description => 'IssueTest#test_create_with_required_custom_field')
48 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :subject => 'test_create', :description => 'IssueTest#test_create_with_required_custom_field')
49 assert issue.available_custom_fields.include?(field)
49 assert issue.available_custom_fields.include?(field)
50 # No value for the custom field
50 # No value for the custom field
51 assert !issue.save
51 assert !issue.save
52 assert_equal I18n.translate('activerecord.errors.messages.invalid'), issue.errors.on(:custom_values)
52 assert_equal I18n.translate('activerecord.errors.messages.invalid'), issue.errors.on(:custom_values)
53 # Blank value
53 # Blank value
54 issue.custom_field_values = { field.id => '' }
54 issue.custom_field_values = { field.id => '' }
55 assert !issue.save
55 assert !issue.save
56 assert_equal I18n.translate('activerecord.errors.messages.invalid'), issue.errors.on(:custom_values)
56 assert_equal I18n.translate('activerecord.errors.messages.invalid'), issue.errors.on(:custom_values)
57 # Invalid value
57 # Invalid value
58 issue.custom_field_values = { field.id => 'SQLServer' }
58 issue.custom_field_values = { field.id => 'SQLServer' }
59 assert !issue.save
59 assert !issue.save
60 assert_equal I18n.translate('activerecord.errors.messages.invalid'), issue.errors.on(:custom_values)
60 assert_equal I18n.translate('activerecord.errors.messages.invalid'), issue.errors.on(:custom_values)
61 # Valid value
61 # Valid value
62 issue.custom_field_values = { field.id => 'PostgreSQL' }
62 issue.custom_field_values = { field.id => 'PostgreSQL' }
63 assert issue.save
63 assert issue.save
64 issue.reload
64 issue.reload
65 assert_equal 'PostgreSQL', issue.custom_value_for(field).value
65 assert_equal 'PostgreSQL', issue.custom_value_for(field).value
66 end
66 end
67
67
68 def test_visible_scope_for_anonymous
68 def test_visible_scope_for_anonymous
69 # Anonymous user should see issues of public projects only
69 # Anonymous user should see issues of public projects only
70 issues = Issue.visible(User.anonymous).all
70 issues = Issue.visible(User.anonymous).all
71 assert issues.any?
71 assert issues.any?
72 assert_nil issues.detect {|issue| !issue.project.is_public?}
72 assert_nil issues.detect {|issue| !issue.project.is_public?}
73 # Anonymous user should not see issues without permission
73 # Anonymous user should not see issues without permission
74 Role.anonymous.remove_permission!(:view_issues)
74 Role.anonymous.remove_permission!(:view_issues)
75 issues = Issue.visible(User.anonymous).all
75 issues = Issue.visible(User.anonymous).all
76 assert issues.empty?
76 assert issues.empty?
77 end
77 end
78
78
79 def test_visible_scope_for_user
79 def test_visible_scope_for_user
80 user = User.find(9)
80 user = User.find(9)
81 assert user.projects.empty?
81 assert user.projects.empty?
82 # Non member user should see issues of public projects only
82 # Non member user should see issues of public projects only
83 issues = Issue.visible(user).all
83 issues = Issue.visible(user).all
84 assert issues.any?
84 assert issues.any?
85 assert_nil issues.detect {|issue| !issue.project.is_public?}
85 assert_nil issues.detect {|issue| !issue.project.is_public?}
86 # Non member user should not see issues without permission
86 # Non member user should not see issues without permission
87 Role.non_member.remove_permission!(:view_issues)
87 Role.non_member.remove_permission!(:view_issues)
88 user.reload
88 user.reload
89 issues = Issue.visible(user).all
89 issues = Issue.visible(user).all
90 assert issues.empty?
90 assert issues.empty?
91 # User should see issues of projects for which he has view_issues permissions only
91 # User should see issues of projects for which he has view_issues permissions only
92 Member.create!(:principal => user, :project_id => 2, :role_ids => [1])
92 Member.create!(:principal => user, :project_id => 2, :role_ids => [1])
93 user.reload
93 user.reload
94 issues = Issue.visible(user).all
94 issues = Issue.visible(user).all
95 assert issues.any?
95 assert issues.any?
96 assert_nil issues.detect {|issue| issue.project_id != 2}
96 assert_nil issues.detect {|issue| issue.project_id != 2}
97 end
97 end
98
98
99 def test_visible_scope_for_admin
99 def test_visible_scope_for_admin
100 user = User.find(1)
100 user = User.find(1)
101 user.members.each(&:destroy)
101 user.members.each(&:destroy)
102 assert user.projects.empty?
102 assert user.projects.empty?
103 issues = Issue.visible(user).all
103 issues = Issue.visible(user).all
104 assert issues.any?
104 assert issues.any?
105 # Admin should see issues on private projects that he does not belong to
105 # Admin should see issues on private projects that he does not belong to
106 assert issues.detect {|issue| !issue.project.is_public?}
106 assert issues.detect {|issue| !issue.project.is_public?}
107 end
107 end
108
108
109 def test_errors_full_messages_should_include_custom_fields_errors
109 def test_errors_full_messages_should_include_custom_fields_errors
110 field = IssueCustomField.find_by_name('Database')
110 field = IssueCustomField.find_by_name('Database')
111
111
112 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :subject => 'test_create', :description => 'IssueTest#test_create_with_required_custom_field')
112 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :subject => 'test_create', :description => 'IssueTest#test_create_with_required_custom_field')
113 assert issue.available_custom_fields.include?(field)
113 assert issue.available_custom_fields.include?(field)
114 # Invalid value
114 # Invalid value
115 issue.custom_field_values = { field.id => 'SQLServer' }
115 issue.custom_field_values = { field.id => 'SQLServer' }
116
116
117 assert !issue.valid?
117 assert !issue.valid?
118 assert_equal 1, issue.errors.full_messages.size
118 assert_equal 1, issue.errors.full_messages.size
119 assert_equal "Database #{I18n.translate('activerecord.errors.messages.inclusion')}", issue.errors.full_messages.first
119 assert_equal "Database #{I18n.translate('activerecord.errors.messages.inclusion')}", issue.errors.full_messages.first
120 end
120 end
121
121
122 def test_update_issue_with_required_custom_field
122 def test_update_issue_with_required_custom_field
123 field = IssueCustomField.find_by_name('Database')
123 field = IssueCustomField.find_by_name('Database')
124 field.update_attribute(:is_required, true)
124 field.update_attribute(:is_required, true)
125
125
126 issue = Issue.find(1)
126 issue = Issue.find(1)
127 assert_nil issue.custom_value_for(field)
127 assert_nil issue.custom_value_for(field)
128 assert issue.available_custom_fields.include?(field)
128 assert issue.available_custom_fields.include?(field)
129 # No change to custom values, issue can be saved
129 # No change to custom values, issue can be saved
130 assert issue.save
130 assert issue.save
131 # Blank value
131 # Blank value
132 issue.custom_field_values = { field.id => '' }
132 issue.custom_field_values = { field.id => '' }
133 assert !issue.save
133 assert !issue.save
134 # Valid value
134 # Valid value
135 issue.custom_field_values = { field.id => 'PostgreSQL' }
135 issue.custom_field_values = { field.id => 'PostgreSQL' }
136 assert issue.save
136 assert issue.save
137 issue.reload
137 issue.reload
138 assert_equal 'PostgreSQL', issue.custom_value_for(field).value
138 assert_equal 'PostgreSQL', issue.custom_value_for(field).value
139 end
139 end
140
140
141 def test_should_not_update_attributes_if_custom_fields_validation_fails
141 def test_should_not_update_attributes_if_custom_fields_validation_fails
142 issue = Issue.find(1)
142 issue = Issue.find(1)
143 field = IssueCustomField.find_by_name('Database')
143 field = IssueCustomField.find_by_name('Database')
144 assert issue.available_custom_fields.include?(field)
144 assert issue.available_custom_fields.include?(field)
145
145
146 issue.custom_field_values = { field.id => 'Invalid' }
146 issue.custom_field_values = { field.id => 'Invalid' }
147 issue.subject = 'Should be not be saved'
147 issue.subject = 'Should be not be saved'
148 assert !issue.save
148 assert !issue.save
149
149
150 issue.reload
150 issue.reload
151 assert_equal "Can't print recipes", issue.subject
151 assert_equal "Can't print recipes", issue.subject
152 end
152 end
153
153
154 def test_should_not_recreate_custom_values_objects_on_update
154 def test_should_not_recreate_custom_values_objects_on_update
155 field = IssueCustomField.find_by_name('Database')
155 field = IssueCustomField.find_by_name('Database')
156
156
157 issue = Issue.find(1)
157 issue = Issue.find(1)
158 issue.custom_field_values = { field.id => 'PostgreSQL' }
158 issue.custom_field_values = { field.id => 'PostgreSQL' }
159 assert issue.save
159 assert issue.save
160 custom_value = issue.custom_value_for(field)
160 custom_value = issue.custom_value_for(field)
161 issue.reload
161 issue.reload
162 issue.custom_field_values = { field.id => 'MySQL' }
162 issue.custom_field_values = { field.id => 'MySQL' }
163 assert issue.save
163 assert issue.save
164 issue.reload
164 issue.reload
165 assert_equal custom_value.id, issue.custom_value_for(field).id
165 assert_equal custom_value.id, issue.custom_value_for(field).id
166 end
166 end
167
167
168 def test_assigning_tracker_id_should_reload_custom_fields_values
168 def test_assigning_tracker_id_should_reload_custom_fields_values
169 issue = Issue.new(:project => Project.find(1))
169 issue = Issue.new(:project => Project.find(1))
170 assert issue.custom_field_values.empty?
170 assert issue.custom_field_values.empty?
171 issue.tracker_id = 1
171 issue.tracker_id = 1
172 assert issue.custom_field_values.any?
172 assert issue.custom_field_values.any?
173 end
173 end
174
174
175 def test_assigning_attributes_should_assign_tracker_id_first
175 def test_assigning_attributes_should_assign_tracker_id_first
176 attributes = ActiveSupport::OrderedHash.new
176 attributes = ActiveSupport::OrderedHash.new
177 attributes['custom_field_values'] = { '1' => 'MySQL' }
177 attributes['custom_field_values'] = { '1' => 'MySQL' }
178 attributes['tracker_id'] = '1'
178 attributes['tracker_id'] = '1'
179 issue = Issue.new(:project => Project.find(1))
179 issue = Issue.new(:project => Project.find(1))
180 issue.attributes = attributes
180 issue.attributes = attributes
181 assert_not_nil issue.custom_value_for(1)
181 assert_not_nil issue.custom_value_for(1)
182 assert_equal 'MySQL', issue.custom_value_for(1).value
182 assert_equal 'MySQL', issue.custom_value_for(1).value
183 end
183 end
184
184
185 def test_should_update_issue_with_disabled_tracker
185 def test_should_update_issue_with_disabled_tracker
186 p = Project.find(1)
186 p = Project.find(1)
187 issue = Issue.find(1)
187 issue = Issue.find(1)
188
188
189 p.trackers.delete(issue.tracker)
189 p.trackers.delete(issue.tracker)
190 assert !p.trackers.include?(issue.tracker)
190 assert !p.trackers.include?(issue.tracker)
191
191
192 issue.reload
192 issue.reload
193 issue.subject = 'New subject'
193 issue.subject = 'New subject'
194 assert issue.save
194 assert issue.save
195 end
195 end
196
196
197 def test_should_not_set_a_disabled_tracker
197 def test_should_not_set_a_disabled_tracker
198 p = Project.find(1)
198 p = Project.find(1)
199 p.trackers.delete(Tracker.find(2))
199 p.trackers.delete(Tracker.find(2))
200
200
201 issue = Issue.find(1)
201 issue = Issue.find(1)
202 issue.tracker_id = 2
202 issue.tracker_id = 2
203 issue.subject = 'New subject'
203 issue.subject = 'New subject'
204 assert !issue.save
204 assert !issue.save
205 assert_not_nil issue.errors.on(:tracker_id)
205 assert_not_nil issue.errors.on(:tracker_id)
206 end
206 end
207
207
208 def test_category_based_assignment
208 def test_category_based_assignment
209 issue = Issue.create(:project_id => 1, :tracker_id => 1, :author_id => 3, :status_id => 1, :priority => IssuePriority.all.first, :subject => 'Assignment test', :description => 'Assignment test', :category_id => 1)
209 issue = Issue.create(:project_id => 1, :tracker_id => 1, :author_id => 3, :status_id => 1, :priority => IssuePriority.all.first, :subject => 'Assignment test', :description => 'Assignment test', :category_id => 1)
210 assert_equal IssueCategory.find(1).assigned_to, issue.assigned_to
210 assert_equal IssueCategory.find(1).assigned_to, issue.assigned_to
211 end
211 end
212
212
213
213
214
214
215 def test_new_statuses_allowed_to
215 def test_new_statuses_allowed_to
216 Workflow.delete_all
216 Workflow.delete_all
217
217
218 Workflow.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 2, :author => false, :assignee => false)
218 Workflow.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 2, :author => false, :assignee => false)
219 Workflow.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 3, :author => true, :assignee => false)
219 Workflow.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 3, :author => true, :assignee => false)
220 Workflow.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 4, :author => false, :assignee => true)
220 Workflow.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 4, :author => false, :assignee => true)
221 Workflow.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 5, :author => true, :assignee => true)
221 Workflow.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 5, :author => true, :assignee => true)
222 status = IssueStatus.find(1)
222 status = IssueStatus.find(1)
223 role = Role.find(1)
223 role = Role.find(1)
224 tracker = Tracker.find(1)
224 tracker = Tracker.find(1)
225 user = User.find(2)
225 user = User.find(2)
226
226
227 issue = Issue.generate!(:tracker => tracker, :status => status, :project_id => 1)
227 issue = Issue.generate!(:tracker => tracker, :status => status, :project_id => 1)
228 assert_equal [1, 2], issue.new_statuses_allowed_to(user).map(&:id)
228 assert_equal [1, 2], issue.new_statuses_allowed_to(user).map(&:id)
229
229
230 issue = Issue.generate!(:tracker => tracker, :status => status, :project_id => 1, :author => user)
230 issue = Issue.generate!(:tracker => tracker, :status => status, :project_id => 1, :author => user)
231 assert_equal [1, 2, 3], issue.new_statuses_allowed_to(user).map(&:id)
231 assert_equal [1, 2, 3], issue.new_statuses_allowed_to(user).map(&:id)
232
232
233 issue = Issue.generate!(:tracker => tracker, :status => status, :project_id => 1, :assigned_to => user)
233 issue = Issue.generate!(:tracker => tracker, :status => status, :project_id => 1, :assigned_to => user)
234 assert_equal [1, 2, 4], issue.new_statuses_allowed_to(user).map(&:id)
234 assert_equal [1, 2, 4], issue.new_statuses_allowed_to(user).map(&:id)
235
235
236 issue = Issue.generate!(:tracker => tracker, :status => status, :project_id => 1, :author => user, :assigned_to => user)
236 issue = Issue.generate!(:tracker => tracker, :status => status, :project_id => 1, :author => user, :assigned_to => user)
237 assert_equal [1, 2, 3, 4, 5], issue.new_statuses_allowed_to(user).map(&:id)
237 assert_equal [1, 2, 3, 4, 5], issue.new_statuses_allowed_to(user).map(&:id)
238 end
238 end
239
239
240 def test_copy
240 def test_copy
241 issue = Issue.new.copy_from(1)
241 issue = Issue.new.copy_from(1)
242 assert issue.save
242 assert issue.save
243 issue.reload
243 issue.reload
244 orig = Issue.find(1)
244 orig = Issue.find(1)
245 assert_equal orig.subject, issue.subject
245 assert_equal orig.subject, issue.subject
246 assert_equal orig.tracker, issue.tracker
246 assert_equal orig.tracker, issue.tracker
247 assert_equal "125", issue.custom_value_for(2).value
247 assert_equal "125", issue.custom_value_for(2).value
248 end
248 end
249
249
250 def test_copy_should_copy_status
250 def test_copy_should_copy_status
251 orig = Issue.find(8)
251 orig = Issue.find(8)
252 assert orig.status != IssueStatus.default
252 assert orig.status != IssueStatus.default
253
253
254 issue = Issue.new.copy_from(orig)
254 issue = Issue.new.copy_from(orig)
255 assert issue.save
255 assert issue.save
256 issue.reload
256 issue.reload
257 assert_equal orig.status, issue.status
257 assert_equal orig.status, issue.status
258 end
258 end
259
259
260 def test_should_close_duplicates
260 def test_should_close_duplicates
261 # Create 3 issues
261 # Create 3 issues
262 issue1 = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :priority => IssuePriority.all.first, :subject => 'Duplicates test', :description => 'Duplicates test')
262 issue1 = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :priority => IssuePriority.all.first, :subject => 'Duplicates test', :description => 'Duplicates test')
263 assert issue1.save
263 assert issue1.save
264 issue2 = issue1.clone
264 issue2 = issue1.clone
265 assert issue2.save
265 assert issue2.save
266 issue3 = issue1.clone
266 issue3 = issue1.clone
267 assert issue3.save
267 assert issue3.save
268
268
269 # 2 is a dupe of 1
269 # 2 is a dupe of 1
270 IssueRelation.create(:issue_from => issue2, :issue_to => issue1, :relation_type => IssueRelation::TYPE_DUPLICATES)
270 IssueRelation.create(:issue_from => issue2, :issue_to => issue1, :relation_type => IssueRelation::TYPE_DUPLICATES)
271 # And 3 is a dupe of 2
271 # And 3 is a dupe of 2
272 IssueRelation.create(:issue_from => issue3, :issue_to => issue2, :relation_type => IssueRelation::TYPE_DUPLICATES)
272 IssueRelation.create(:issue_from => issue3, :issue_to => issue2, :relation_type => IssueRelation::TYPE_DUPLICATES)
273 # And 3 is a dupe of 1 (circular duplicates)
273 # And 3 is a dupe of 1 (circular duplicates)
274 IssueRelation.create(:issue_from => issue3, :issue_to => issue1, :relation_type => IssueRelation::TYPE_DUPLICATES)
274 IssueRelation.create(:issue_from => issue3, :issue_to => issue1, :relation_type => IssueRelation::TYPE_DUPLICATES)
275
275
276 assert issue1.reload.duplicates.include?(issue2)
276 assert issue1.reload.duplicates.include?(issue2)
277
277
278 # Closing issue 1
278 # Closing issue 1
279 issue1.init_journal(User.find(:first), "Closing issue1")
279 issue1.init_journal(User.find(:first), "Closing issue1")
280 issue1.status = IssueStatus.find :first, :conditions => {:is_closed => true}
280 issue1.status = IssueStatus.find :first, :conditions => {:is_closed => true}
281 assert issue1.save
281 assert issue1.save
282 # 2 and 3 should be also closed
282 # 2 and 3 should be also closed
283 assert issue2.reload.closed?
283 assert issue2.reload.closed?
284 assert issue3.reload.closed?
284 assert issue3.reload.closed?
285 end
285 end
286
286
287 def test_should_not_close_duplicated_issue
287 def test_should_not_close_duplicated_issue
288 # Create 3 issues
288 # Create 3 issues
289 issue1 = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :priority => IssuePriority.all.first, :subject => 'Duplicates test', :description => 'Duplicates test')
289 issue1 = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :priority => IssuePriority.all.first, :subject => 'Duplicates test', :description => 'Duplicates test')
290 assert issue1.save
290 assert issue1.save
291 issue2 = issue1.clone
291 issue2 = issue1.clone
292 assert issue2.save
292 assert issue2.save
293
293
294 # 2 is a dupe of 1
294 # 2 is a dupe of 1
295 IssueRelation.create(:issue_from => issue2, :issue_to => issue1, :relation_type => IssueRelation::TYPE_DUPLICATES)
295 IssueRelation.create(:issue_from => issue2, :issue_to => issue1, :relation_type => IssueRelation::TYPE_DUPLICATES)
296 # 2 is a dup of 1 but 1 is not a duplicate of 2
296 # 2 is a dup of 1 but 1 is not a duplicate of 2
297 assert !issue2.reload.duplicates.include?(issue1)
297 assert !issue2.reload.duplicates.include?(issue1)
298
298
299 # Closing issue 2
299 # Closing issue 2
300 issue2.init_journal(User.find(:first), "Closing issue2")
300 issue2.init_journal(User.find(:first), "Closing issue2")
301 issue2.status = IssueStatus.find :first, :conditions => {:is_closed => true}
301 issue2.status = IssueStatus.find :first, :conditions => {:is_closed => true}
302 assert issue2.save
302 assert issue2.save
303 # 1 should not be also closed
303 # 1 should not be also closed
304 assert !issue1.reload.closed?
304 assert !issue1.reload.closed?
305 end
305 end
306
306
307 def test_assignable_versions
307 def test_assignable_versions
308 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :fixed_version_id => 1, :subject => 'New issue')
308 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :fixed_version_id => 1, :subject => 'New issue')
309 assert_equal ['open'], issue.assignable_versions.collect(&:status).uniq
309 assert_equal ['open'], issue.assignable_versions.collect(&:status).uniq
310 end
310 end
311
311
312 def test_should_not_be_able_to_assign_a_new_issue_to_a_closed_version
312 def test_should_not_be_able_to_assign_a_new_issue_to_a_closed_version
313 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :fixed_version_id => 1, :subject => 'New issue')
313 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :fixed_version_id => 1, :subject => 'New issue')
314 assert !issue.save
314 assert !issue.save
315 assert_not_nil issue.errors.on(:fixed_version_id)
315 assert_not_nil issue.errors.on(:fixed_version_id)
316 end
316 end
317
317
318 def test_should_not_be_able_to_assign_a_new_issue_to_a_locked_version
318 def test_should_not_be_able_to_assign_a_new_issue_to_a_locked_version
319 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :fixed_version_id => 2, :subject => 'New issue')
319 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :fixed_version_id => 2, :subject => 'New issue')
320 assert !issue.save
320 assert !issue.save
321 assert_not_nil issue.errors.on(:fixed_version_id)
321 assert_not_nil issue.errors.on(:fixed_version_id)
322 end
322 end
323
323
324 def test_should_be_able_to_assign_a_new_issue_to_an_open_version
324 def test_should_be_able_to_assign_a_new_issue_to_an_open_version
325 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :fixed_version_id => 3, :subject => 'New issue')
325 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :fixed_version_id => 3, :subject => 'New issue')
326 assert issue.save
326 assert issue.save
327 end
327 end
328
328
329 def test_should_be_able_to_update_an_issue_assigned_to_a_closed_version
329 def test_should_be_able_to_update_an_issue_assigned_to_a_closed_version
330 issue = Issue.find(11)
330 issue = Issue.find(11)
331 assert_equal 'closed', issue.fixed_version.status
331 assert_equal 'closed', issue.fixed_version.status
332 issue.subject = 'Subject changed'
332 issue.subject = 'Subject changed'
333 assert issue.save
333 assert issue.save
334 end
334 end
335
335
336 def test_should_not_be_able_to_reopen_an_issue_assigned_to_a_closed_version
336 def test_should_not_be_able_to_reopen_an_issue_assigned_to_a_closed_version
337 issue = Issue.find(11)
337 issue = Issue.find(11)
338 issue.status_id = 1
338 issue.status_id = 1
339 assert !issue.save
339 assert !issue.save
340 assert_not_nil issue.errors.on_base
340 assert_not_nil issue.errors.on_base
341 end
341 end
342
342
343 def test_should_be_able_to_reopen_and_reassign_an_issue_assigned_to_a_closed_version
343 def test_should_be_able_to_reopen_and_reassign_an_issue_assigned_to_a_closed_version
344 issue = Issue.find(11)
344 issue = Issue.find(11)
345 issue.status_id = 1
345 issue.status_id = 1
346 issue.fixed_version_id = 3
346 issue.fixed_version_id = 3
347 assert issue.save
347 assert issue.save
348 end
348 end
349
349
350 def test_should_be_able_to_reopen_an_issue_assigned_to_a_locked_version
350 def test_should_be_able_to_reopen_an_issue_assigned_to_a_locked_version
351 issue = Issue.find(12)
351 issue = Issue.find(12)
352 assert_equal 'locked', issue.fixed_version.status
352 assert_equal 'locked', issue.fixed_version.status
353 issue.status_id = 1
353 issue.status_id = 1
354 assert issue.save
354 assert issue.save
355 end
355 end
356
356
357 def test_move_to_another_project_with_same_category
357 def test_move_to_another_project_with_same_category
358 issue = Issue.find(1)
358 issue = Issue.find(1)
359 assert issue.move_to_project(Project.find(2))
359 assert issue.move_to_project(Project.find(2))
360 issue.reload
360 issue.reload
361 assert_equal 2, issue.project_id
361 assert_equal 2, issue.project_id
362 # Category changes
362 # Category changes
363 assert_equal 4, issue.category_id
363 assert_equal 4, issue.category_id
364 # Make sure time entries were move to the target project
364 # Make sure time entries were move to the target project
365 assert_equal 2, issue.time_entries.first.project_id
365 assert_equal 2, issue.time_entries.first.project_id
366 end
366 end
367
367
368 def test_move_to_another_project_without_same_category
368 def test_move_to_another_project_without_same_category
369 issue = Issue.find(2)
369 issue = Issue.find(2)
370 assert issue.move_to_project(Project.find(2))
370 assert issue.move_to_project(Project.find(2))
371 issue.reload
371 issue.reload
372 assert_equal 2, issue.project_id
372 assert_equal 2, issue.project_id
373 # Category cleared
373 # Category cleared
374 assert_nil issue.category_id
374 assert_nil issue.category_id
375 end
375 end
376
376
377 def test_move_to_another_project_should_clear_fixed_version_when_not_shared
377 def test_move_to_another_project_should_clear_fixed_version_when_not_shared
378 issue = Issue.find(1)
378 issue = Issue.find(1)
379 issue.update_attribute(:fixed_version_id, 1)
379 issue.update_attribute(:fixed_version_id, 1)
380 assert issue.move_to_project(Project.find(2))
380 assert issue.move_to_project(Project.find(2))
381 issue.reload
381 issue.reload
382 assert_equal 2, issue.project_id
382 assert_equal 2, issue.project_id
383 # Cleared fixed_version
383 # Cleared fixed_version
384 assert_equal nil, issue.fixed_version
384 assert_equal nil, issue.fixed_version
385 end
385 end
386
386
387 def test_move_to_another_project_should_keep_fixed_version_when_shared_with_the_target_project
387 def test_move_to_another_project_should_keep_fixed_version_when_shared_with_the_target_project
388 issue = Issue.find(1)
388 issue = Issue.find(1)
389 issue.update_attribute(:fixed_version_id, 4)
389 issue.update_attribute(:fixed_version_id, 4)
390 assert issue.move_to_project(Project.find(5))
390 assert issue.move_to_project(Project.find(5))
391 issue.reload
391 issue.reload
392 assert_equal 5, issue.project_id
392 assert_equal 5, issue.project_id
393 # Keep fixed_version
393 # Keep fixed_version
394 assert_equal 4, issue.fixed_version_id
394 assert_equal 4, issue.fixed_version_id
395 end
395 end
396
396
397 def test_move_to_another_project_should_clear_fixed_version_when_not_shared_with_the_target_project
397 def test_move_to_another_project_should_clear_fixed_version_when_not_shared_with_the_target_project
398 issue = Issue.find(1)
398 issue = Issue.find(1)
399 issue.update_attribute(:fixed_version_id, 1)
399 issue.update_attribute(:fixed_version_id, 1)
400 assert issue.move_to_project(Project.find(5))
400 assert issue.move_to_project(Project.find(5))
401 issue.reload
401 issue.reload
402 assert_equal 5, issue.project_id
402 assert_equal 5, issue.project_id
403 # Cleared fixed_version
403 # Cleared fixed_version
404 assert_equal nil, issue.fixed_version
404 assert_equal nil, issue.fixed_version
405 end
405 end
406
406
407 def test_move_to_another_project_should_keep_fixed_version_when_shared_systemwide
407 def test_move_to_another_project_should_keep_fixed_version_when_shared_systemwide
408 issue = Issue.find(1)
408 issue = Issue.find(1)
409 issue.update_attribute(:fixed_version_id, 7)
409 issue.update_attribute(:fixed_version_id, 7)
410 assert issue.move_to_project(Project.find(2))
410 assert issue.move_to_project(Project.find(2))
411 issue.reload
411 issue.reload
412 assert_equal 2, issue.project_id
412 assert_equal 2, issue.project_id
413 # Keep fixed_version
413 # Keep fixed_version
414 assert_equal 7, issue.fixed_version_id
414 assert_equal 7, issue.fixed_version_id
415 end
415 end
416
416
417 def test_move_to_another_project_with_disabled_tracker
417 def test_move_to_another_project_with_disabled_tracker
418 issue = Issue.find(1)
418 issue = Issue.find(1)
419 target = Project.find(2)
419 target = Project.find(2)
420 target.tracker_ids = [3]
420 target.tracker_ids = [3]
421 target.save
421 target.save
422 assert_equal false, issue.move_to_project(target)
422 assert_equal false, issue.move_to_project(target)
423 issue.reload
423 issue.reload
424 assert_equal 1, issue.project_id
424 assert_equal 1, issue.project_id
425 end
425 end
426
426
427 def test_copy_to_the_same_project
427 def test_copy_to_the_same_project
428 issue = Issue.find(1)
428 issue = Issue.find(1)
429 copy = nil
429 copy = nil
430 assert_difference 'Issue.count' do
430 assert_difference 'Issue.count' do
431 copy = issue.move_to_project(issue.project, nil, :copy => true)
431 copy = issue.move_to_project(issue.project, nil, :copy => true)
432 end
432 end
433 assert_kind_of Issue, copy
433 assert_kind_of Issue, copy
434 assert_equal issue.project, copy.project
434 assert_equal issue.project, copy.project
435 assert_equal "125", copy.custom_value_for(2).value
435 assert_equal "125", copy.custom_value_for(2).value
436 end
436 end
437
437
438 def test_copy_to_another_project_and_tracker
438 def test_copy_to_another_project_and_tracker
439 issue = Issue.find(1)
439 issue = Issue.find(1)
440 copy = nil
440 copy = nil
441 assert_difference 'Issue.count' do
441 assert_difference 'Issue.count' do
442 copy = issue.move_to_project(Project.find(3), Tracker.find(2), :copy => true)
442 copy = issue.move_to_project(Project.find(3), Tracker.find(2), :copy => true)
443 end
443 end
444 copy.reload
444 copy.reload
445 assert_kind_of Issue, copy
445 assert_kind_of Issue, copy
446 assert_equal Project.find(3), copy.project
446 assert_equal Project.find(3), copy.project
447 assert_equal Tracker.find(2), copy.tracker
447 assert_equal Tracker.find(2), copy.tracker
448 # Custom field #2 is not associated with target tracker
448 # Custom field #2 is not associated with target tracker
449 assert_nil copy.custom_value_for(2)
449 assert_nil copy.custom_value_for(2)
450 end
450 end
451
451
452 context "#move_to_project" do
452 context "#move_to_project" do
453 context "as a copy" do
453 context "as a copy" do
454 setup do
454 setup do
455 @issue = Issue.find(1)
455 @issue = Issue.find(1)
456 @copy = nil
456 @copy = nil
457 end
457 end
458
458
459 should "allow assigned_to changes" do
459 should "allow assigned_to changes" do
460 @copy = @issue.move_to_project(Project.find(3), Tracker.find(2), {:copy => true, :attributes => {:assigned_to_id => 3}})
460 @copy = @issue.move_to_project(Project.find(3), Tracker.find(2), {:copy => true, :attributes => {:assigned_to_id => 3}})
461 assert_equal 3, @copy.assigned_to_id
461 assert_equal 3, @copy.assigned_to_id
462 end
462 end
463
463
464 should "allow status changes" do
464 should "allow status changes" do
465 @copy = @issue.move_to_project(Project.find(3), Tracker.find(2), {:copy => true, :attributes => {:status_id => 2}})
465 @copy = @issue.move_to_project(Project.find(3), Tracker.find(2), {:copy => true, :attributes => {:status_id => 2}})
466 assert_equal 2, @copy.status_id
466 assert_equal 2, @copy.status_id
467 end
467 end
468
468
469 should "allow start date changes" do
469 should "allow start date changes" do
470 date = Date.today
470 date = Date.today
471 @copy = @issue.move_to_project(Project.find(3), Tracker.find(2), {:copy => true, :attributes => {:start_date => date}})
471 @copy = @issue.move_to_project(Project.find(3), Tracker.find(2), {:copy => true, :attributes => {:start_date => date}})
472 assert_equal date, @copy.start_date
472 assert_equal date, @copy.start_date
473 end
473 end
474
474
475 should "allow due date changes" do
475 should "allow due date changes" do
476 date = Date.today
476 date = Date.today
477 @copy = @issue.move_to_project(Project.find(3), Tracker.find(2), {:copy => true, :attributes => {:due_date => date}})
477 @copy = @issue.move_to_project(Project.find(3), Tracker.find(2), {:copy => true, :attributes => {:due_date => date}})
478
478
479 assert_equal date, @copy.due_date
479 assert_equal date, @copy.due_date
480 end
480 end
481 end
481 end
482 end
482 end
483
483
484 def test_recipients_should_not_include_users_that_cannot_view_the_issue
484 def test_recipients_should_not_include_users_that_cannot_view_the_issue
485 issue = Issue.find(12)
485 issue = Issue.find(12)
486 assert issue.recipients.include?(issue.author.mail)
486 assert issue.recipients.include?(issue.author.mail)
487 # move the issue to a private project
487 # move the issue to a private project
488 copy = issue.move_to_project(Project.find(5), Tracker.find(2), :copy => true)
488 copy = issue.move_to_project(Project.find(5), Tracker.find(2), :copy => true)
489 # author is not a member of project anymore
489 # author is not a member of project anymore
490 assert !copy.recipients.include?(copy.author.mail)
490 assert !copy.recipients.include?(copy.author.mail)
491 end
491 end
492
492
493 def test_watcher_recipients_should_not_include_users_that_cannot_view_the_issue
493 def test_watcher_recipients_should_not_include_users_that_cannot_view_the_issue
494 user = User.find(3)
494 user = User.find(3)
495 issue = Issue.find(9)
495 issue = Issue.find(9)
496 Watcher.create!(:user => user, :watchable => issue)
496 Watcher.create!(:user => user, :watchable => issue)
497 assert issue.watched_by?(user)
497 assert issue.watched_by?(user)
498 assert !issue.watcher_recipients.include?(user.mail)
498 assert !issue.watcher_recipients.include?(user.mail)
499 end
499 end
500
500
501 def test_issue_destroy
501 def test_issue_destroy
502 Issue.find(1).destroy
502 Issue.find(1).destroy
503 assert_nil Issue.find_by_id(1)
503 assert_nil Issue.find_by_id(1)
504 assert_nil TimeEntry.find_by_issue_id(1)
504 assert_nil TimeEntry.find_by_issue_id(1)
505 end
505 end
506
506
507 def test_blocked
507 def test_blocked
508 blocked_issue = Issue.find(9)
508 blocked_issue = Issue.find(9)
509 blocking_issue = Issue.find(10)
509 blocking_issue = Issue.find(10)
510
510
511 assert blocked_issue.blocked?
511 assert blocked_issue.blocked?
512 assert !blocking_issue.blocked?
512 assert !blocking_issue.blocked?
513 end
513 end
514
514
515 def test_blocked_issues_dont_allow_closed_statuses
515 def test_blocked_issues_dont_allow_closed_statuses
516 blocked_issue = Issue.find(9)
516 blocked_issue = Issue.find(9)
517
517
518 allowed_statuses = blocked_issue.new_statuses_allowed_to(users(:users_002))
518 allowed_statuses = blocked_issue.new_statuses_allowed_to(users(:users_002))
519 assert !allowed_statuses.empty?
519 assert !allowed_statuses.empty?
520 closed_statuses = allowed_statuses.select {|st| st.is_closed?}
520 closed_statuses = allowed_statuses.select {|st| st.is_closed?}
521 assert closed_statuses.empty?
521 assert closed_statuses.empty?
522 end
522 end
523
523
524 def test_unblocked_issues_allow_closed_statuses
524 def test_unblocked_issues_allow_closed_statuses
525 blocking_issue = Issue.find(10)
525 blocking_issue = Issue.find(10)
526
526
527 allowed_statuses = blocking_issue.new_statuses_allowed_to(users(:users_002))
527 allowed_statuses = blocking_issue.new_statuses_allowed_to(users(:users_002))
528 assert !allowed_statuses.empty?
528 assert !allowed_statuses.empty?
529 closed_statuses = allowed_statuses.select {|st| st.is_closed?}
529 closed_statuses = allowed_statuses.select {|st| st.is_closed?}
530 assert !closed_statuses.empty?
530 assert !closed_statuses.empty?
531 end
531 end
532
532
533 def test_rescheduling_an_issue_should_reschedule_following_issue
533 def test_rescheduling_an_issue_should_reschedule_following_issue
534 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)
534 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)
535 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)
535 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)
536 IssueRelation.create!(:issue_from => issue1, :issue_to => issue2, :relation_type => IssueRelation::TYPE_PRECEDES)
536 IssueRelation.create!(:issue_from => issue1, :issue_to => issue2, :relation_type => IssueRelation::TYPE_PRECEDES)
537 assert_equal issue1.due_date + 1, issue2.reload.start_date
537 assert_equal issue1.due_date + 1, issue2.reload.start_date
538
538
539 issue1.due_date = Date.today + 5
539 issue1.due_date = Date.today + 5
540 issue1.save!
540 issue1.save!
541 assert_equal issue1.due_date + 1, issue2.reload.start_date
541 assert_equal issue1.due_date + 1, issue2.reload.start_date
542 end
542 end
543
543
544 def test_overdue
544 def test_overdue
545 assert Issue.new(:due_date => 1.day.ago.to_date).overdue?
545 assert Issue.new(:due_date => 1.day.ago.to_date).overdue?
546 assert !Issue.new(:due_date => Date.today).overdue?
546 assert !Issue.new(:due_date => Date.today).overdue?
547 assert !Issue.new(:due_date => 1.day.from_now.to_date).overdue?
547 assert !Issue.new(:due_date => 1.day.from_now.to_date).overdue?
548 assert !Issue.new(:due_date => nil).overdue?
548 assert !Issue.new(:due_date => nil).overdue?
549 assert !Issue.new(:due_date => 1.day.ago.to_date, :status => IssueStatus.find(:first, :conditions => {:is_closed => true})).overdue?
549 assert !Issue.new(:due_date => 1.day.ago.to_date, :status => IssueStatus.find(:first, :conditions => {:is_closed => true})).overdue?
550 end
550 end
551
551
552 context "#behind_schedule?" do
552 context "#behind_schedule?" do
553 should "be false if the issue has no start_date" do
553 should "be false if the issue has no start_date" do
554 assert !Issue.new(:start_date => nil, :due_date => 1.day.from_now.to_date, :done_ratio => 0).behind_schedule?
554 assert !Issue.new(:start_date => nil, :due_date => 1.day.from_now.to_date, :done_ratio => 0).behind_schedule?
555 end
555 end
556
556
557 should "be false if the issue has no end_date" do
557 should "be false if the issue has no end_date" do
558 assert !Issue.new(:start_date => 1.day.from_now.to_date, :due_date => nil, :done_ratio => 0).behind_schedule?
558 assert !Issue.new(:start_date => 1.day.from_now.to_date, :due_date => nil, :done_ratio => 0).behind_schedule?
559 end
559 end
560
560
561 should "be false if the issue has more done than it's calendar time" do
561 should "be false if the issue has more done than it's calendar time" do
562 assert !Issue.new(:start_date => 50.days.ago.to_date, :due_date => 50.days.from_now.to_date, :done_ratio => 90).behind_schedule?
562 assert !Issue.new(:start_date => 50.days.ago.to_date, :due_date => 50.days.from_now.to_date, :done_ratio => 90).behind_schedule?
563 end
563 end
564
564
565 should "be true if the issue hasn't been started at all" do
565 should "be true if the issue hasn't been started at all" do
566 assert Issue.new(:start_date => 1.day.ago.to_date, :due_date => 1.day.from_now.to_date, :done_ratio => 0).behind_schedule?
566 assert Issue.new(:start_date => 1.day.ago.to_date, :due_date => 1.day.from_now.to_date, :done_ratio => 0).behind_schedule?
567 end
567 end
568
568
569 should "be true if the issue has used more calendar time than it's done ratio" do
569 should "be true if the issue has used more calendar time than it's done ratio" do
570 assert Issue.new(:start_date => 100.days.ago.to_date, :due_date => Date.today, :done_ratio => 90).behind_schedule?
570 assert Issue.new(:start_date => 100.days.ago.to_date, :due_date => Date.today, :done_ratio => 90).behind_schedule?
571 end
571 end
572 end
572 end
573
573
574 context "#assignable_users" do
574 context "#assignable_users" do
575 should "be Users" do
575 should "be Users" do
576 assert_kind_of User, Issue.find(1).assignable_users.first
576 assert_kind_of User, Issue.find(1).assignable_users.first
577 end
577 end
578
578
579 should "include the issue author" do
579 should "include the issue author" do
580 project = Project.find(1)
580 project = Project.find(1)
581 non_project_member = User.generate!
581 non_project_member = User.generate!
582 issue = Issue.generate_for_project!(project, :author => non_project_member)
582 issue = Issue.generate_for_project!(project, :author => non_project_member)
583
583
584 assert issue.assignable_users.include?(non_project_member)
584 assert issue.assignable_users.include?(non_project_member)
585 end
585 end
586
586
587 should "not show the issue author twice" do
587 should "not show the issue author twice" do
588 assignable_user_ids = Issue.find(1).assignable_users.collect(&:id)
588 assignable_user_ids = Issue.find(1).assignable_users.collect(&:id)
589 assert_equal 2, assignable_user_ids.length
589 assert_equal 2, assignable_user_ids.length
590
590
591 assignable_user_ids.each do |user_id|
591 assignable_user_ids.each do |user_id|
592 assert_equal 1, assignable_user_ids.select {|i| i == user_id}.length, "User #{user_id} appears more or less than once"
592 assert_equal 1, assignable_user_ids.select {|i| i == user_id}.length, "User #{user_id} appears more or less than once"
593 end
593 end
594 end
594 end
595 end
595 end
596
596
597 def test_create_should_send_email_notification
597 def test_create_should_send_email_notification
598 ActionMailer::Base.deliveries.clear
598 ActionMailer::Base.deliveries.clear
599 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3, :status_id => 1, :priority => IssuePriority.all.first, :subject => 'test_create', :estimated_hours => '1:30')
599 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3, :status_id => 1, :priority => IssuePriority.all.first, :subject => 'test_create', :estimated_hours => '1:30')
600
600
601 assert issue.save
601 assert issue.save
602 assert_equal 1, ActionMailer::Base.deliveries.size
602 assert_equal 1, ActionMailer::Base.deliveries.size
603 end
603 end
604
604
605 def test_stale_issue_should_not_send_email_notification
605 def test_stale_issue_should_not_send_email_notification
606 ActionMailer::Base.deliveries.clear
606 ActionMailer::Base.deliveries.clear
607 issue = Issue.find(1)
607 issue = Issue.find(1)
608 stale = Issue.find(1)
608 stale = Issue.find(1)
609
609
610 issue.init_journal(User.find(1))
610 issue.init_journal(User.find(1))
611 issue.subject = 'Subjet update'
611 issue.subject = 'Subjet update'
612 assert issue.save
612 assert issue.save
613 assert_equal 1, ActionMailer::Base.deliveries.size
613 assert_equal 1, ActionMailer::Base.deliveries.size
614 ActionMailer::Base.deliveries.clear
614 ActionMailer::Base.deliveries.clear
615
615
616 stale.init_journal(User.find(1))
616 stale.init_journal(User.find(1))
617 stale.subject = 'Another subjet update'
617 stale.subject = 'Another subjet update'
618 assert_raise ActiveRecord::StaleObjectError do
618 assert_raise ActiveRecord::StaleObjectError do
619 stale.save
619 stale.save
620 end
620 end
621 assert ActionMailer::Base.deliveries.empty?
621 assert ActionMailer::Base.deliveries.empty?
622 end
622 end
623
623
624 def test_journalized_description
624 def test_journalized_description
625 IssueCustomField.delete_all
626
625 i = Issue.first
627 i = Issue.first
626 old_description = i.description
628 old_description = i.description
627 new_description = "This is the new description"
629 new_description = "This is the new description"
628
630
629 i.init_journal(User.find(2))
631 i.init_journal(User.find(2))
630 i.description = new_description
632 i.description = new_description
631 assert_difference 'Journal.count', 1 do
633 assert_difference 'Journal.count', 1 do
632 assert_difference 'JournalDetail.count', 1 do
634 assert_difference 'JournalDetail.count', 1 do
633 i.save!
635 i.save!
634 end
636 end
635 end
637 end
636
638
637 detail = JournalDetail.first(:order => 'id DESC')
639 detail = JournalDetail.first(:order => 'id DESC')
638 assert_equal i, detail.journal.journalized
640 assert_equal i, detail.journal.journalized
639 assert_equal 'attr', detail.property
641 assert_equal 'attr', detail.property
640 assert_equal 'description', detail.prop_key
642 assert_equal 'description', detail.prop_key
641 assert_equal old_description, detail.old_value
643 assert_equal old_description, detail.old_value
642 assert_equal new_description, detail.value
644 assert_equal new_description, detail.value
643 end
645 end
644
646
645 def test_saving_twice_should_not_duplicate_journal_details
647 def test_saving_twice_should_not_duplicate_journal_details
646 i = Issue.find(:first)
648 i = Issue.find(:first)
647 i.init_journal(User.find(2), 'Some notes')
649 i.init_journal(User.find(2), 'Some notes')
648 # initial changes
650 # initial changes
649 i.subject = 'New subject'
651 i.subject = 'New subject'
650 i.done_ratio = i.done_ratio + 10
652 i.done_ratio = i.done_ratio + 10
651 assert_difference 'Journal.count' do
653 assert_difference 'Journal.count' do
652 assert i.save
654 assert i.save
653 end
655 end
654 # 1 more change
656 # 1 more change
655 i.priority = IssuePriority.find(:first, :conditions => ["id <> ?", i.priority_id])
657 i.priority = IssuePriority.find(:first, :conditions => ["id <> ?", i.priority_id])
656 assert_no_difference 'Journal.count' do
658 assert_no_difference 'Journal.count' do
657 assert_difference 'JournalDetail.count', 1 do
659 assert_difference 'JournalDetail.count', 1 do
658 i.save
660 i.save
659 end
661 end
660 end
662 end
661 # no more change
663 # no more change
662 assert_no_difference 'Journal.count' do
664 assert_no_difference 'Journal.count' do
663 assert_no_difference 'JournalDetail.count' do
665 assert_no_difference 'JournalDetail.count' do
664 i.save
666 i.save
665 end
667 end
666 end
668 end
667 end
669 end
668
670
669 def test_all_dependent_issues
671 def test_all_dependent_issues
670 IssueRelation.delete_all
672 IssueRelation.delete_all
671 assert IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(2), :relation_type => IssueRelation::TYPE_PRECEDES)
673 assert IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(2), :relation_type => IssueRelation::TYPE_PRECEDES)
672 assert IssueRelation.create!(:issue_from => Issue.find(2), :issue_to => Issue.find(3), :relation_type => IssueRelation::TYPE_PRECEDES)
674 assert IssueRelation.create!(:issue_from => Issue.find(2), :issue_to => Issue.find(3), :relation_type => IssueRelation::TYPE_PRECEDES)
673 assert IssueRelation.create!(:issue_from => Issue.find(3), :issue_to => Issue.find(8), :relation_type => IssueRelation::TYPE_PRECEDES)
675 assert IssueRelation.create!(:issue_from => Issue.find(3), :issue_to => Issue.find(8), :relation_type => IssueRelation::TYPE_PRECEDES)
674
676
675 assert_equal [2, 3, 8], Issue.find(1).all_dependent_issues.collect(&:id).sort
677 assert_equal [2, 3, 8], Issue.find(1).all_dependent_issues.collect(&:id).sort
676 end
678 end
677
679
678 def test_all_dependent_issues_with_persistent_circular_dependency
680 def test_all_dependent_issues_with_persistent_circular_dependency
679 IssueRelation.delete_all
681 IssueRelation.delete_all
680 assert IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(2), :relation_type => IssueRelation::TYPE_PRECEDES)
682 assert IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(2), :relation_type => IssueRelation::TYPE_PRECEDES)
681 assert IssueRelation.create!(:issue_from => Issue.find(2), :issue_to => Issue.find(3), :relation_type => IssueRelation::TYPE_PRECEDES)
683 assert IssueRelation.create!(:issue_from => Issue.find(2), :issue_to => Issue.find(3), :relation_type => IssueRelation::TYPE_PRECEDES)
682 # Validation skipping
684 # Validation skipping
683 assert IssueRelation.new(:issue_from => Issue.find(3), :issue_to => Issue.find(1), :relation_type => IssueRelation::TYPE_PRECEDES).save(false)
685 assert IssueRelation.new(:issue_from => Issue.find(3), :issue_to => Issue.find(1), :relation_type => IssueRelation::TYPE_PRECEDES).save(false)
684
686
685 assert_equal [2, 3], Issue.find(1).all_dependent_issues.collect(&:id).sort
687 assert_equal [2, 3], Issue.find(1).all_dependent_issues.collect(&:id).sort
686 end
688 end
687
689
688 context "#done_ratio" do
690 context "#done_ratio" do
689 setup do
691 setup do
690 @issue = Issue.find(1)
692 @issue = Issue.find(1)
691 @issue_status = IssueStatus.find(1)
693 @issue_status = IssueStatus.find(1)
692 @issue_status.update_attribute(:default_done_ratio, 50)
694 @issue_status.update_attribute(:default_done_ratio, 50)
693 @issue2 = Issue.find(2)
695 @issue2 = Issue.find(2)
694 @issue_status2 = IssueStatus.find(2)
696 @issue_status2 = IssueStatus.find(2)
695 @issue_status2.update_attribute(:default_done_ratio, 0)
697 @issue_status2.update_attribute(:default_done_ratio, 0)
696 end
698 end
697
699
698 context "with Setting.issue_done_ratio using the issue_field" do
700 context "with Setting.issue_done_ratio using the issue_field" do
699 setup do
701 setup do
700 Setting.issue_done_ratio = 'issue_field'
702 Setting.issue_done_ratio = 'issue_field'
701 end
703 end
702
704
703 should "read the issue's field" do
705 should "read the issue's field" do
704 assert_equal 0, @issue.done_ratio
706 assert_equal 0, @issue.done_ratio
705 assert_equal 30, @issue2.done_ratio
707 assert_equal 30, @issue2.done_ratio
706 end
708 end
707 end
709 end
708
710
709 context "with Setting.issue_done_ratio using the issue_status" do
711 context "with Setting.issue_done_ratio using the issue_status" do
710 setup do
712 setup do
711 Setting.issue_done_ratio = 'issue_status'
713 Setting.issue_done_ratio = 'issue_status'
712 end
714 end
713
715
714 should "read the Issue Status's default done ratio" do
716 should "read the Issue Status's default done ratio" do
715 assert_equal 50, @issue.done_ratio
717 assert_equal 50, @issue.done_ratio
716 assert_equal 0, @issue2.done_ratio
718 assert_equal 0, @issue2.done_ratio
717 end
719 end
718 end
720 end
719 end
721 end
720
722
721 context "#update_done_ratio_from_issue_status" do
723 context "#update_done_ratio_from_issue_status" do
722 setup do
724 setup do
723 @issue = Issue.find(1)
725 @issue = Issue.find(1)
724 @issue_status = IssueStatus.find(1)
726 @issue_status = IssueStatus.find(1)
725 @issue_status.update_attribute(:default_done_ratio, 50)
727 @issue_status.update_attribute(:default_done_ratio, 50)
726 @issue2 = Issue.find(2)
728 @issue2 = Issue.find(2)
727 @issue_status2 = IssueStatus.find(2)
729 @issue_status2 = IssueStatus.find(2)
728 @issue_status2.update_attribute(:default_done_ratio, 0)
730 @issue_status2.update_attribute(:default_done_ratio, 0)
729 end
731 end
730
732
731 context "with Setting.issue_done_ratio using the issue_field" do
733 context "with Setting.issue_done_ratio using the issue_field" do
732 setup do
734 setup do
733 Setting.issue_done_ratio = 'issue_field'
735 Setting.issue_done_ratio = 'issue_field'
734 end
736 end
735
737
736 should "not change the issue" do
738 should "not change the issue" do
737 @issue.update_done_ratio_from_issue_status
739 @issue.update_done_ratio_from_issue_status
738 @issue2.update_done_ratio_from_issue_status
740 @issue2.update_done_ratio_from_issue_status
739
741
740 assert_equal 0, @issue.read_attribute(:done_ratio)
742 assert_equal 0, @issue.read_attribute(:done_ratio)
741 assert_equal 30, @issue2.read_attribute(:done_ratio)
743 assert_equal 30, @issue2.read_attribute(:done_ratio)
742 end
744 end
743 end
745 end
744
746
745 context "with Setting.issue_done_ratio using the issue_status" do
747 context "with Setting.issue_done_ratio using the issue_status" do
746 setup do
748 setup do
747 Setting.issue_done_ratio = 'issue_status'
749 Setting.issue_done_ratio = 'issue_status'
748 end
750 end
749
751
750 should "change the issue's done ratio" do
752 should "change the issue's done ratio" do
751 @issue.update_done_ratio_from_issue_status
753 @issue.update_done_ratio_from_issue_status
752 @issue2.update_done_ratio_from_issue_status
754 @issue2.update_done_ratio_from_issue_status
753
755
754 assert_equal 50, @issue.read_attribute(:done_ratio)
756 assert_equal 50, @issue.read_attribute(:done_ratio)
755 assert_equal 0, @issue2.read_attribute(:done_ratio)
757 assert_equal 0, @issue2.read_attribute(:done_ratio)
756 end
758 end
757 end
759 end
758 end
760 end
759
761
760 test "#by_tracker" do
762 test "#by_tracker" do
761 groups = Issue.by_tracker(Project.find(1))
763 groups = Issue.by_tracker(Project.find(1))
762 assert_equal 3, groups.size
764 assert_equal 3, groups.size
763 assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i}
765 assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i}
764 end
766 end
765
767
766 test "#by_version" do
768 test "#by_version" do
767 groups = Issue.by_version(Project.find(1))
769 groups = Issue.by_version(Project.find(1))
768 assert_equal 3, groups.size
770 assert_equal 3, groups.size
769 assert_equal 3, groups.inject(0) {|sum, group| sum + group['total'].to_i}
771 assert_equal 3, groups.inject(0) {|sum, group| sum + group['total'].to_i}
770 end
772 end
771
773
772 test "#by_priority" do
774 test "#by_priority" do
773 groups = Issue.by_priority(Project.find(1))
775 groups = Issue.by_priority(Project.find(1))
774 assert_equal 4, groups.size
776 assert_equal 4, groups.size
775 assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i}
777 assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i}
776 end
778 end
777
779
778 test "#by_category" do
780 test "#by_category" do
779 groups = Issue.by_category(Project.find(1))
781 groups = Issue.by_category(Project.find(1))
780 assert_equal 2, groups.size
782 assert_equal 2, groups.size
781 assert_equal 3, groups.inject(0) {|sum, group| sum + group['total'].to_i}
783 assert_equal 3, groups.inject(0) {|sum, group| sum + group['total'].to_i}
782 end
784 end
783
785
784 test "#by_assigned_to" do
786 test "#by_assigned_to" do
785 groups = Issue.by_assigned_to(Project.find(1))
787 groups = Issue.by_assigned_to(Project.find(1))
786 assert_equal 2, groups.size
788 assert_equal 2, groups.size
787 assert_equal 2, groups.inject(0) {|sum, group| sum + group['total'].to_i}
789 assert_equal 2, groups.inject(0) {|sum, group| sum + group['total'].to_i}
788 end
790 end
789
791
790 test "#by_author" do
792 test "#by_author" do
791 groups = Issue.by_author(Project.find(1))
793 groups = Issue.by_author(Project.find(1))
792 assert_equal 4, groups.size
794 assert_equal 4, groups.size
793 assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i}
795 assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i}
794 end
796 end
795
797
796 test "#by_subproject" do
798 test "#by_subproject" do
797 groups = Issue.by_subproject(Project.find(1))
799 groups = Issue.by_subproject(Project.find(1))
798 assert_equal 2, groups.size
800 assert_equal 2, groups.size
799 assert_equal 5, groups.inject(0) {|sum, group| sum + group['total'].to_i}
801 assert_equal 5, groups.inject(0) {|sum, group| sum + group['total'].to_i}
800 end
802 end
801
803
802
804
803 context ".allowed_target_projects_on_move" do
805 context ".allowed_target_projects_on_move" do
804 should "return all active projects for admin users" do
806 should "return all active projects for admin users" do
805 User.current = User.find(1)
807 User.current = User.find(1)
806 assert_equal Project.active.count, Issue.allowed_target_projects_on_move.size
808 assert_equal Project.active.count, Issue.allowed_target_projects_on_move.size
807 end
809 end
808
810
809 should "return allowed projects for non admin users" do
811 should "return allowed projects for non admin users" do
810 User.current = User.find(2)
812 User.current = User.find(2)
811 Role.non_member.remove_permission! :move_issues
813 Role.non_member.remove_permission! :move_issues
812 assert_equal 3, Issue.allowed_target_projects_on_move.size
814 assert_equal 3, Issue.allowed_target_projects_on_move.size
813
815
814 Role.non_member.add_permission! :move_issues
816 Role.non_member.add_permission! :move_issues
815 assert_equal Project.active.count, Issue.allowed_target_projects_on_move.size
817 assert_equal Project.active.count, Issue.allowed_target_projects_on_move.size
816 end
818 end
817 end
819 end
818
820
819 def test_recently_updated_with_limit_scopes
821 def test_recently_updated_with_limit_scopes
820 #should return the last updated issue
822 #should return the last updated issue
821 assert_equal 1, Issue.recently_updated.with_limit(1).length
823 assert_equal 1, Issue.recently_updated.with_limit(1).length
822 assert_equal Issue.find(:first, :order => "updated_on DESC"), Issue.recently_updated.with_limit(1).first
824 assert_equal Issue.find(:first, :order => "updated_on DESC"), Issue.recently_updated.with_limit(1).first
823 end
825 end
824
826
825 def test_on_active_projects_scope
827 def test_on_active_projects_scope
826 assert Project.find(2).archive
828 assert Project.find(2).archive
827
829
828 before = Issue.on_active_project.length
830 before = Issue.on_active_project.length
829 # test inclusion to results
831 # test inclusion to results
830 issue = Issue.generate_for_project!(Project.find(1), :tracker => Project.find(2).trackers.first)
832 issue = Issue.generate_for_project!(Project.find(1), :tracker => Project.find(2).trackers.first)
831 assert_equal before + 1, Issue.on_active_project.length
833 assert_equal before + 1, Issue.on_active_project.length
832
834
833 # Move to an archived project
835 # Move to an archived project
834 issue.project = Project.find(2)
836 issue.project = Project.find(2)
835 assert issue.save
837 assert issue.save
836 assert_equal before, Issue.on_active_project.length
838 assert_equal before, Issue.on_active_project.length
837 end
839 end
838
840
839 context "Issue#recipients" do
841 context "Issue#recipients" do
840 setup do
842 setup do
841 @project = Project.find(1)
843 @project = Project.find(1)
842 @author = User.generate_with_protected!
844 @author = User.generate_with_protected!
843 @assignee = User.generate_with_protected!
845 @assignee = User.generate_with_protected!
844 @issue = Issue.generate_for_project!(@project, :assigned_to => @assignee, :author => @author)
846 @issue = Issue.generate_for_project!(@project, :assigned_to => @assignee, :author => @author)
845 end
847 end
846
848
847 should "include project recipients" do
849 should "include project recipients" do
848 assert @project.recipients.present?
850 assert @project.recipients.present?
849 @project.recipients.each do |project_recipient|
851 @project.recipients.each do |project_recipient|
850 assert @issue.recipients.include?(project_recipient)
852 assert @issue.recipients.include?(project_recipient)
851 end
853 end
852 end
854 end
853
855
854 should "include the author if the author is active" do
856 should "include the author if the author is active" do
855 assert @issue.author, "No author set for Issue"
857 assert @issue.author, "No author set for Issue"
856 assert @issue.recipients.include?(@issue.author.mail)
858 assert @issue.recipients.include?(@issue.author.mail)
857 end
859 end
858
860
859 should "include the assigned to user if the assigned to user is active" do
861 should "include the assigned to user if the assigned to user is active" do
860 assert @issue.assigned_to, "No assigned_to set for Issue"
862 assert @issue.assigned_to, "No assigned_to set for Issue"
861 assert @issue.recipients.include?(@issue.assigned_to.mail)
863 assert @issue.recipients.include?(@issue.assigned_to.mail)
862 end
864 end
863
865
864 should "not include users who opt out of all email" do
866 should "not include users who opt out of all email" do
865 @author.update_attribute(:mail_notification, :none)
867 @author.update_attribute(:mail_notification, :none)
866
868
867 assert !@issue.recipients.include?(@issue.author.mail)
869 assert !@issue.recipients.include?(@issue.author.mail)
868 end
870 end
869
871
870 should "not include the issue author if they are only notified of assigned issues" do
872 should "not include the issue author if they are only notified of assigned issues" do
871 @author.update_attribute(:mail_notification, :only_assigned)
873 @author.update_attribute(:mail_notification, :only_assigned)
872
874
873 assert !@issue.recipients.include?(@issue.author.mail)
875 assert !@issue.recipients.include?(@issue.author.mail)
874 end
876 end
875
877
876 should "not include the assigned user if they are only notified of owned issues" do
878 should "not include the assigned user if they are only notified of owned issues" do
877 @assignee.update_attribute(:mail_notification, :only_owner)
879 @assignee.update_attribute(:mail_notification, :only_owner)
878
880
879 assert !@issue.recipients.include?(@issue.assigned_to.mail)
881 assert !@issue.recipients.include?(@issue.assigned_to.mail)
880 end
882 end
881
883
882 end
884 end
883 end
885 end
General Comments 0
You need to be logged in to leave comments. Login now