##// END OF EJS Templates
not use assert_not_nil in Errors#[]...
Toshi MARUYAMA -
r11840:c49451eb102d
parent child
Show More
@@ -1,592 +1,592
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2013 Jean-Philippe Lang
2 # Copyright (C) 2006-2013 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 ProjectsControllerTest < ActionController::TestCase
20 class ProjectsControllerTest < ActionController::TestCase
21 fixtures :projects, :versions, :users, :roles, :members, :member_roles, :issues, :journals, :journal_details,
21 fixtures :projects, :versions, :users, :roles, :members, :member_roles, :issues, :journals, :journal_details,
22 :trackers, :projects_trackers, :issue_statuses, :enabled_modules, :enumerations, :boards, :messages,
22 :trackers, :projects_trackers, :issue_statuses, :enabled_modules, :enumerations, :boards, :messages,
23 :attachments, :custom_fields, :custom_values, :time_entries
23 :attachments, :custom_fields, :custom_values, :time_entries
24
24
25 def setup
25 def setup
26 @request.session[:user_id] = nil
26 @request.session[:user_id] = nil
27 Setting.default_language = 'en'
27 Setting.default_language = 'en'
28 end
28 end
29
29
30 def test_index_by_anonymous_should_not_show_private_projects
30 def test_index_by_anonymous_should_not_show_private_projects
31 get :index
31 get :index
32 assert_response :success
32 assert_response :success
33 assert_template 'index'
33 assert_template 'index'
34 projects = assigns(:projects)
34 projects = assigns(:projects)
35 assert_not_nil projects
35 assert_not_nil projects
36 assert projects.all?(&:is_public?)
36 assert projects.all?(&:is_public?)
37
37
38 assert_select 'ul' do
38 assert_select 'ul' do
39 assert_select 'li' do
39 assert_select 'li' do
40 assert_select 'a', :text => 'eCookbook'
40 assert_select 'a', :text => 'eCookbook'
41 assert_select 'ul' do
41 assert_select 'ul' do
42 assert_select 'a', :text => 'Child of private child'
42 assert_select 'a', :text => 'Child of private child'
43 end
43 end
44 end
44 end
45 end
45 end
46 assert_select 'a', :text => /Private child of eCookbook/, :count => 0
46 assert_select 'a', :text => /Private child of eCookbook/, :count => 0
47 end
47 end
48
48
49 def test_index_atom
49 def test_index_atom
50 get :index, :format => 'atom'
50 get :index, :format => 'atom'
51 assert_response :success
51 assert_response :success
52 assert_template 'common/feed'
52 assert_template 'common/feed'
53 assert_select 'feed>title', :text => 'Redmine: Latest projects'
53 assert_select 'feed>title', :text => 'Redmine: Latest projects'
54 assert_select 'feed>entry', :count => Project.visible(User.current).count
54 assert_select 'feed>entry', :count => Project.visible(User.current).count
55 end
55 end
56
56
57 test "#index by non-admin user with view_time_entries permission should show overall spent time link" do
57 test "#index by non-admin user with view_time_entries permission should show overall spent time link" do
58 @request.session[:user_id] = 3
58 @request.session[:user_id] = 3
59 get :index
59 get :index
60 assert_template 'index'
60 assert_template 'index'
61 assert_select 'a[href=?]', '/time_entries'
61 assert_select 'a[href=?]', '/time_entries'
62 end
62 end
63
63
64 test "#index by non-admin user without view_time_entries permission should not show overall spent time link" do
64 test "#index by non-admin user without view_time_entries permission should not show overall spent time link" do
65 Role.find(2).remove_permission! :view_time_entries
65 Role.find(2).remove_permission! :view_time_entries
66 Role.non_member.remove_permission! :view_time_entries
66 Role.non_member.remove_permission! :view_time_entries
67 Role.anonymous.remove_permission! :view_time_entries
67 Role.anonymous.remove_permission! :view_time_entries
68 @request.session[:user_id] = 3
68 @request.session[:user_id] = 3
69
69
70 get :index
70 get :index
71 assert_template 'index'
71 assert_template 'index'
72 assert_select 'a[href=?]', '/time_entries', 0
72 assert_select 'a[href=?]', '/time_entries', 0
73 end
73 end
74
74
75 test "#new by admin user should accept get" do
75 test "#new by admin user should accept get" do
76 @request.session[:user_id] = 1
76 @request.session[:user_id] = 1
77
77
78 get :new
78 get :new
79 assert_response :success
79 assert_response :success
80 assert_template 'new'
80 assert_template 'new'
81 end
81 end
82
82
83 test "#new by non-admin user with add_project permission should accept get" do
83 test "#new by non-admin user with add_project permission should accept get" do
84 Role.non_member.add_permission! :add_project
84 Role.non_member.add_permission! :add_project
85 @request.session[:user_id] = 9
85 @request.session[:user_id] = 9
86
86
87 get :new
87 get :new
88 assert_response :success
88 assert_response :success
89 assert_template 'new'
89 assert_template 'new'
90 assert_select 'select[name=?]', 'project[parent_id]', 0
90 assert_select 'select[name=?]', 'project[parent_id]', 0
91 end
91 end
92
92
93 test "#new by non-admin user with add_subprojects permission should accept get" do
93 test "#new by non-admin user with add_subprojects permission should accept get" do
94 Role.find(1).remove_permission! :add_project
94 Role.find(1).remove_permission! :add_project
95 Role.find(1).add_permission! :add_subprojects
95 Role.find(1).add_permission! :add_subprojects
96 @request.session[:user_id] = 2
96 @request.session[:user_id] = 2
97
97
98 get :new, :parent_id => 'ecookbook'
98 get :new, :parent_id => 'ecookbook'
99 assert_response :success
99 assert_response :success
100 assert_template 'new'
100 assert_template 'new'
101
101
102 assert_select 'select[name=?]', 'project[parent_id]' do
102 assert_select 'select[name=?]', 'project[parent_id]' do
103 # parent project selected
103 # parent project selected
104 assert_select 'option[value=1][selected=selected]'
104 assert_select 'option[value=1][selected=selected]'
105 # no empty value
105 # no empty value
106 assert_select 'option[value=]', 0
106 assert_select 'option[value=]', 0
107 end
107 end
108 end
108 end
109
109
110 test "#create by admin user should create a new project" do
110 test "#create by admin user should create a new project" do
111 @request.session[:user_id] = 1
111 @request.session[:user_id] = 1
112
112
113 post :create,
113 post :create,
114 :project => {
114 :project => {
115 :name => "blog",
115 :name => "blog",
116 :description => "weblog",
116 :description => "weblog",
117 :homepage => 'http://weblog',
117 :homepage => 'http://weblog',
118 :identifier => "blog",
118 :identifier => "blog",
119 :is_public => 1,
119 :is_public => 1,
120 :custom_field_values => { '3' => 'Beta' },
120 :custom_field_values => { '3' => 'Beta' },
121 :tracker_ids => ['1', '3'],
121 :tracker_ids => ['1', '3'],
122 # an issue custom field that is not for all project
122 # an issue custom field that is not for all project
123 :issue_custom_field_ids => ['9'],
123 :issue_custom_field_ids => ['9'],
124 :enabled_module_names => ['issue_tracking', 'news', 'repository']
124 :enabled_module_names => ['issue_tracking', 'news', 'repository']
125 }
125 }
126 assert_redirected_to '/projects/blog/settings'
126 assert_redirected_to '/projects/blog/settings'
127
127
128 project = Project.find_by_name('blog')
128 project = Project.find_by_name('blog')
129 assert_kind_of Project, project
129 assert_kind_of Project, project
130 assert project.active?
130 assert project.active?
131 assert_equal 'weblog', project.description
131 assert_equal 'weblog', project.description
132 assert_equal 'http://weblog', project.homepage
132 assert_equal 'http://weblog', project.homepage
133 assert_equal true, project.is_public?
133 assert_equal true, project.is_public?
134 assert_nil project.parent
134 assert_nil project.parent
135 assert_equal 'Beta', project.custom_value_for(3).value
135 assert_equal 'Beta', project.custom_value_for(3).value
136 assert_equal [1, 3], project.trackers.map(&:id).sort
136 assert_equal [1, 3], project.trackers.map(&:id).sort
137 assert_equal ['issue_tracking', 'news', 'repository'], project.enabled_module_names.sort
137 assert_equal ['issue_tracking', 'news', 'repository'], project.enabled_module_names.sort
138 assert project.issue_custom_fields.include?(IssueCustomField.find(9))
138 assert project.issue_custom_fields.include?(IssueCustomField.find(9))
139 end
139 end
140
140
141 test "#create by admin user should create a new subproject" do
141 test "#create by admin user should create a new subproject" do
142 @request.session[:user_id] = 1
142 @request.session[:user_id] = 1
143
143
144 assert_difference 'Project.count' do
144 assert_difference 'Project.count' do
145 post :create, :project => { :name => "blog",
145 post :create, :project => { :name => "blog",
146 :description => "weblog",
146 :description => "weblog",
147 :identifier => "blog",
147 :identifier => "blog",
148 :is_public => 1,
148 :is_public => 1,
149 :custom_field_values => { '3' => 'Beta' },
149 :custom_field_values => { '3' => 'Beta' },
150 :parent_id => 1
150 :parent_id => 1
151 }
151 }
152 assert_redirected_to '/projects/blog/settings'
152 assert_redirected_to '/projects/blog/settings'
153 end
153 end
154
154
155 project = Project.find_by_name('blog')
155 project = Project.find_by_name('blog')
156 assert_kind_of Project, project
156 assert_kind_of Project, project
157 assert_equal Project.find(1), project.parent
157 assert_equal Project.find(1), project.parent
158 end
158 end
159
159
160 test "#create by admin user should continue" do
160 test "#create by admin user should continue" do
161 @request.session[:user_id] = 1
161 @request.session[:user_id] = 1
162
162
163 assert_difference 'Project.count' do
163 assert_difference 'Project.count' do
164 post :create, :project => {:name => "blog", :identifier => "blog"}, :continue => 'Create and continue'
164 post :create, :project => {:name => "blog", :identifier => "blog"}, :continue => 'Create and continue'
165 end
165 end
166 assert_redirected_to '/projects/new'
166 assert_redirected_to '/projects/new'
167 end
167 end
168
168
169 test "#create by non-admin user with add_project permission should create a new project" do
169 test "#create by non-admin user with add_project permission should create a new project" do
170 Role.non_member.add_permission! :add_project
170 Role.non_member.add_permission! :add_project
171 @request.session[:user_id] = 9
171 @request.session[:user_id] = 9
172
172
173 post :create, :project => { :name => "blog",
173 post :create, :project => { :name => "blog",
174 :description => "weblog",
174 :description => "weblog",
175 :identifier => "blog",
175 :identifier => "blog",
176 :is_public => 1,
176 :is_public => 1,
177 :custom_field_values => { '3' => 'Beta' },
177 :custom_field_values => { '3' => 'Beta' },
178 :tracker_ids => ['1', '3'],
178 :tracker_ids => ['1', '3'],
179 :enabled_module_names => ['issue_tracking', 'news', 'repository']
179 :enabled_module_names => ['issue_tracking', 'news', 'repository']
180 }
180 }
181
181
182 assert_redirected_to '/projects/blog/settings'
182 assert_redirected_to '/projects/blog/settings'
183
183
184 project = Project.find_by_name('blog')
184 project = Project.find_by_name('blog')
185 assert_kind_of Project, project
185 assert_kind_of Project, project
186 assert_equal 'weblog', project.description
186 assert_equal 'weblog', project.description
187 assert_equal true, project.is_public?
187 assert_equal true, project.is_public?
188 assert_equal [1, 3], project.trackers.map(&:id).sort
188 assert_equal [1, 3], project.trackers.map(&:id).sort
189 assert_equal ['issue_tracking', 'news', 'repository'], project.enabled_module_names.sort
189 assert_equal ['issue_tracking', 'news', 'repository'], project.enabled_module_names.sort
190
190
191 # User should be added as a project member
191 # User should be added as a project member
192 assert User.find(9).member_of?(project)
192 assert User.find(9).member_of?(project)
193 assert_equal 1, project.members.size
193 assert_equal 1, project.members.size
194 end
194 end
195
195
196 test "#create by non-admin user with add_project permission should fail with parent_id" do
196 test "#create by non-admin user with add_project permission should fail with parent_id" do
197 Role.non_member.add_permission! :add_project
197 Role.non_member.add_permission! :add_project
198 @request.session[:user_id] = 9
198 @request.session[:user_id] = 9
199
199
200 assert_no_difference 'Project.count' do
200 assert_no_difference 'Project.count' do
201 post :create, :project => { :name => "blog",
201 post :create, :project => { :name => "blog",
202 :description => "weblog",
202 :description => "weblog",
203 :identifier => "blog",
203 :identifier => "blog",
204 :is_public => 1,
204 :is_public => 1,
205 :custom_field_values => { '3' => 'Beta' },
205 :custom_field_values => { '3' => 'Beta' },
206 :parent_id => 1
206 :parent_id => 1
207 }
207 }
208 end
208 end
209 assert_response :success
209 assert_response :success
210 project = assigns(:project)
210 project = assigns(:project)
211 assert_kind_of Project, project
211 assert_kind_of Project, project
212 assert_not_nil project.errors[:parent_id]
212 assert_not_equal [], project.errors[:parent_id]
213 end
213 end
214
214
215 test "#create by non-admin user with add_subprojects permission should create a project with a parent_id" do
215 test "#create by non-admin user with add_subprojects permission should create a project with a parent_id" do
216 Role.find(1).remove_permission! :add_project
216 Role.find(1).remove_permission! :add_project
217 Role.find(1).add_permission! :add_subprojects
217 Role.find(1).add_permission! :add_subprojects
218 @request.session[:user_id] = 2
218 @request.session[:user_id] = 2
219
219
220 post :create, :project => { :name => "blog",
220 post :create, :project => { :name => "blog",
221 :description => "weblog",
221 :description => "weblog",
222 :identifier => "blog",
222 :identifier => "blog",
223 :is_public => 1,
223 :is_public => 1,
224 :custom_field_values => { '3' => 'Beta' },
224 :custom_field_values => { '3' => 'Beta' },
225 :parent_id => 1
225 :parent_id => 1
226 }
226 }
227 assert_redirected_to '/projects/blog/settings'
227 assert_redirected_to '/projects/blog/settings'
228 project = Project.find_by_name('blog')
228 project = Project.find_by_name('blog')
229 end
229 end
230
230
231 test "#create by non-admin user with add_subprojects permission should fail without parent_id" do
231 test "#create by non-admin user with add_subprojects permission should fail without parent_id" do
232 Role.find(1).remove_permission! :add_project
232 Role.find(1).remove_permission! :add_project
233 Role.find(1).add_permission! :add_subprojects
233 Role.find(1).add_permission! :add_subprojects
234 @request.session[:user_id] = 2
234 @request.session[:user_id] = 2
235
235
236 assert_no_difference 'Project.count' do
236 assert_no_difference 'Project.count' do
237 post :create, :project => { :name => "blog",
237 post :create, :project => { :name => "blog",
238 :description => "weblog",
238 :description => "weblog",
239 :identifier => "blog",
239 :identifier => "blog",
240 :is_public => 1,
240 :is_public => 1,
241 :custom_field_values => { '3' => 'Beta' }
241 :custom_field_values => { '3' => 'Beta' }
242 }
242 }
243 end
243 end
244 assert_response :success
244 assert_response :success
245 project = assigns(:project)
245 project = assigns(:project)
246 assert_kind_of Project, project
246 assert_kind_of Project, project
247 assert_not_nil project.errors[:parent_id]
247 assert_not_equal [], project.errors[:parent_id]
248 end
248 end
249
249
250 test "#create by non-admin user with add_subprojects permission should fail with unauthorized parent_id" do
250 test "#create by non-admin user with add_subprojects permission should fail with unauthorized parent_id" do
251 Role.find(1).remove_permission! :add_project
251 Role.find(1).remove_permission! :add_project
252 Role.find(1).add_permission! :add_subprojects
252 Role.find(1).add_permission! :add_subprojects
253 @request.session[:user_id] = 2
253 @request.session[:user_id] = 2
254
254
255 assert !User.find(2).member_of?(Project.find(6))
255 assert !User.find(2).member_of?(Project.find(6))
256 assert_no_difference 'Project.count' do
256 assert_no_difference 'Project.count' do
257 post :create, :project => { :name => "blog",
257 post :create, :project => { :name => "blog",
258 :description => "weblog",
258 :description => "weblog",
259 :identifier => "blog",
259 :identifier => "blog",
260 :is_public => 1,
260 :is_public => 1,
261 :custom_field_values => { '3' => 'Beta' },
261 :custom_field_values => { '3' => 'Beta' },
262 :parent_id => 6
262 :parent_id => 6
263 }
263 }
264 end
264 end
265 assert_response :success
265 assert_response :success
266 project = assigns(:project)
266 project = assigns(:project)
267 assert_kind_of Project, project
267 assert_kind_of Project, project
268 assert_not_nil project.errors[:parent_id]
268 assert_not_equal [], project.errors[:parent_id]
269 end
269 end
270
270
271 def test_create_subproject_with_inherit_members_should_inherit_members
271 def test_create_subproject_with_inherit_members_should_inherit_members
272 Role.find_by_name('Manager').add_permission! :add_subprojects
272 Role.find_by_name('Manager').add_permission! :add_subprojects
273 parent = Project.find(1)
273 parent = Project.find(1)
274 @request.session[:user_id] = 2
274 @request.session[:user_id] = 2
275
275
276 assert_difference 'Project.count' do
276 assert_difference 'Project.count' do
277 post :create, :project => {
277 post :create, :project => {
278 :name => 'inherited', :identifier => 'inherited', :parent_id => parent.id, :inherit_members => '1'
278 :name => 'inherited', :identifier => 'inherited', :parent_id => parent.id, :inherit_members => '1'
279 }
279 }
280 assert_response 302
280 assert_response 302
281 end
281 end
282
282
283 project = Project.order('id desc').first
283 project = Project.order('id desc').first
284 assert_equal 'inherited', project.name
284 assert_equal 'inherited', project.name
285 assert_equal parent, project.parent
285 assert_equal parent, project.parent
286 assert project.memberships.count > 0
286 assert project.memberships.count > 0
287 assert_equal parent.memberships.count, project.memberships.count
287 assert_equal parent.memberships.count, project.memberships.count
288 end
288 end
289
289
290 def test_create_should_preserve_modules_on_validation_failure
290 def test_create_should_preserve_modules_on_validation_failure
291 with_settings :default_projects_modules => ['issue_tracking', 'repository'] do
291 with_settings :default_projects_modules => ['issue_tracking', 'repository'] do
292 @request.session[:user_id] = 1
292 @request.session[:user_id] = 1
293 assert_no_difference 'Project.count' do
293 assert_no_difference 'Project.count' do
294 post :create, :project => {
294 post :create, :project => {
295 :name => "blog",
295 :name => "blog",
296 :identifier => "",
296 :identifier => "",
297 :enabled_module_names => %w(issue_tracking news)
297 :enabled_module_names => %w(issue_tracking news)
298 }
298 }
299 end
299 end
300 assert_response :success
300 assert_response :success
301 project = assigns(:project)
301 project = assigns(:project)
302 assert_equal %w(issue_tracking news), project.enabled_module_names.sort
302 assert_equal %w(issue_tracking news), project.enabled_module_names.sort
303 end
303 end
304 end
304 end
305
305
306 def test_show_by_id
306 def test_show_by_id
307 get :show, :id => 1
307 get :show, :id => 1
308 assert_response :success
308 assert_response :success
309 assert_template 'show'
309 assert_template 'show'
310 assert_not_nil assigns(:project)
310 assert_not_nil assigns(:project)
311 end
311 end
312
312
313 def test_show_by_identifier
313 def test_show_by_identifier
314 get :show, :id => 'ecookbook'
314 get :show, :id => 'ecookbook'
315 assert_response :success
315 assert_response :success
316 assert_template 'show'
316 assert_template 'show'
317 assert_not_nil assigns(:project)
317 assert_not_nil assigns(:project)
318 assert_equal Project.find_by_identifier('ecookbook'), assigns(:project)
318 assert_equal Project.find_by_identifier('ecookbook'), assigns(:project)
319
319
320 assert_select 'li', :text => /Development status/
320 assert_select 'li', :text => /Development status/
321 end
321 end
322
322
323 def test_show_should_not_display_hidden_custom_fields
323 def test_show_should_not_display_hidden_custom_fields
324 ProjectCustomField.find_by_name('Development status').update_attribute :visible, false
324 ProjectCustomField.find_by_name('Development status').update_attribute :visible, false
325 get :show, :id => 'ecookbook'
325 get :show, :id => 'ecookbook'
326 assert_response :success
326 assert_response :success
327 assert_template 'show'
327 assert_template 'show'
328 assert_not_nil assigns(:project)
328 assert_not_nil assigns(:project)
329
329
330 assert_select 'li', :text => /Development status/, :count => 0
330 assert_select 'li', :text => /Development status/, :count => 0
331 end
331 end
332
332
333 def test_show_should_not_fail_when_custom_values_are_nil
333 def test_show_should_not_fail_when_custom_values_are_nil
334 project = Project.find_by_identifier('ecookbook')
334 project = Project.find_by_identifier('ecookbook')
335 project.custom_values.first.update_attribute(:value, nil)
335 project.custom_values.first.update_attribute(:value, nil)
336 get :show, :id => 'ecookbook'
336 get :show, :id => 'ecookbook'
337 assert_response :success
337 assert_response :success
338 assert_template 'show'
338 assert_template 'show'
339 assert_not_nil assigns(:project)
339 assert_not_nil assigns(:project)
340 assert_equal Project.find_by_identifier('ecookbook'), assigns(:project)
340 assert_equal Project.find_by_identifier('ecookbook'), assigns(:project)
341 end
341 end
342
342
343 def show_archived_project_should_be_denied
343 def show_archived_project_should_be_denied
344 project = Project.find_by_identifier('ecookbook')
344 project = Project.find_by_identifier('ecookbook')
345 project.archive!
345 project.archive!
346
346
347 get :show, :id => 'ecookbook'
347 get :show, :id => 'ecookbook'
348 assert_response 403
348 assert_response 403
349 assert_nil assigns(:project)
349 assert_nil assigns(:project)
350 assert_select 'p', :text => /archived/
350 assert_select 'p', :text => /archived/
351 end
351 end
352
352
353 def test_show_should_not_show_private_subprojects_that_are_not_visible
353 def test_show_should_not_show_private_subprojects_that_are_not_visible
354 get :show, :id => 'ecookbook'
354 get :show, :id => 'ecookbook'
355 assert_response :success
355 assert_response :success
356 assert_template 'show'
356 assert_template 'show'
357 assert_select 'a', :text => /Private child/, :count => 0
357 assert_select 'a', :text => /Private child/, :count => 0
358 end
358 end
359
359
360 def test_show_should_show_private_subprojects_that_are_visible
360 def test_show_should_show_private_subprojects_that_are_visible
361 @request.session[:user_id] = 2 # manager who is a member of the private subproject
361 @request.session[:user_id] = 2 # manager who is a member of the private subproject
362 get :show, :id => 'ecookbook'
362 get :show, :id => 'ecookbook'
363 assert_response :success
363 assert_response :success
364 assert_template 'show'
364 assert_template 'show'
365 assert_select 'a', :text => /Private child/
365 assert_select 'a', :text => /Private child/
366 end
366 end
367
367
368 def test_settings
368 def test_settings
369 @request.session[:user_id] = 2 # manager
369 @request.session[:user_id] = 2 # manager
370 get :settings, :id => 1
370 get :settings, :id => 1
371 assert_response :success
371 assert_response :success
372 assert_template 'settings'
372 assert_template 'settings'
373 end
373 end
374
374
375 def test_settings_of_subproject
375 def test_settings_of_subproject
376 @request.session[:user_id] = 2
376 @request.session[:user_id] = 2
377 get :settings, :id => 'private-child'
377 get :settings, :id => 'private-child'
378 assert_response :success
378 assert_response :success
379 assert_template 'settings'
379 assert_template 'settings'
380
380
381 assert_select 'input[type=checkbox][name=?]', 'project[inherit_members]'
381 assert_select 'input[type=checkbox][name=?]', 'project[inherit_members]'
382 end
382 end
383
383
384 def test_settings_should_be_denied_for_member_on_closed_project
384 def test_settings_should_be_denied_for_member_on_closed_project
385 Project.find(1).close
385 Project.find(1).close
386 @request.session[:user_id] = 2 # manager
386 @request.session[:user_id] = 2 # manager
387
387
388 get :settings, :id => 1
388 get :settings, :id => 1
389 assert_response 403
389 assert_response 403
390 end
390 end
391
391
392 def test_settings_should_be_denied_for_anonymous_on_closed_project
392 def test_settings_should_be_denied_for_anonymous_on_closed_project
393 Project.find(1).close
393 Project.find(1).close
394
394
395 get :settings, :id => 1
395 get :settings, :id => 1
396 assert_response 302
396 assert_response 302
397 end
397 end
398
398
399 def test_update
399 def test_update
400 @request.session[:user_id] = 2 # manager
400 @request.session[:user_id] = 2 # manager
401 post :update, :id => 1, :project => {:name => 'Test changed name',
401 post :update, :id => 1, :project => {:name => 'Test changed name',
402 :issue_custom_field_ids => ['']}
402 :issue_custom_field_ids => ['']}
403 assert_redirected_to '/projects/ecookbook/settings'
403 assert_redirected_to '/projects/ecookbook/settings'
404 project = Project.find(1)
404 project = Project.find(1)
405 assert_equal 'Test changed name', project.name
405 assert_equal 'Test changed name', project.name
406 end
406 end
407
407
408 def test_update_with_failure
408 def test_update_with_failure
409 @request.session[:user_id] = 2 # manager
409 @request.session[:user_id] = 2 # manager
410 post :update, :id => 1, :project => {:name => ''}
410 post :update, :id => 1, :project => {:name => ''}
411 assert_response :success
411 assert_response :success
412 assert_template 'settings'
412 assert_template 'settings'
413 assert_error_tag :content => /name can&#x27;t be blank/i
413 assert_error_tag :content => /name can&#x27;t be blank/i
414 end
414 end
415
415
416 def test_update_should_be_denied_for_member_on_closed_project
416 def test_update_should_be_denied_for_member_on_closed_project
417 Project.find(1).close
417 Project.find(1).close
418 @request.session[:user_id] = 2 # manager
418 @request.session[:user_id] = 2 # manager
419
419
420 post :update, :id => 1, :project => {:name => 'Closed'}
420 post :update, :id => 1, :project => {:name => 'Closed'}
421 assert_response 403
421 assert_response 403
422 assert_equal 'eCookbook', Project.find(1).name
422 assert_equal 'eCookbook', Project.find(1).name
423 end
423 end
424
424
425 def test_update_should_be_denied_for_anonymous_on_closed_project
425 def test_update_should_be_denied_for_anonymous_on_closed_project
426 Project.find(1).close
426 Project.find(1).close
427
427
428 post :update, :id => 1, :project => {:name => 'Closed'}
428 post :update, :id => 1, :project => {:name => 'Closed'}
429 assert_response 302
429 assert_response 302
430 assert_equal 'eCookbook', Project.find(1).name
430 assert_equal 'eCookbook', Project.find(1).name
431 end
431 end
432
432
433 def test_modules
433 def test_modules
434 @request.session[:user_id] = 2
434 @request.session[:user_id] = 2
435 Project.find(1).enabled_module_names = ['issue_tracking', 'news']
435 Project.find(1).enabled_module_names = ['issue_tracking', 'news']
436
436
437 post :modules, :id => 1, :enabled_module_names => ['issue_tracking', 'repository', 'documents']
437 post :modules, :id => 1, :enabled_module_names => ['issue_tracking', 'repository', 'documents']
438 assert_redirected_to '/projects/ecookbook/settings/modules'
438 assert_redirected_to '/projects/ecookbook/settings/modules'
439 assert_equal ['documents', 'issue_tracking', 'repository'], Project.find(1).enabled_module_names.sort
439 assert_equal ['documents', 'issue_tracking', 'repository'], Project.find(1).enabled_module_names.sort
440 end
440 end
441
441
442 def test_destroy_leaf_project_without_confirmation_should_show_confirmation
442 def test_destroy_leaf_project_without_confirmation_should_show_confirmation
443 @request.session[:user_id] = 1 # admin
443 @request.session[:user_id] = 1 # admin
444
444
445 assert_no_difference 'Project.count' do
445 assert_no_difference 'Project.count' do
446 delete :destroy, :id => 2
446 delete :destroy, :id => 2
447 assert_response :success
447 assert_response :success
448 assert_template 'destroy'
448 assert_template 'destroy'
449 end
449 end
450 end
450 end
451
451
452 def test_destroy_without_confirmation_should_show_confirmation_with_subprojects
452 def test_destroy_without_confirmation_should_show_confirmation_with_subprojects
453 @request.session[:user_id] = 1 # admin
453 @request.session[:user_id] = 1 # admin
454
454
455 assert_no_difference 'Project.count' do
455 assert_no_difference 'Project.count' do
456 delete :destroy, :id => 1
456 delete :destroy, :id => 1
457 assert_response :success
457 assert_response :success
458 assert_template 'destroy'
458 assert_template 'destroy'
459 end
459 end
460 assert_select 'strong',
460 assert_select 'strong',
461 :text => ['Private child of eCookbook',
461 :text => ['Private child of eCookbook',
462 'Child of private child, eCookbook Subproject 1',
462 'Child of private child, eCookbook Subproject 1',
463 'eCookbook Subproject 2'].join(', ')
463 'eCookbook Subproject 2'].join(', ')
464 end
464 end
465
465
466 def test_destroy_with_confirmation_should_destroy_the_project_and_subprojects
466 def test_destroy_with_confirmation_should_destroy_the_project_and_subprojects
467 @request.session[:user_id] = 1 # admin
467 @request.session[:user_id] = 1 # admin
468
468
469 assert_difference 'Project.count', -5 do
469 assert_difference 'Project.count', -5 do
470 delete :destroy, :id => 1, :confirm => 1
470 delete :destroy, :id => 1, :confirm => 1
471 assert_redirected_to '/admin/projects'
471 assert_redirected_to '/admin/projects'
472 end
472 end
473 assert_nil Project.find_by_id(1)
473 assert_nil Project.find_by_id(1)
474 end
474 end
475
475
476 def test_archive
476 def test_archive
477 @request.session[:user_id] = 1 # admin
477 @request.session[:user_id] = 1 # admin
478 post :archive, :id => 1
478 post :archive, :id => 1
479 assert_redirected_to '/admin/projects'
479 assert_redirected_to '/admin/projects'
480 assert !Project.find(1).active?
480 assert !Project.find(1).active?
481 end
481 end
482
482
483 def test_archive_with_failure
483 def test_archive_with_failure
484 @request.session[:user_id] = 1
484 @request.session[:user_id] = 1
485 Project.any_instance.stubs(:archive).returns(false)
485 Project.any_instance.stubs(:archive).returns(false)
486 post :archive, :id => 1
486 post :archive, :id => 1
487 assert_redirected_to '/admin/projects'
487 assert_redirected_to '/admin/projects'
488 assert_match /project cannot be archived/i, flash[:error]
488 assert_match /project cannot be archived/i, flash[:error]
489 end
489 end
490
490
491 def test_unarchive
491 def test_unarchive
492 @request.session[:user_id] = 1 # admin
492 @request.session[:user_id] = 1 # admin
493 Project.find(1).archive
493 Project.find(1).archive
494 post :unarchive, :id => 1
494 post :unarchive, :id => 1
495 assert_redirected_to '/admin/projects'
495 assert_redirected_to '/admin/projects'
496 assert Project.find(1).active?
496 assert Project.find(1).active?
497 end
497 end
498
498
499 def test_close
499 def test_close
500 @request.session[:user_id] = 2
500 @request.session[:user_id] = 2
501 post :close, :id => 1
501 post :close, :id => 1
502 assert_redirected_to '/projects/ecookbook'
502 assert_redirected_to '/projects/ecookbook'
503 assert_equal Project::STATUS_CLOSED, Project.find(1).status
503 assert_equal Project::STATUS_CLOSED, Project.find(1).status
504 end
504 end
505
505
506 def test_reopen
506 def test_reopen
507 Project.find(1).close
507 Project.find(1).close
508 @request.session[:user_id] = 2
508 @request.session[:user_id] = 2
509 post :reopen, :id => 1
509 post :reopen, :id => 1
510 assert_redirected_to '/projects/ecookbook'
510 assert_redirected_to '/projects/ecookbook'
511 assert Project.find(1).active?
511 assert Project.find(1).active?
512 end
512 end
513
513
514 def test_project_breadcrumbs_should_be_limited_to_3_ancestors
514 def test_project_breadcrumbs_should_be_limited_to_3_ancestors
515 CustomField.delete_all
515 CustomField.delete_all
516 parent = nil
516 parent = nil
517 6.times do |i|
517 6.times do |i|
518 p = Project.generate_with_parent!(parent)
518 p = Project.generate_with_parent!(parent)
519 get :show, :id => p
519 get :show, :id => p
520 assert_select '#header h1' do
520 assert_select '#header h1' do
521 assert_select 'a', :count => [i, 3].min
521 assert_select 'a', :count => [i, 3].min
522 end
522 end
523
523
524 parent = p
524 parent = p
525 end
525 end
526 end
526 end
527
527
528 def test_get_copy
528 def test_get_copy
529 @request.session[:user_id] = 1 # admin
529 @request.session[:user_id] = 1 # admin
530 get :copy, :id => 1
530 get :copy, :id => 1
531 assert_response :success
531 assert_response :success
532 assert_template 'copy'
532 assert_template 'copy'
533 assert assigns(:project)
533 assert assigns(:project)
534 assert_equal Project.find(1).description, assigns(:project).description
534 assert_equal Project.find(1).description, assigns(:project).description
535 assert_nil assigns(:project).id
535 assert_nil assigns(:project).id
536
536
537 assert_select 'input[name=?][value=?]', 'project[enabled_module_names][]', 'issue_tracking', 1
537 assert_select 'input[name=?][value=?]', 'project[enabled_module_names][]', 'issue_tracking', 1
538 end
538 end
539
539
540 def test_get_copy_with_invalid_source_should_respond_with_404
540 def test_get_copy_with_invalid_source_should_respond_with_404
541 @request.session[:user_id] = 1
541 @request.session[:user_id] = 1
542 get :copy, :id => 99
542 get :copy, :id => 99
543 assert_response 404
543 assert_response 404
544 end
544 end
545
545
546 def test_post_copy_should_copy_requested_items
546 def test_post_copy_should_copy_requested_items
547 @request.session[:user_id] = 1 # admin
547 @request.session[:user_id] = 1 # admin
548 CustomField.delete_all
548 CustomField.delete_all
549
549
550 assert_difference 'Project.count' do
550 assert_difference 'Project.count' do
551 post :copy, :id => 1,
551 post :copy, :id => 1,
552 :project => {
552 :project => {
553 :name => 'Copy',
553 :name => 'Copy',
554 :identifier => 'unique-copy',
554 :identifier => 'unique-copy',
555 :tracker_ids => ['1', '2', '3', ''],
555 :tracker_ids => ['1', '2', '3', ''],
556 :enabled_module_names => %w(issue_tracking time_tracking)
556 :enabled_module_names => %w(issue_tracking time_tracking)
557 },
557 },
558 :only => %w(issues versions)
558 :only => %w(issues versions)
559 end
559 end
560 project = Project.find('unique-copy')
560 project = Project.find('unique-copy')
561 source = Project.find(1)
561 source = Project.find(1)
562 assert_equal %w(issue_tracking time_tracking), project.enabled_module_names.sort
562 assert_equal %w(issue_tracking time_tracking), project.enabled_module_names.sort
563
563
564 assert_equal source.versions.count, project.versions.count, "All versions were not copied"
564 assert_equal source.versions.count, project.versions.count, "All versions were not copied"
565 assert_equal source.issues.count, project.issues.count, "All issues were not copied"
565 assert_equal source.issues.count, project.issues.count, "All issues were not copied"
566 assert_equal 0, project.members.count
566 assert_equal 0, project.members.count
567 end
567 end
568
568
569 def test_post_copy_should_redirect_to_settings_when_successful
569 def test_post_copy_should_redirect_to_settings_when_successful
570 @request.session[:user_id] = 1 # admin
570 @request.session[:user_id] = 1 # admin
571 post :copy, :id => 1, :project => {:name => 'Copy', :identifier => 'unique-copy'}
571 post :copy, :id => 1, :project => {:name => 'Copy', :identifier => 'unique-copy'}
572 assert_response :redirect
572 assert_response :redirect
573 assert_redirected_to :controller => 'projects', :action => 'settings', :id => 'unique-copy'
573 assert_redirected_to :controller => 'projects', :action => 'settings', :id => 'unique-copy'
574 end
574 end
575
575
576 def test_jump_should_redirect_to_active_tab
576 def test_jump_should_redirect_to_active_tab
577 get :show, :id => 1, :jump => 'issues'
577 get :show, :id => 1, :jump => 'issues'
578 assert_redirected_to '/projects/ecookbook/issues'
578 assert_redirected_to '/projects/ecookbook/issues'
579 end
579 end
580
580
581 def test_jump_should_not_redirect_to_inactive_tab
581 def test_jump_should_not_redirect_to_inactive_tab
582 get :show, :id => 3, :jump => 'documents'
582 get :show, :id => 3, :jump => 'documents'
583 assert_response :success
583 assert_response :success
584 assert_template 'show'
584 assert_template 'show'
585 end
585 end
586
586
587 def test_jump_should_not_redirect_to_unknown_tab
587 def test_jump_should_not_redirect_to_unknown_tab
588 get :show, :id => 3, :jump => 'foobar'
588 get :show, :id => 3, :jump => 'foobar'
589 assert_response :success
589 assert_response :success
590 assert_template 'show'
590 assert_template 'show'
591 end
591 end
592 end
592 end
@@ -1,283 +1,283
1 # encoding: utf-8
1 # encoding: utf-8
2 #
2 #
3 # Redmine - project management software
3 # Redmine - project management software
4 # Copyright (C) 2006-2013 Jean-Philippe Lang
4 # Copyright (C) 2006-2013 Jean-Philippe Lang
5 #
5 #
6 # This program is free software; you can redistribute it and/or
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2
8 # as published by the Free Software Foundation; either version 2
9 # of the License, or (at your option) any later version.
9 # of the License, or (at your option) any later version.
10 #
10 #
11 # This program is distributed in the hope that it will be useful,
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
14 # GNU General Public License for more details.
15 #
15 #
16 # You should have received a copy of the GNU General Public License
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19
19
20 require File.expand_path('../../test_helper', __FILE__)
20 require File.expand_path('../../test_helper', __FILE__)
21
21
22 class AttachmentTest < ActiveSupport::TestCase
22 class AttachmentTest < ActiveSupport::TestCase
23 fixtures :users, :projects, :roles, :members, :member_roles,
23 fixtures :users, :projects, :roles, :members, :member_roles,
24 :enabled_modules, :issues, :trackers, :attachments
24 :enabled_modules, :issues, :trackers, :attachments
25
25
26 class MockFile
26 class MockFile
27 attr_reader :original_filename, :content_type, :content, :size
27 attr_reader :original_filename, :content_type, :content, :size
28
28
29 def initialize(attributes)
29 def initialize(attributes)
30 @original_filename = attributes[:original_filename]
30 @original_filename = attributes[:original_filename]
31 @content_type = attributes[:content_type]
31 @content_type = attributes[:content_type]
32 @content = attributes[:content] || "Content"
32 @content = attributes[:content] || "Content"
33 @size = content.size
33 @size = content.size
34 end
34 end
35 end
35 end
36
36
37 def setup
37 def setup
38 set_tmp_attachments_directory
38 set_tmp_attachments_directory
39 end
39 end
40
40
41 def test_container_for_new_attachment_should_be_nil
41 def test_container_for_new_attachment_should_be_nil
42 assert_nil Attachment.new.container
42 assert_nil Attachment.new.container
43 end
43 end
44
44
45 def test_create
45 def test_create
46 a = Attachment.new(:container => Issue.find(1),
46 a = Attachment.new(:container => Issue.find(1),
47 :file => uploaded_test_file("testfile.txt", "text/plain"),
47 :file => uploaded_test_file("testfile.txt", "text/plain"),
48 :author => User.find(1))
48 :author => User.find(1))
49 assert a.save
49 assert a.save
50 assert_equal 'testfile.txt', a.filename
50 assert_equal 'testfile.txt', a.filename
51 assert_equal 59, a.filesize
51 assert_equal 59, a.filesize
52 assert_equal 'text/plain', a.content_type
52 assert_equal 'text/plain', a.content_type
53 assert_equal 0, a.downloads
53 assert_equal 0, a.downloads
54 assert_equal '1478adae0d4eb06d35897518540e25d6', a.digest
54 assert_equal '1478adae0d4eb06d35897518540e25d6', a.digest
55
55
56 assert a.disk_directory
56 assert a.disk_directory
57 assert_match %r{\A\d{4}/\d{2}\z}, a.disk_directory
57 assert_match %r{\A\d{4}/\d{2}\z}, a.disk_directory
58
58
59 assert File.exist?(a.diskfile)
59 assert File.exist?(a.diskfile)
60 assert_equal 59, File.size(a.diskfile)
60 assert_equal 59, File.size(a.diskfile)
61 end
61 end
62
62
63 def test_copy_should_preserve_attributes
63 def test_copy_should_preserve_attributes
64 a = Attachment.find(1)
64 a = Attachment.find(1)
65 copy = a.copy
65 copy = a.copy
66
66
67 assert_save copy
67 assert_save copy
68 copy = Attachment.order('id DESC').first
68 copy = Attachment.order('id DESC').first
69 %w(filename filesize content_type author_id created_on description digest disk_filename disk_directory diskfile).each do |attribute|
69 %w(filename filesize content_type author_id created_on description digest disk_filename disk_directory diskfile).each do |attribute|
70 assert_equal a.send(attribute), copy.send(attribute), "#{attribute} was different"
70 assert_equal a.send(attribute), copy.send(attribute), "#{attribute} was different"
71 end
71 end
72 end
72 end
73
73
74 def test_size_should_be_validated_for_new_file
74 def test_size_should_be_validated_for_new_file
75 with_settings :attachment_max_size => 0 do
75 with_settings :attachment_max_size => 0 do
76 a = Attachment.new(:container => Issue.find(1),
76 a = Attachment.new(:container => Issue.find(1),
77 :file => uploaded_test_file("testfile.txt", "text/plain"),
77 :file => uploaded_test_file("testfile.txt", "text/plain"),
78 :author => User.find(1))
78 :author => User.find(1))
79 assert !a.save
79 assert !a.save
80 end
80 end
81 end
81 end
82
82
83 def test_size_should_not_be_validated_when_copying
83 def test_size_should_not_be_validated_when_copying
84 a = Attachment.create!(:container => Issue.find(1),
84 a = Attachment.create!(:container => Issue.find(1),
85 :file => uploaded_test_file("testfile.txt", "text/plain"),
85 :file => uploaded_test_file("testfile.txt", "text/plain"),
86 :author => User.find(1))
86 :author => User.find(1))
87 with_settings :attachment_max_size => 0 do
87 with_settings :attachment_max_size => 0 do
88 copy = a.copy
88 copy = a.copy
89 assert copy.save
89 assert copy.save
90 end
90 end
91 end
91 end
92
92
93 def test_description_length_should_be_validated
93 def test_description_length_should_be_validated
94 a = Attachment.new(:description => 'a' * 300)
94 a = Attachment.new(:description => 'a' * 300)
95 assert !a.save
95 assert !a.save
96 assert_not_nil a.errors[:description]
96 assert_not_equal [], a.errors[:description]
97 end
97 end
98
98
99 def test_destroy
99 def test_destroy
100 a = Attachment.new(:container => Issue.find(1),
100 a = Attachment.new(:container => Issue.find(1),
101 :file => uploaded_test_file("testfile.txt", "text/plain"),
101 :file => uploaded_test_file("testfile.txt", "text/plain"),
102 :author => User.find(1))
102 :author => User.find(1))
103 assert a.save
103 assert a.save
104 assert_equal 'testfile.txt', a.filename
104 assert_equal 'testfile.txt', a.filename
105 assert_equal 59, a.filesize
105 assert_equal 59, a.filesize
106 assert_equal 'text/plain', a.content_type
106 assert_equal 'text/plain', a.content_type
107 assert_equal 0, a.downloads
107 assert_equal 0, a.downloads
108 assert_equal '1478adae0d4eb06d35897518540e25d6', a.digest
108 assert_equal '1478adae0d4eb06d35897518540e25d6', a.digest
109 diskfile = a.diskfile
109 diskfile = a.diskfile
110 assert File.exist?(diskfile)
110 assert File.exist?(diskfile)
111 assert_equal 59, File.size(a.diskfile)
111 assert_equal 59, File.size(a.diskfile)
112 assert a.destroy
112 assert a.destroy
113 assert !File.exist?(diskfile)
113 assert !File.exist?(diskfile)
114 end
114 end
115
115
116 def test_destroy_should_not_delete_file_referenced_by_other_attachment
116 def test_destroy_should_not_delete_file_referenced_by_other_attachment
117 a = Attachment.create!(:container => Issue.find(1),
117 a = Attachment.create!(:container => Issue.find(1),
118 :file => uploaded_test_file("testfile.txt", "text/plain"),
118 :file => uploaded_test_file("testfile.txt", "text/plain"),
119 :author => User.find(1))
119 :author => User.find(1))
120 diskfile = a.diskfile
120 diskfile = a.diskfile
121
121
122 copy = a.copy
122 copy = a.copy
123 copy.save!
123 copy.save!
124
124
125 assert File.exists?(diskfile)
125 assert File.exists?(diskfile)
126 a.destroy
126 a.destroy
127 assert File.exists?(diskfile)
127 assert File.exists?(diskfile)
128 copy.destroy
128 copy.destroy
129 assert !File.exists?(diskfile)
129 assert !File.exists?(diskfile)
130 end
130 end
131
131
132 def test_create_should_auto_assign_content_type
132 def test_create_should_auto_assign_content_type
133 a = Attachment.new(:container => Issue.find(1),
133 a = Attachment.new(:container => Issue.find(1),
134 :file => uploaded_test_file("testfile.txt", ""),
134 :file => uploaded_test_file("testfile.txt", ""),
135 :author => User.find(1))
135 :author => User.find(1))
136 assert a.save
136 assert a.save
137 assert_equal 'text/plain', a.content_type
137 assert_equal 'text/plain', a.content_type
138 end
138 end
139
139
140 def test_identical_attachments_at_the_same_time_should_not_overwrite
140 def test_identical_attachments_at_the_same_time_should_not_overwrite
141 a1 = Attachment.create!(:container => Issue.find(1),
141 a1 = Attachment.create!(:container => Issue.find(1),
142 :file => uploaded_test_file("testfile.txt", ""),
142 :file => uploaded_test_file("testfile.txt", ""),
143 :author => User.find(1))
143 :author => User.find(1))
144 a2 = Attachment.create!(:container => Issue.find(1),
144 a2 = Attachment.create!(:container => Issue.find(1),
145 :file => uploaded_test_file("testfile.txt", ""),
145 :file => uploaded_test_file("testfile.txt", ""),
146 :author => User.find(1))
146 :author => User.find(1))
147 assert a1.disk_filename != a2.disk_filename
147 assert a1.disk_filename != a2.disk_filename
148 end
148 end
149
149
150 def test_filename_should_be_basenamed
150 def test_filename_should_be_basenamed
151 a = Attachment.new(:file => MockFile.new(:original_filename => "path/to/the/file"))
151 a = Attachment.new(:file => MockFile.new(:original_filename => "path/to/the/file"))
152 assert_equal 'file', a.filename
152 assert_equal 'file', a.filename
153 end
153 end
154
154
155 def test_filename_should_be_sanitized
155 def test_filename_should_be_sanitized
156 a = Attachment.new(:file => MockFile.new(:original_filename => "valid:[] invalid:?%*|\"'<>chars"))
156 a = Attachment.new(:file => MockFile.new(:original_filename => "valid:[] invalid:?%*|\"'<>chars"))
157 assert_equal 'valid_[] invalid_chars', a.filename
157 assert_equal 'valid_[] invalid_chars', a.filename
158 end
158 end
159
159
160 def test_diskfilename
160 def test_diskfilename
161 assert Attachment.disk_filename("test_file.txt") =~ /^\d{12}_test_file.txt$/
161 assert Attachment.disk_filename("test_file.txt") =~ /^\d{12}_test_file.txt$/
162 assert_equal 'test_file.txt', Attachment.disk_filename("test_file.txt")[13..-1]
162 assert_equal 'test_file.txt', Attachment.disk_filename("test_file.txt")[13..-1]
163 assert_equal '770c509475505f37c2b8fb6030434d6b.txt', Attachment.disk_filename("test_accentuΓ©.txt")[13..-1]
163 assert_equal '770c509475505f37c2b8fb6030434d6b.txt', Attachment.disk_filename("test_accentuΓ©.txt")[13..-1]
164 assert_equal 'f8139524ebb8f32e51976982cd20a85d', Attachment.disk_filename("test_accentuΓ©")[13..-1]
164 assert_equal 'f8139524ebb8f32e51976982cd20a85d', Attachment.disk_filename("test_accentuΓ©")[13..-1]
165 assert_equal 'cbb5b0f30978ba03731d61f9f6d10011', Attachment.disk_filename("test_accentuΓ©.Γ§a")[13..-1]
165 assert_equal 'cbb5b0f30978ba03731d61f9f6d10011', Attachment.disk_filename("test_accentuΓ©.Γ§a")[13..-1]
166 end
166 end
167
167
168 def test_title
168 def test_title
169 a = Attachment.new(:filename => "test.png")
169 a = Attachment.new(:filename => "test.png")
170 assert_equal "test.png", a.title
170 assert_equal "test.png", a.title
171
171
172 a = Attachment.new(:filename => "test.png", :description => "Cool image")
172 a = Attachment.new(:filename => "test.png", :description => "Cool image")
173 assert_equal "test.png (Cool image)", a.title
173 assert_equal "test.png (Cool image)", a.title
174 end
174 end
175
175
176 def test_prune_should_destroy_old_unattached_attachments
176 def test_prune_should_destroy_old_unattached_attachments
177 Attachment.create!(:file => uploaded_test_file("testfile.txt", ""), :author_id => 1, :created_on => 2.days.ago)
177 Attachment.create!(:file => uploaded_test_file("testfile.txt", ""), :author_id => 1, :created_on => 2.days.ago)
178 Attachment.create!(:file => uploaded_test_file("testfile.txt", ""), :author_id => 1, :created_on => 2.days.ago)
178 Attachment.create!(:file => uploaded_test_file("testfile.txt", ""), :author_id => 1, :created_on => 2.days.ago)
179 Attachment.create!(:file => uploaded_test_file("testfile.txt", ""), :author_id => 1)
179 Attachment.create!(:file => uploaded_test_file("testfile.txt", ""), :author_id => 1)
180
180
181 assert_difference 'Attachment.count', -2 do
181 assert_difference 'Attachment.count', -2 do
182 Attachment.prune
182 Attachment.prune
183 end
183 end
184 end
184 end
185
185
186 def test_move_from_root_to_target_directory_should_move_root_files
186 def test_move_from_root_to_target_directory_should_move_root_files
187 a = Attachment.find(20)
187 a = Attachment.find(20)
188 assert a.disk_directory.blank?
188 assert a.disk_directory.blank?
189 # Create a real file for this fixture
189 # Create a real file for this fixture
190 File.open(a.diskfile, "w") do |f|
190 File.open(a.diskfile, "w") do |f|
191 f.write "test file at the root of files directory"
191 f.write "test file at the root of files directory"
192 end
192 end
193 assert a.readable?
193 assert a.readable?
194 Attachment.move_from_root_to_target_directory
194 Attachment.move_from_root_to_target_directory
195
195
196 a.reload
196 a.reload
197 assert_equal '2012/05', a.disk_directory
197 assert_equal '2012/05', a.disk_directory
198 assert a.readable?
198 assert a.readable?
199 end
199 end
200
200
201 test "Attachmnet.attach_files should attach the file" do
201 test "Attachmnet.attach_files should attach the file" do
202 issue = Issue.first
202 issue = Issue.first
203 assert_difference 'Attachment.count' do
203 assert_difference 'Attachment.count' do
204 Attachment.attach_files(issue,
204 Attachment.attach_files(issue,
205 '1' => {
205 '1' => {
206 'file' => uploaded_test_file('testfile.txt', 'text/plain'),
206 'file' => uploaded_test_file('testfile.txt', 'text/plain'),
207 'description' => 'test'
207 'description' => 'test'
208 })
208 })
209 end
209 end
210
210
211 attachment = Attachment.first(:order => 'id DESC')
211 attachment = Attachment.first(:order => 'id DESC')
212 assert_equal issue, attachment.container
212 assert_equal issue, attachment.container
213 assert_equal 'testfile.txt', attachment.filename
213 assert_equal 'testfile.txt', attachment.filename
214 assert_equal 59, attachment.filesize
214 assert_equal 59, attachment.filesize
215 assert_equal 'test', attachment.description
215 assert_equal 'test', attachment.description
216 assert_equal 'text/plain', attachment.content_type
216 assert_equal 'text/plain', attachment.content_type
217 assert File.exists?(attachment.diskfile)
217 assert File.exists?(attachment.diskfile)
218 assert_equal 59, File.size(attachment.diskfile)
218 assert_equal 59, File.size(attachment.diskfile)
219 end
219 end
220
220
221 test "Attachmnet.attach_files should add unsaved files to the object as unsaved attachments" do
221 test "Attachmnet.attach_files should add unsaved files to the object as unsaved attachments" do
222 # Max size of 0 to force Attachment creation failures
222 # Max size of 0 to force Attachment creation failures
223 with_settings(:attachment_max_size => 0) do
223 with_settings(:attachment_max_size => 0) do
224 @project = Project.find(1)
224 @project = Project.find(1)
225 response = Attachment.attach_files(@project, {
225 response = Attachment.attach_files(@project, {
226 '1' => {'file' => mock_file, 'description' => 'test'},
226 '1' => {'file' => mock_file, 'description' => 'test'},
227 '2' => {'file' => mock_file, 'description' => 'test'}
227 '2' => {'file' => mock_file, 'description' => 'test'}
228 })
228 })
229
229
230 assert response[:unsaved].present?
230 assert response[:unsaved].present?
231 assert_equal 2, response[:unsaved].length
231 assert_equal 2, response[:unsaved].length
232 assert response[:unsaved].first.new_record?
232 assert response[:unsaved].first.new_record?
233 assert response[:unsaved].second.new_record?
233 assert response[:unsaved].second.new_record?
234 assert_equal response[:unsaved], @project.unsaved_attachments
234 assert_equal response[:unsaved], @project.unsaved_attachments
235 end
235 end
236 end
236 end
237
237
238 def test_latest_attach
238 def test_latest_attach
239 set_fixtures_attachments_directory
239 set_fixtures_attachments_directory
240 a1 = Attachment.find(16)
240 a1 = Attachment.find(16)
241 assert_equal "testfile.png", a1.filename
241 assert_equal "testfile.png", a1.filename
242 assert a1.readable?
242 assert a1.readable?
243 assert (! a1.visible?(User.anonymous))
243 assert (! a1.visible?(User.anonymous))
244 assert a1.visible?(User.find(2))
244 assert a1.visible?(User.find(2))
245 a2 = Attachment.find(17)
245 a2 = Attachment.find(17)
246 assert_equal "testfile.PNG", a2.filename
246 assert_equal "testfile.PNG", a2.filename
247 assert a2.readable?
247 assert a2.readable?
248 assert (! a2.visible?(User.anonymous))
248 assert (! a2.visible?(User.anonymous))
249 assert a2.visible?(User.find(2))
249 assert a2.visible?(User.find(2))
250 assert a1.created_on < a2.created_on
250 assert a1.created_on < a2.created_on
251
251
252 la1 = Attachment.latest_attach([a1, a2], "testfile.png")
252 la1 = Attachment.latest_attach([a1, a2], "testfile.png")
253 assert_equal 17, la1.id
253 assert_equal 17, la1.id
254 la2 = Attachment.latest_attach([a1, a2], "Testfile.PNG")
254 la2 = Attachment.latest_attach([a1, a2], "Testfile.PNG")
255 assert_equal 17, la2.id
255 assert_equal 17, la2.id
256
256
257 set_tmp_attachments_directory
257 set_tmp_attachments_directory
258 end
258 end
259
259
260 def test_thumbnailable_should_be_true_for_images
260 def test_thumbnailable_should_be_true_for_images
261 assert_equal true, Attachment.new(:filename => 'test.jpg').thumbnailable?
261 assert_equal true, Attachment.new(:filename => 'test.jpg').thumbnailable?
262 end
262 end
263
263
264 def test_thumbnailable_should_be_true_for_non_images
264 def test_thumbnailable_should_be_true_for_non_images
265 assert_equal false, Attachment.new(:filename => 'test.txt').thumbnailable?
265 assert_equal false, Attachment.new(:filename => 'test.txt').thumbnailable?
266 end
266 end
267
267
268 if convert_installed?
268 if convert_installed?
269 def test_thumbnail_should_generate_the_thumbnail
269 def test_thumbnail_should_generate_the_thumbnail
270 set_fixtures_attachments_directory
270 set_fixtures_attachments_directory
271 attachment = Attachment.find(16)
271 attachment = Attachment.find(16)
272 Attachment.clear_thumbnails
272 Attachment.clear_thumbnails
273
273
274 assert_difference "Dir.glob(File.join(Attachment.thumbnails_storage_path, '*.thumb')).size" do
274 assert_difference "Dir.glob(File.join(Attachment.thumbnails_storage_path, '*.thumb')).size" do
275 thumbnail = attachment.thumbnail
275 thumbnail = attachment.thumbnail
276 assert_equal "16_8e0294de2441577c529f170b6fb8f638_100.thumb", File.basename(thumbnail)
276 assert_equal "16_8e0294de2441577c529f170b6fb8f638_100.thumb", File.basename(thumbnail)
277 assert File.exists?(thumbnail)
277 assert File.exists?(thumbnail)
278 end
278 end
279 end
279 end
280 else
280 else
281 puts '(ImageMagick convert not available)'
281 puts '(ImageMagick convert not available)'
282 end
282 end
283 end
283 end
@@ -1,358 +1,358
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2013 Jean-Philippe Lang
2 # Copyright (C) 2006-2013 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 IssueNestedSetTest < ActiveSupport::TestCase
20 class IssueNestedSetTest < ActiveSupport::TestCase
21 fixtures :projects, :users, :roles,
21 fixtures :projects, :users, :roles,
22 :trackers, :projects_trackers,
22 :trackers, :projects_trackers,
23 :issue_statuses, :issue_categories, :issue_relations,
23 :issue_statuses, :issue_categories, :issue_relations,
24 :enumerations,
24 :enumerations,
25 :issues
25 :issues
26
26
27 def test_create_root_issue
27 def test_create_root_issue
28 issue1 = Issue.generate!
28 issue1 = Issue.generate!
29 issue2 = Issue.generate!
29 issue2 = Issue.generate!
30 issue1.reload
30 issue1.reload
31 issue2.reload
31 issue2.reload
32
32
33 assert_equal [issue1.id, nil, 1, 2], [issue1.root_id, issue1.parent_id, issue1.lft, issue1.rgt]
33 assert_equal [issue1.id, nil, 1, 2], [issue1.root_id, issue1.parent_id, issue1.lft, issue1.rgt]
34 assert_equal [issue2.id, nil, 1, 2], [issue2.root_id, issue2.parent_id, issue2.lft, issue2.rgt]
34 assert_equal [issue2.id, nil, 1, 2], [issue2.root_id, issue2.parent_id, issue2.lft, issue2.rgt]
35 end
35 end
36
36
37 def test_create_child_issue
37 def test_create_child_issue
38 parent = Issue.generate!
38 parent = Issue.generate!
39 child = Issue.generate!(:parent_issue_id => parent.id)
39 child = Issue.generate!(:parent_issue_id => parent.id)
40 parent.reload
40 parent.reload
41 child.reload
41 child.reload
42
42
43 assert_equal [parent.id, nil, 1, 4], [parent.root_id, parent.parent_id, parent.lft, parent.rgt]
43 assert_equal [parent.id, nil, 1, 4], [parent.root_id, parent.parent_id, parent.lft, parent.rgt]
44 assert_equal [parent.id, parent.id, 2, 3], [child.root_id, child.parent_id, child.lft, child.rgt]
44 assert_equal [parent.id, parent.id, 2, 3], [child.root_id, child.parent_id, child.lft, child.rgt]
45 end
45 end
46
46
47 def test_creating_a_child_in_a_subproject_should_validate
47 def test_creating_a_child_in_a_subproject_should_validate
48 issue = Issue.generate!
48 issue = Issue.generate!
49 child = Issue.new(:project_id => 3, :tracker_id => 2, :author_id => 1,
49 child = Issue.new(:project_id => 3, :tracker_id => 2, :author_id => 1,
50 :subject => 'child', :parent_issue_id => issue.id)
50 :subject => 'child', :parent_issue_id => issue.id)
51 assert_save child
51 assert_save child
52 assert_equal issue, child.reload.parent
52 assert_equal issue, child.reload.parent
53 end
53 end
54
54
55 def test_creating_a_child_in_an_invalid_project_should_not_validate
55 def test_creating_a_child_in_an_invalid_project_should_not_validate
56 issue = Issue.generate!
56 issue = Issue.generate!
57 child = Issue.new(:project_id => 2, :tracker_id => 1, :author_id => 1,
57 child = Issue.new(:project_id => 2, :tracker_id => 1, :author_id => 1,
58 :subject => 'child', :parent_issue_id => issue.id)
58 :subject => 'child', :parent_issue_id => issue.id)
59 assert !child.save
59 assert !child.save
60 assert_not_nil child.errors[:parent_issue_id]
60 assert_not_equal [], child.errors[:parent_issue_id]
61 end
61 end
62
62
63 def test_move_a_root_to_child
63 def test_move_a_root_to_child
64 parent1 = Issue.generate!
64 parent1 = Issue.generate!
65 parent2 = Issue.generate!
65 parent2 = Issue.generate!
66 child = Issue.generate!(:parent_issue_id => parent1.id)
66 child = Issue.generate!(:parent_issue_id => parent1.id)
67
67
68 parent2.parent_issue_id = parent1.id
68 parent2.parent_issue_id = parent1.id
69 parent2.save!
69 parent2.save!
70 child.reload
70 child.reload
71 parent1.reload
71 parent1.reload
72 parent2.reload
72 parent2.reload
73
73
74 assert_equal [parent1.id, 1, 6], [parent1.root_id, parent1.lft, parent1.rgt]
74 assert_equal [parent1.id, 1, 6], [parent1.root_id, parent1.lft, parent1.rgt]
75 assert_equal [parent1.id, 4, 5], [parent2.root_id, parent2.lft, parent2.rgt]
75 assert_equal [parent1.id, 4, 5], [parent2.root_id, parent2.lft, parent2.rgt]
76 assert_equal [parent1.id, 2, 3], [child.root_id, child.lft, child.rgt]
76 assert_equal [parent1.id, 2, 3], [child.root_id, child.lft, child.rgt]
77 end
77 end
78
78
79 def test_move_a_child_to_root
79 def test_move_a_child_to_root
80 parent1 = Issue.generate!
80 parent1 = Issue.generate!
81 parent2 = Issue.generate!
81 parent2 = Issue.generate!
82 child = Issue.generate!(:parent_issue_id => parent1.id)
82 child = Issue.generate!(:parent_issue_id => parent1.id)
83
83
84 child.parent_issue_id = nil
84 child.parent_issue_id = nil
85 child.save!
85 child.save!
86 child.reload
86 child.reload
87 parent1.reload
87 parent1.reload
88 parent2.reload
88 parent2.reload
89
89
90 assert_equal [parent1.id, 1, 2], [parent1.root_id, parent1.lft, parent1.rgt]
90 assert_equal [parent1.id, 1, 2], [parent1.root_id, parent1.lft, parent1.rgt]
91 assert_equal [parent2.id, 1, 2], [parent2.root_id, parent2.lft, parent2.rgt]
91 assert_equal [parent2.id, 1, 2], [parent2.root_id, parent2.lft, parent2.rgt]
92 assert_equal [child.id, 1, 2], [child.root_id, child.lft, child.rgt]
92 assert_equal [child.id, 1, 2], [child.root_id, child.lft, child.rgt]
93 end
93 end
94
94
95 def test_move_a_child_to_another_issue
95 def test_move_a_child_to_another_issue
96 parent1 = Issue.generate!
96 parent1 = Issue.generate!
97 parent2 = Issue.generate!
97 parent2 = Issue.generate!
98 child = Issue.generate!(:parent_issue_id => parent1.id)
98 child = Issue.generate!(:parent_issue_id => parent1.id)
99
99
100 child.parent_issue_id = parent2.id
100 child.parent_issue_id = parent2.id
101 child.save!
101 child.save!
102 child.reload
102 child.reload
103 parent1.reload
103 parent1.reload
104 parent2.reload
104 parent2.reload
105
105
106 assert_equal [parent1.id, 1, 2], [parent1.root_id, parent1.lft, parent1.rgt]
106 assert_equal [parent1.id, 1, 2], [parent1.root_id, parent1.lft, parent1.rgt]
107 assert_equal [parent2.id, 1, 4], [parent2.root_id, parent2.lft, parent2.rgt]
107 assert_equal [parent2.id, 1, 4], [parent2.root_id, parent2.lft, parent2.rgt]
108 assert_equal [parent2.id, 2, 3], [child.root_id, child.lft, child.rgt]
108 assert_equal [parent2.id, 2, 3], [child.root_id, child.lft, child.rgt]
109 end
109 end
110
110
111 def test_move_a_child_with_descendants_to_another_issue
111 def test_move_a_child_with_descendants_to_another_issue
112 parent1 = Issue.generate!
112 parent1 = Issue.generate!
113 parent2 = Issue.generate!
113 parent2 = Issue.generate!
114 child = Issue.generate!(:parent_issue_id => parent1.id)
114 child = Issue.generate!(:parent_issue_id => parent1.id)
115 grandchild = Issue.generate!(:parent_issue_id => child.id)
115 grandchild = Issue.generate!(:parent_issue_id => child.id)
116
116
117 parent1.reload
117 parent1.reload
118 parent2.reload
118 parent2.reload
119 child.reload
119 child.reload
120 grandchild.reload
120 grandchild.reload
121
121
122 assert_equal [parent1.id, 1, 6], [parent1.root_id, parent1.lft, parent1.rgt]
122 assert_equal [parent1.id, 1, 6], [parent1.root_id, parent1.lft, parent1.rgt]
123 assert_equal [parent2.id, 1, 2], [parent2.root_id, parent2.lft, parent2.rgt]
123 assert_equal [parent2.id, 1, 2], [parent2.root_id, parent2.lft, parent2.rgt]
124 assert_equal [parent1.id, 2, 5], [child.root_id, child.lft, child.rgt]
124 assert_equal [parent1.id, 2, 5], [child.root_id, child.lft, child.rgt]
125 assert_equal [parent1.id, 3, 4], [grandchild.root_id, grandchild.lft, grandchild.rgt]
125 assert_equal [parent1.id, 3, 4], [grandchild.root_id, grandchild.lft, grandchild.rgt]
126
126
127 child.reload.parent_issue_id = parent2.id
127 child.reload.parent_issue_id = parent2.id
128 child.save!
128 child.save!
129 child.reload
129 child.reload
130 grandchild.reload
130 grandchild.reload
131 parent1.reload
131 parent1.reload
132 parent2.reload
132 parent2.reload
133
133
134 assert_equal [parent1.id, 1, 2], [parent1.root_id, parent1.lft, parent1.rgt]
134 assert_equal [parent1.id, 1, 2], [parent1.root_id, parent1.lft, parent1.rgt]
135 assert_equal [parent2.id, 1, 6], [parent2.root_id, parent2.lft, parent2.rgt]
135 assert_equal [parent2.id, 1, 6], [parent2.root_id, parent2.lft, parent2.rgt]
136 assert_equal [parent2.id, 2, 5], [child.root_id, child.lft, child.rgt]
136 assert_equal [parent2.id, 2, 5], [child.root_id, child.lft, child.rgt]
137 assert_equal [parent2.id, 3, 4], [grandchild.root_id, grandchild.lft, grandchild.rgt]
137 assert_equal [parent2.id, 3, 4], [grandchild.root_id, grandchild.lft, grandchild.rgt]
138 end
138 end
139
139
140 def test_move_a_child_with_descendants_to_another_project
140 def test_move_a_child_with_descendants_to_another_project
141 parent1 = Issue.generate!
141 parent1 = Issue.generate!
142 child = Issue.generate!(:parent_issue_id => parent1.id)
142 child = Issue.generate!(:parent_issue_id => parent1.id)
143 grandchild = Issue.generate!(:parent_issue_id => child.id)
143 grandchild = Issue.generate!(:parent_issue_id => child.id)
144
144
145 child.reload
145 child.reload
146 child.project = Project.find(2)
146 child.project = Project.find(2)
147 assert child.save
147 assert child.save
148 child.reload
148 child.reload
149 grandchild.reload
149 grandchild.reload
150 parent1.reload
150 parent1.reload
151
151
152 assert_equal [1, parent1.id, 1, 2], [parent1.project_id, parent1.root_id, parent1.lft, parent1.rgt]
152 assert_equal [1, parent1.id, 1, 2], [parent1.project_id, parent1.root_id, parent1.lft, parent1.rgt]
153 assert_equal [2, child.id, 1, 4], [child.project_id, child.root_id, child.lft, child.rgt]
153 assert_equal [2, child.id, 1, 4], [child.project_id, child.root_id, child.lft, child.rgt]
154 assert_equal [2, child.id, 2, 3], [grandchild.project_id, grandchild.root_id, grandchild.lft, grandchild.rgt]
154 assert_equal [2, child.id, 2, 3], [grandchild.project_id, grandchild.root_id, grandchild.lft, grandchild.rgt]
155 end
155 end
156
156
157 def test_moving_an_issue_to_a_descendant_should_not_validate
157 def test_moving_an_issue_to_a_descendant_should_not_validate
158 parent1 = Issue.generate!
158 parent1 = Issue.generate!
159 parent2 = Issue.generate!
159 parent2 = Issue.generate!
160 child = Issue.generate!(:parent_issue_id => parent1.id)
160 child = Issue.generate!(:parent_issue_id => parent1.id)
161 grandchild = Issue.generate!(:parent_issue_id => child.id)
161 grandchild = Issue.generate!(:parent_issue_id => child.id)
162
162
163 child.reload
163 child.reload
164 child.parent_issue_id = grandchild.id
164 child.parent_issue_id = grandchild.id
165 assert !child.save
165 assert !child.save
166 assert_not_nil child.errors[:parent_issue_id]
166 assert_not_equal [], child.errors[:parent_issue_id]
167 end
167 end
168
168
169 def test_destroy_should_destroy_children
169 def test_destroy_should_destroy_children
170 issue1 = Issue.generate!
170 issue1 = Issue.generate!
171 issue2 = Issue.generate!
171 issue2 = Issue.generate!
172 issue3 = Issue.generate!(:parent_issue_id => issue2.id)
172 issue3 = Issue.generate!(:parent_issue_id => issue2.id)
173 issue4 = Issue.generate!(:parent_issue_id => issue1.id)
173 issue4 = Issue.generate!(:parent_issue_id => issue1.id)
174
174
175 issue3.init_journal(User.find(2))
175 issue3.init_journal(User.find(2))
176 issue3.subject = 'child with journal'
176 issue3.subject = 'child with journal'
177 issue3.save!
177 issue3.save!
178
178
179 assert_difference 'Issue.count', -2 do
179 assert_difference 'Issue.count', -2 do
180 assert_difference 'Journal.count', -1 do
180 assert_difference 'Journal.count', -1 do
181 assert_difference 'JournalDetail.count', -1 do
181 assert_difference 'JournalDetail.count', -1 do
182 Issue.find(issue2.id).destroy
182 Issue.find(issue2.id).destroy
183 end
183 end
184 end
184 end
185 end
185 end
186
186
187 issue1.reload
187 issue1.reload
188 issue4.reload
188 issue4.reload
189 assert !Issue.exists?(issue2.id)
189 assert !Issue.exists?(issue2.id)
190 assert !Issue.exists?(issue3.id)
190 assert !Issue.exists?(issue3.id)
191 assert_equal [issue1.id, 1, 4], [issue1.root_id, issue1.lft, issue1.rgt]
191 assert_equal [issue1.id, 1, 4], [issue1.root_id, issue1.lft, issue1.rgt]
192 assert_equal [issue1.id, 2, 3], [issue4.root_id, issue4.lft, issue4.rgt]
192 assert_equal [issue1.id, 2, 3], [issue4.root_id, issue4.lft, issue4.rgt]
193 end
193 end
194
194
195 def test_destroy_child_should_update_parent
195 def test_destroy_child_should_update_parent
196 issue = Issue.generate!
196 issue = Issue.generate!
197 child1 = Issue.generate!(:parent_issue_id => issue.id)
197 child1 = Issue.generate!(:parent_issue_id => issue.id)
198 child2 = Issue.generate!(:parent_issue_id => issue.id)
198 child2 = Issue.generate!(:parent_issue_id => issue.id)
199
199
200 issue.reload
200 issue.reload
201 assert_equal [issue.id, 1, 6], [issue.root_id, issue.lft, issue.rgt]
201 assert_equal [issue.id, 1, 6], [issue.root_id, issue.lft, issue.rgt]
202
202
203 child2.reload.destroy
203 child2.reload.destroy
204
204
205 issue.reload
205 issue.reload
206 assert_equal [issue.id, 1, 4], [issue.root_id, issue.lft, issue.rgt]
206 assert_equal [issue.id, 1, 4], [issue.root_id, issue.lft, issue.rgt]
207 end
207 end
208
208
209 def test_destroy_parent_issue_updated_during_children_destroy
209 def test_destroy_parent_issue_updated_during_children_destroy
210 parent = Issue.generate!
210 parent = Issue.generate!
211 Issue.generate!(:start_date => Date.today, :parent_issue_id => parent.id)
211 Issue.generate!(:start_date => Date.today, :parent_issue_id => parent.id)
212 Issue.generate!(:start_date => 2.days.from_now, :parent_issue_id => parent.id)
212 Issue.generate!(:start_date => 2.days.from_now, :parent_issue_id => parent.id)
213
213
214 assert_difference 'Issue.count', -3 do
214 assert_difference 'Issue.count', -3 do
215 Issue.find(parent.id).destroy
215 Issue.find(parent.id).destroy
216 end
216 end
217 end
217 end
218
218
219 def test_destroy_child_issue_with_children
219 def test_destroy_child_issue_with_children
220 root = Issue.create!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'root')
220 root = Issue.create!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'root')
221 child = Issue.create!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'child', :parent_issue_id => root.id)
221 child = Issue.create!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'child', :parent_issue_id => root.id)
222 leaf = Issue.create!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'leaf', :parent_issue_id => child.id)
222 leaf = Issue.create!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'leaf', :parent_issue_id => child.id)
223 leaf.init_journal(User.find(2))
223 leaf.init_journal(User.find(2))
224 leaf.subject = 'leaf with journal'
224 leaf.subject = 'leaf with journal'
225 leaf.save!
225 leaf.save!
226
226
227 assert_difference 'Issue.count', -2 do
227 assert_difference 'Issue.count', -2 do
228 assert_difference 'Journal.count', -1 do
228 assert_difference 'Journal.count', -1 do
229 assert_difference 'JournalDetail.count', -1 do
229 assert_difference 'JournalDetail.count', -1 do
230 Issue.find(child.id).destroy
230 Issue.find(child.id).destroy
231 end
231 end
232 end
232 end
233 end
233 end
234
234
235 root = Issue.find(root.id)
235 root = Issue.find(root.id)
236 assert root.leaf?, "Root issue is not a leaf (lft: #{root.lft}, rgt: #{root.rgt})"
236 assert root.leaf?, "Root issue is not a leaf (lft: #{root.lft}, rgt: #{root.rgt})"
237 end
237 end
238
238
239 def test_destroy_issue_with_grand_child
239 def test_destroy_issue_with_grand_child
240 parent = Issue.generate!
240 parent = Issue.generate!
241 issue = Issue.generate!(:parent_issue_id => parent.id)
241 issue = Issue.generate!(:parent_issue_id => parent.id)
242 child = Issue.generate!(:parent_issue_id => issue.id)
242 child = Issue.generate!(:parent_issue_id => issue.id)
243 grandchild1 = Issue.generate!(:parent_issue_id => child.id)
243 grandchild1 = Issue.generate!(:parent_issue_id => child.id)
244 grandchild2 = Issue.generate!(:parent_issue_id => child.id)
244 grandchild2 = Issue.generate!(:parent_issue_id => child.id)
245
245
246 assert_difference 'Issue.count', -4 do
246 assert_difference 'Issue.count', -4 do
247 Issue.find(issue.id).destroy
247 Issue.find(issue.id).destroy
248 parent.reload
248 parent.reload
249 assert_equal [1, 2], [parent.lft, parent.rgt]
249 assert_equal [1, 2], [parent.lft, parent.rgt]
250 end
250 end
251 end
251 end
252
252
253 def test_parent_priority_should_be_the_highest_child_priority
253 def test_parent_priority_should_be_the_highest_child_priority
254 parent = Issue.generate!(:priority => IssuePriority.find_by_name('Normal'))
254 parent = Issue.generate!(:priority => IssuePriority.find_by_name('Normal'))
255 # Create children
255 # Create children
256 child1 = Issue.generate!(:priority => IssuePriority.find_by_name('High'), :parent_issue_id => parent.id)
256 child1 = Issue.generate!(:priority => IssuePriority.find_by_name('High'), :parent_issue_id => parent.id)
257 assert_equal 'High', parent.reload.priority.name
257 assert_equal 'High', parent.reload.priority.name
258 child2 = Issue.generate!(:priority => IssuePriority.find_by_name('Immediate'), :parent_issue_id => child1.id)
258 child2 = Issue.generate!(:priority => IssuePriority.find_by_name('Immediate'), :parent_issue_id => child1.id)
259 assert_equal 'Immediate', child1.reload.priority.name
259 assert_equal 'Immediate', child1.reload.priority.name
260 assert_equal 'Immediate', parent.reload.priority.name
260 assert_equal 'Immediate', parent.reload.priority.name
261 child3 = Issue.generate!(:priority => IssuePriority.find_by_name('Low'), :parent_issue_id => parent.id)
261 child3 = Issue.generate!(:priority => IssuePriority.find_by_name('Low'), :parent_issue_id => parent.id)
262 assert_equal 'Immediate', parent.reload.priority.name
262 assert_equal 'Immediate', parent.reload.priority.name
263 # Destroy a child
263 # Destroy a child
264 child1.destroy
264 child1.destroy
265 assert_equal 'Low', parent.reload.priority.name
265 assert_equal 'Low', parent.reload.priority.name
266 # Update a child
266 # Update a child
267 child3.reload.priority = IssuePriority.find_by_name('Normal')
267 child3.reload.priority = IssuePriority.find_by_name('Normal')
268 child3.save!
268 child3.save!
269 assert_equal 'Normal', parent.reload.priority.name
269 assert_equal 'Normal', parent.reload.priority.name
270 end
270 end
271
271
272 def test_parent_dates_should_be_lowest_start_and_highest_due_dates
272 def test_parent_dates_should_be_lowest_start_and_highest_due_dates
273 parent = Issue.generate!
273 parent = Issue.generate!
274 Issue.generate!(:start_date => '2010-01-25', :due_date => '2010-02-15', :parent_issue_id => parent.id)
274 Issue.generate!(:start_date => '2010-01-25', :due_date => '2010-02-15', :parent_issue_id => parent.id)
275 Issue.generate!( :due_date => '2010-02-13', :parent_issue_id => parent.id)
275 Issue.generate!( :due_date => '2010-02-13', :parent_issue_id => parent.id)
276 Issue.generate!(:start_date => '2010-02-01', :due_date => '2010-02-22', :parent_issue_id => parent.id)
276 Issue.generate!(:start_date => '2010-02-01', :due_date => '2010-02-22', :parent_issue_id => parent.id)
277 parent.reload
277 parent.reload
278 assert_equal Date.parse('2010-01-25'), parent.start_date
278 assert_equal Date.parse('2010-01-25'), parent.start_date
279 assert_equal Date.parse('2010-02-22'), parent.due_date
279 assert_equal Date.parse('2010-02-22'), parent.due_date
280 end
280 end
281
281
282 def test_parent_done_ratio_should_be_average_done_ratio_of_leaves
282 def test_parent_done_ratio_should_be_average_done_ratio_of_leaves
283 parent = Issue.generate!
283 parent = Issue.generate!
284 Issue.generate!(:done_ratio => 20, :parent_issue_id => parent.id)
284 Issue.generate!(:done_ratio => 20, :parent_issue_id => parent.id)
285 assert_equal 20, parent.reload.done_ratio
285 assert_equal 20, parent.reload.done_ratio
286 Issue.generate!(:done_ratio => 70, :parent_issue_id => parent.id)
286 Issue.generate!(:done_ratio => 70, :parent_issue_id => parent.id)
287 assert_equal 45, parent.reload.done_ratio
287 assert_equal 45, parent.reload.done_ratio
288
288
289 child = Issue.generate!(:done_ratio => 0, :parent_issue_id => parent.id)
289 child = Issue.generate!(:done_ratio => 0, :parent_issue_id => parent.id)
290 assert_equal 30, parent.reload.done_ratio
290 assert_equal 30, parent.reload.done_ratio
291
291
292 Issue.generate!(:done_ratio => 30, :parent_issue_id => child.id)
292 Issue.generate!(:done_ratio => 30, :parent_issue_id => child.id)
293 assert_equal 30, child.reload.done_ratio
293 assert_equal 30, child.reload.done_ratio
294 assert_equal 40, parent.reload.done_ratio
294 assert_equal 40, parent.reload.done_ratio
295 end
295 end
296
296
297 def test_parent_done_ratio_should_be_weighted_by_estimated_times_if_any
297 def test_parent_done_ratio_should_be_weighted_by_estimated_times_if_any
298 parent = Issue.generate!
298 parent = Issue.generate!
299 Issue.generate!(:estimated_hours => 10, :done_ratio => 20, :parent_issue_id => parent.id)
299 Issue.generate!(:estimated_hours => 10, :done_ratio => 20, :parent_issue_id => parent.id)
300 assert_equal 20, parent.reload.done_ratio
300 assert_equal 20, parent.reload.done_ratio
301 Issue.generate!(:estimated_hours => 20, :done_ratio => 50, :parent_issue_id => parent.id)
301 Issue.generate!(:estimated_hours => 20, :done_ratio => 50, :parent_issue_id => parent.id)
302 assert_equal (50 * 20 + 20 * 10) / 30, parent.reload.done_ratio
302 assert_equal (50 * 20 + 20 * 10) / 30, parent.reload.done_ratio
303 end
303 end
304
304
305 def test_parent_estimate_should_be_sum_of_leaves
305 def test_parent_estimate_should_be_sum_of_leaves
306 parent = Issue.generate!
306 parent = Issue.generate!
307 Issue.generate!(:estimated_hours => nil, :parent_issue_id => parent.id)
307 Issue.generate!(:estimated_hours => nil, :parent_issue_id => parent.id)
308 assert_equal nil, parent.reload.estimated_hours
308 assert_equal nil, parent.reload.estimated_hours
309 Issue.generate!(:estimated_hours => 5, :parent_issue_id => parent.id)
309 Issue.generate!(:estimated_hours => 5, :parent_issue_id => parent.id)
310 assert_equal 5, parent.reload.estimated_hours
310 assert_equal 5, parent.reload.estimated_hours
311 Issue.generate!(:estimated_hours => 7, :parent_issue_id => parent.id)
311 Issue.generate!(:estimated_hours => 7, :parent_issue_id => parent.id)
312 assert_equal 12, parent.reload.estimated_hours
312 assert_equal 12, parent.reload.estimated_hours
313 end
313 end
314
314
315 def test_move_parent_updates_old_parent_attributes
315 def test_move_parent_updates_old_parent_attributes
316 first_parent = Issue.generate!
316 first_parent = Issue.generate!
317 second_parent = Issue.generate!
317 second_parent = Issue.generate!
318 child = Issue.generate!(:estimated_hours => 5, :parent_issue_id => first_parent.id)
318 child = Issue.generate!(:estimated_hours => 5, :parent_issue_id => first_parent.id)
319 assert_equal 5, first_parent.reload.estimated_hours
319 assert_equal 5, first_parent.reload.estimated_hours
320 child.update_attributes(:estimated_hours => 7, :parent_issue_id => second_parent.id)
320 child.update_attributes(:estimated_hours => 7, :parent_issue_id => second_parent.id)
321 assert_equal 7, second_parent.reload.estimated_hours
321 assert_equal 7, second_parent.reload.estimated_hours
322 assert_nil first_parent.reload.estimated_hours
322 assert_nil first_parent.reload.estimated_hours
323 end
323 end
324
324
325 def test_reschuling_a_parent_should_reschedule_subtasks
325 def test_reschuling_a_parent_should_reschedule_subtasks
326 parent = Issue.generate!
326 parent = Issue.generate!
327 c1 = Issue.generate!(:start_date => '2010-05-12', :due_date => '2010-05-18', :parent_issue_id => parent.id)
327 c1 = Issue.generate!(:start_date => '2010-05-12', :due_date => '2010-05-18', :parent_issue_id => parent.id)
328 c2 = Issue.generate!(:start_date => '2010-06-03', :due_date => '2010-06-10', :parent_issue_id => parent.id)
328 c2 = Issue.generate!(:start_date => '2010-06-03', :due_date => '2010-06-10', :parent_issue_id => parent.id)
329 parent.reload
329 parent.reload
330 parent.reschedule_on!(Date.parse('2010-06-02'))
330 parent.reschedule_on!(Date.parse('2010-06-02'))
331 c1.reload
331 c1.reload
332 assert_equal [Date.parse('2010-06-02'), Date.parse('2010-06-08')], [c1.start_date, c1.due_date]
332 assert_equal [Date.parse('2010-06-02'), Date.parse('2010-06-08')], [c1.start_date, c1.due_date]
333 c2.reload
333 c2.reload
334 assert_equal [Date.parse('2010-06-03'), Date.parse('2010-06-10')], [c2.start_date, c2.due_date] # no change
334 assert_equal [Date.parse('2010-06-03'), Date.parse('2010-06-10')], [c2.start_date, c2.due_date] # no change
335 parent.reload
335 parent.reload
336 assert_equal [Date.parse('2010-06-02'), Date.parse('2010-06-10')], [parent.start_date, parent.due_date]
336 assert_equal [Date.parse('2010-06-02'), Date.parse('2010-06-10')], [parent.start_date, parent.due_date]
337 end
337 end
338
338
339 def test_project_copy_should_copy_issue_tree
339 def test_project_copy_should_copy_issue_tree
340 p = Project.create!(:name => 'Tree copy', :identifier => 'tree-copy', :tracker_ids => [1, 2])
340 p = Project.create!(:name => 'Tree copy', :identifier => 'tree-copy', :tracker_ids => [1, 2])
341 i1 = Issue.generate!(:project => p, :subject => 'i1')
341 i1 = Issue.generate!(:project => p, :subject => 'i1')
342 i2 = Issue.generate!(:project => p, :subject => 'i2', :parent_issue_id => i1.id)
342 i2 = Issue.generate!(:project => p, :subject => 'i2', :parent_issue_id => i1.id)
343 i3 = Issue.generate!(:project => p, :subject => 'i3', :parent_issue_id => i1.id)
343 i3 = Issue.generate!(:project => p, :subject => 'i3', :parent_issue_id => i1.id)
344 i4 = Issue.generate!(:project => p, :subject => 'i4', :parent_issue_id => i2.id)
344 i4 = Issue.generate!(:project => p, :subject => 'i4', :parent_issue_id => i2.id)
345 i5 = Issue.generate!(:project => p, :subject => 'i5')
345 i5 = Issue.generate!(:project => p, :subject => 'i5')
346 c = Project.new(:name => 'Copy', :identifier => 'copy', :tracker_ids => [1, 2])
346 c = Project.new(:name => 'Copy', :identifier => 'copy', :tracker_ids => [1, 2])
347 c.copy(p, :only => 'issues')
347 c.copy(p, :only => 'issues')
348 c.reload
348 c.reload
349
349
350 assert_equal 5, c.issues.count
350 assert_equal 5, c.issues.count
351 ic1, ic2, ic3, ic4, ic5 = c.issues.order('subject').all
351 ic1, ic2, ic3, ic4, ic5 = c.issues.order('subject').all
352 assert ic1.root?
352 assert ic1.root?
353 assert_equal ic1, ic2.parent
353 assert_equal ic1, ic2.parent
354 assert_equal ic1, ic3.parent
354 assert_equal ic1, ic3.parent
355 assert_equal ic2, ic4.parent
355 assert_equal ic2, ic4.parent
356 assert ic5.root?
356 assert ic5.root?
357 end
357 end
358 end
358 end
@@ -1,216 +1,216
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2013 Jean-Philippe Lang
2 # Copyright (C) 2006-2013 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 IssueRelationTest < ActiveSupport::TestCase
20 class IssueRelationTest < ActiveSupport::TestCase
21 fixtures :projects,
21 fixtures :projects,
22 :users,
22 :users,
23 :roles,
23 :roles,
24 :members,
24 :members,
25 :member_roles,
25 :member_roles,
26 :issues,
26 :issues,
27 :issue_statuses,
27 :issue_statuses,
28 :issue_relations,
28 :issue_relations,
29 :enabled_modules,
29 :enabled_modules,
30 :enumerations,
30 :enumerations,
31 :trackers,
31 :trackers,
32 :projects_trackers
32 :projects_trackers
33
33
34 include Redmine::I18n
34 include Redmine::I18n
35
35
36 def test_create
36 def test_create
37 from = Issue.find(1)
37 from = Issue.find(1)
38 to = Issue.find(2)
38 to = Issue.find(2)
39
39
40 relation = IssueRelation.new :issue_from => from, :issue_to => to,
40 relation = IssueRelation.new :issue_from => from, :issue_to => to,
41 :relation_type => IssueRelation::TYPE_PRECEDES
41 :relation_type => IssueRelation::TYPE_PRECEDES
42 assert relation.save
42 assert relation.save
43 relation.reload
43 relation.reload
44 assert_equal IssueRelation::TYPE_PRECEDES, relation.relation_type
44 assert_equal IssueRelation::TYPE_PRECEDES, relation.relation_type
45 assert_equal from, relation.issue_from
45 assert_equal from, relation.issue_from
46 assert_equal to, relation.issue_to
46 assert_equal to, relation.issue_to
47 end
47 end
48
48
49 def test_create_minimum
49 def test_create_minimum
50 relation = IssueRelation.new :issue_from => Issue.find(1), :issue_to => Issue.find(2)
50 relation = IssueRelation.new :issue_from => Issue.find(1), :issue_to => Issue.find(2)
51 assert relation.save
51 assert relation.save
52 assert_equal IssueRelation::TYPE_RELATES, relation.relation_type
52 assert_equal IssueRelation::TYPE_RELATES, relation.relation_type
53 end
53 end
54
54
55 def test_follows_relation_should_be_reversed
55 def test_follows_relation_should_be_reversed
56 from = Issue.find(1)
56 from = Issue.find(1)
57 to = Issue.find(2)
57 to = Issue.find(2)
58
58
59 relation = IssueRelation.new :issue_from => from, :issue_to => to,
59 relation = IssueRelation.new :issue_from => from, :issue_to => to,
60 :relation_type => IssueRelation::TYPE_FOLLOWS
60 :relation_type => IssueRelation::TYPE_FOLLOWS
61 assert relation.save
61 assert relation.save
62 relation.reload
62 relation.reload
63 assert_equal IssueRelation::TYPE_PRECEDES, relation.relation_type
63 assert_equal IssueRelation::TYPE_PRECEDES, relation.relation_type
64 assert_equal to, relation.issue_from
64 assert_equal to, relation.issue_from
65 assert_equal from, relation.issue_to
65 assert_equal from, relation.issue_to
66 end
66 end
67
67
68 def test_follows_relation_should_not_be_reversed_if_validation_fails
68 def test_follows_relation_should_not_be_reversed_if_validation_fails
69 from = Issue.find(1)
69 from = Issue.find(1)
70 to = Issue.find(2)
70 to = Issue.find(2)
71
71
72 relation = IssueRelation.new :issue_from => from, :issue_to => to,
72 relation = IssueRelation.new :issue_from => from, :issue_to => to,
73 :relation_type => IssueRelation::TYPE_FOLLOWS,
73 :relation_type => IssueRelation::TYPE_FOLLOWS,
74 :delay => 'xx'
74 :delay => 'xx'
75 assert !relation.save
75 assert !relation.save
76 assert_equal IssueRelation::TYPE_FOLLOWS, relation.relation_type
76 assert_equal IssueRelation::TYPE_FOLLOWS, relation.relation_type
77 assert_equal from, relation.issue_from
77 assert_equal from, relation.issue_from
78 assert_equal to, relation.issue_to
78 assert_equal to, relation.issue_to
79 end
79 end
80
80
81 def test_relation_type_for
81 def test_relation_type_for
82 from = Issue.find(1)
82 from = Issue.find(1)
83 to = Issue.find(2)
83 to = Issue.find(2)
84
84
85 relation = IssueRelation.new :issue_from => from, :issue_to => to,
85 relation = IssueRelation.new :issue_from => from, :issue_to => to,
86 :relation_type => IssueRelation::TYPE_PRECEDES
86 :relation_type => IssueRelation::TYPE_PRECEDES
87 assert_equal IssueRelation::TYPE_PRECEDES, relation.relation_type_for(from)
87 assert_equal IssueRelation::TYPE_PRECEDES, relation.relation_type_for(from)
88 assert_equal IssueRelation::TYPE_FOLLOWS, relation.relation_type_for(to)
88 assert_equal IssueRelation::TYPE_FOLLOWS, relation.relation_type_for(to)
89 end
89 end
90
90
91 def test_set_issue_to_dates_without_issue_to
91 def test_set_issue_to_dates_without_issue_to
92 r = IssueRelation.new(:issue_from => Issue.new(:start_date => Date.today),
92 r = IssueRelation.new(:issue_from => Issue.new(:start_date => Date.today),
93 :relation_type => IssueRelation::TYPE_PRECEDES,
93 :relation_type => IssueRelation::TYPE_PRECEDES,
94 :delay => 1)
94 :delay => 1)
95 assert_nil r.set_issue_to_dates
95 assert_nil r.set_issue_to_dates
96 end
96 end
97
97
98 def test_set_issue_to_dates_without_issues
98 def test_set_issue_to_dates_without_issues
99 r = IssueRelation.new(:relation_type => IssueRelation::TYPE_PRECEDES, :delay => 1)
99 r = IssueRelation.new(:relation_type => IssueRelation::TYPE_PRECEDES, :delay => 1)
100 assert_nil r.set_issue_to_dates
100 assert_nil r.set_issue_to_dates
101 end
101 end
102
102
103 def test_validates_circular_dependency
103 def test_validates_circular_dependency
104 IssueRelation.delete_all
104 IssueRelation.delete_all
105 assert IssueRelation.create!(
105 assert IssueRelation.create!(
106 :issue_from => Issue.find(1), :issue_to => Issue.find(2),
106 :issue_from => Issue.find(1), :issue_to => Issue.find(2),
107 :relation_type => IssueRelation::TYPE_PRECEDES
107 :relation_type => IssueRelation::TYPE_PRECEDES
108 )
108 )
109 assert IssueRelation.create!(
109 assert IssueRelation.create!(
110 :issue_from => Issue.find(2), :issue_to => Issue.find(3),
110 :issue_from => Issue.find(2), :issue_to => Issue.find(3),
111 :relation_type => IssueRelation::TYPE_PRECEDES
111 :relation_type => IssueRelation::TYPE_PRECEDES
112 )
112 )
113 r = IssueRelation.new(
113 r = IssueRelation.new(
114 :issue_from => Issue.find(3), :issue_to => Issue.find(1),
114 :issue_from => Issue.find(3), :issue_to => Issue.find(1),
115 :relation_type => IssueRelation::TYPE_PRECEDES
115 :relation_type => IssueRelation::TYPE_PRECEDES
116 )
116 )
117 assert !r.save
117 assert !r.save
118 assert_not_nil r.errors[:base]
118 assert_not_equal [], r.errors[:base]
119 end
119 end
120
120
121 def test_validates_circular_dependency_of_subtask
121 def test_validates_circular_dependency_of_subtask
122 set_language_if_valid 'en'
122 set_language_if_valid 'en'
123 issue1 = Issue.generate!
123 issue1 = Issue.generate!
124 issue2 = Issue.generate!
124 issue2 = Issue.generate!
125 IssueRelation.create!(
125 IssueRelation.create!(
126 :issue_from => issue1, :issue_to => issue2,
126 :issue_from => issue1, :issue_to => issue2,
127 :relation_type => IssueRelation::TYPE_PRECEDES
127 :relation_type => IssueRelation::TYPE_PRECEDES
128 )
128 )
129 child = Issue.generate!(:parent_issue_id => issue2.id)
129 child = Issue.generate!(:parent_issue_id => issue2.id)
130 issue1.reload
130 issue1.reload
131 child.reload
131 child.reload
132
132
133 r = IssueRelation.new(
133 r = IssueRelation.new(
134 :issue_from => child, :issue_to => issue1,
134 :issue_from => child, :issue_to => issue1,
135 :relation_type => IssueRelation::TYPE_PRECEDES
135 :relation_type => IssueRelation::TYPE_PRECEDES
136 )
136 )
137 assert !r.save
137 assert !r.save
138 assert_include 'This relation would create a circular dependency', r.errors.full_messages
138 assert_include 'This relation would create a circular dependency', r.errors.full_messages
139 end
139 end
140
140
141 def test_subtasks_should_allow_precedes_relation
141 def test_subtasks_should_allow_precedes_relation
142 parent = Issue.generate!
142 parent = Issue.generate!
143 child1 = Issue.generate!(:parent_issue_id => parent.id)
143 child1 = Issue.generate!(:parent_issue_id => parent.id)
144 child2 = Issue.generate!(:parent_issue_id => parent.id)
144 child2 = Issue.generate!(:parent_issue_id => parent.id)
145
145
146 r = IssueRelation.new(
146 r = IssueRelation.new(
147 :issue_from => child1, :issue_to => child2,
147 :issue_from => child1, :issue_to => child2,
148 :relation_type => IssueRelation::TYPE_PRECEDES
148 :relation_type => IssueRelation::TYPE_PRECEDES
149 )
149 )
150 assert r.valid?
150 assert r.valid?
151 assert r.save
151 assert r.save
152 end
152 end
153
153
154 def test_validates_circular_dependency_on_reverse_relations
154 def test_validates_circular_dependency_on_reverse_relations
155 IssueRelation.delete_all
155 IssueRelation.delete_all
156 assert IssueRelation.create!(
156 assert IssueRelation.create!(
157 :issue_from => Issue.find(1), :issue_to => Issue.find(3),
157 :issue_from => Issue.find(1), :issue_to => Issue.find(3),
158 :relation_type => IssueRelation::TYPE_BLOCKS
158 :relation_type => IssueRelation::TYPE_BLOCKS
159 )
159 )
160 assert IssueRelation.create!(
160 assert IssueRelation.create!(
161 :issue_from => Issue.find(1), :issue_to => Issue.find(2),
161 :issue_from => Issue.find(1), :issue_to => Issue.find(2),
162 :relation_type => IssueRelation::TYPE_BLOCKED
162 :relation_type => IssueRelation::TYPE_BLOCKED
163 )
163 )
164 r = IssueRelation.new(
164 r = IssueRelation.new(
165 :issue_from => Issue.find(2), :issue_to => Issue.find(1),
165 :issue_from => Issue.find(2), :issue_to => Issue.find(1),
166 :relation_type => IssueRelation::TYPE_BLOCKED
166 :relation_type => IssueRelation::TYPE_BLOCKED
167 )
167 )
168 assert !r.save
168 assert !r.save
169 assert_not_nil r.errors[:base]
169 assert_not_equal [], r.errors[:base]
170 end
170 end
171
171
172 def test_create_should_make_journal_entry
172 def test_create_should_make_journal_entry
173 from = Issue.find(1)
173 from = Issue.find(1)
174 to = Issue.find(2)
174 to = Issue.find(2)
175 from_journals = from.journals.size
175 from_journals = from.journals.size
176 to_journals = to.journals.size
176 to_journals = to.journals.size
177 relation = IssueRelation.new(:issue_from => from, :issue_to => to,
177 relation = IssueRelation.new(:issue_from => from, :issue_to => to,
178 :relation_type => IssueRelation::TYPE_PRECEDES)
178 :relation_type => IssueRelation::TYPE_PRECEDES)
179 assert relation.save
179 assert relation.save
180 from.reload
180 from.reload
181 to.reload
181 to.reload
182 relation.reload
182 relation.reload
183 assert_equal from.journals.size, (from_journals + 1)
183 assert_equal from.journals.size, (from_journals + 1)
184 assert_equal to.journals.size, (to_journals + 1)
184 assert_equal to.journals.size, (to_journals + 1)
185 assert_equal 'relation', from.journals.last.details.last.property
185 assert_equal 'relation', from.journals.last.details.last.property
186 assert_equal 'label_precedes', from.journals.last.details.last.prop_key
186 assert_equal 'label_precedes', from.journals.last.details.last.prop_key
187 assert_equal '2', from.journals.last.details.last.value
187 assert_equal '2', from.journals.last.details.last.value
188 assert_nil from.journals.last.details.last.old_value
188 assert_nil from.journals.last.details.last.old_value
189 assert_equal 'relation', to.journals.last.details.last.property
189 assert_equal 'relation', to.journals.last.details.last.property
190 assert_equal 'label_follows', to.journals.last.details.last.prop_key
190 assert_equal 'label_follows', to.journals.last.details.last.prop_key
191 assert_equal '1', to.journals.last.details.last.value
191 assert_equal '1', to.journals.last.details.last.value
192 assert_nil to.journals.last.details.last.old_value
192 assert_nil to.journals.last.details.last.old_value
193 end
193 end
194
194
195 def test_delete_should_make_journal_entry
195 def test_delete_should_make_journal_entry
196 relation = IssueRelation.find(1)
196 relation = IssueRelation.find(1)
197 id = relation.id
197 id = relation.id
198 from = relation.issue_from
198 from = relation.issue_from
199 to = relation.issue_to
199 to = relation.issue_to
200 from_journals = from.journals.size
200 from_journals = from.journals.size
201 to_journals = to.journals.size
201 to_journals = to.journals.size
202 assert relation.destroy
202 assert relation.destroy
203 from.reload
203 from.reload
204 to.reload
204 to.reload
205 assert_equal from.journals.size, (from_journals + 1)
205 assert_equal from.journals.size, (from_journals + 1)
206 assert_equal to.journals.size, (to_journals + 1)
206 assert_equal to.journals.size, (to_journals + 1)
207 assert_equal 'relation', from.journals.last.details.last.property
207 assert_equal 'relation', from.journals.last.details.last.property
208 assert_equal 'label_blocks', from.journals.last.details.last.prop_key
208 assert_equal 'label_blocks', from.journals.last.details.last.prop_key
209 assert_equal '9', from.journals.last.details.last.old_value
209 assert_equal '9', from.journals.last.details.last.old_value
210 assert_nil from.journals.last.details.last.value
210 assert_nil from.journals.last.details.last.value
211 assert_equal 'relation', to.journals.last.details.last.property
211 assert_equal 'relation', to.journals.last.details.last.property
212 assert_equal 'label_blocked_by', to.journals.last.details.last.prop_key
212 assert_equal 'label_blocked_by', to.journals.last.details.last.prop_key
213 assert_equal '10', to.journals.last.details.last.old_value
213 assert_equal '10', to.journals.last.details.last.old_value
214 assert_nil to.journals.last.details.last.value
214 assert_nil to.journals.last.details.last.value
215 end
215 end
216 end
216 end
@@ -1,2290 +1,2290
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2013 Jean-Philippe Lang
2 # Copyright (C) 2006-2013 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class IssueTest < ActiveSupport::TestCase
20 class IssueTest < ActiveSupport::TestCase
21 fixtures :projects, :users, :members, :member_roles, :roles,
21 fixtures :projects, :users, :members, :member_roles, :roles,
22 :groups_users,
22 :groups_users,
23 :trackers, :projects_trackers,
23 :trackers, :projects_trackers,
24 :enabled_modules,
24 :enabled_modules,
25 :versions,
25 :versions,
26 :issue_statuses, :issue_categories, :issue_relations, :workflows,
26 :issue_statuses, :issue_categories, :issue_relations, :workflows,
27 :enumerations,
27 :enumerations,
28 :issues, :journals, :journal_details,
28 :issues, :journals, :journal_details,
29 :custom_fields, :custom_fields_projects, :custom_fields_trackers, :custom_values,
29 :custom_fields, :custom_fields_projects, :custom_fields_trackers, :custom_values,
30 :time_entries
30 :time_entries
31
31
32 include Redmine::I18n
32 include Redmine::I18n
33
33
34 def teardown
34 def teardown
35 User.current = nil
35 User.current = nil
36 end
36 end
37
37
38 def test_initialize
38 def test_initialize
39 issue = Issue.new
39 issue = Issue.new
40
40
41 assert_nil issue.project_id
41 assert_nil issue.project_id
42 assert_nil issue.tracker_id
42 assert_nil issue.tracker_id
43 assert_nil issue.author_id
43 assert_nil issue.author_id
44 assert_nil issue.assigned_to_id
44 assert_nil issue.assigned_to_id
45 assert_nil issue.category_id
45 assert_nil issue.category_id
46
46
47 assert_equal IssueStatus.default, issue.status
47 assert_equal IssueStatus.default, issue.status
48 assert_equal IssuePriority.default, issue.priority
48 assert_equal IssuePriority.default, issue.priority
49 end
49 end
50
50
51 def test_create
51 def test_create
52 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3,
52 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3,
53 :status_id => 1, :priority => IssuePriority.all.first,
53 :status_id => 1, :priority => IssuePriority.all.first,
54 :subject => 'test_create',
54 :subject => 'test_create',
55 :description => 'IssueTest#test_create', :estimated_hours => '1:30')
55 :description => 'IssueTest#test_create', :estimated_hours => '1:30')
56 assert issue.save
56 assert issue.save
57 issue.reload
57 issue.reload
58 assert_equal 1.5, issue.estimated_hours
58 assert_equal 1.5, issue.estimated_hours
59 end
59 end
60
60
61 def test_create_minimal
61 def test_create_minimal
62 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3,
62 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3,
63 :status_id => 1, :priority => IssuePriority.all.first,
63 :status_id => 1, :priority => IssuePriority.all.first,
64 :subject => 'test_create')
64 :subject => 'test_create')
65 assert issue.save
65 assert issue.save
66 assert issue.description.nil?
66 assert issue.description.nil?
67 assert_nil issue.estimated_hours
67 assert_nil issue.estimated_hours
68 end
68 end
69
69
70 def test_start_date_format_should_be_validated
70 def test_start_date_format_should_be_validated
71 set_language_if_valid 'en'
71 set_language_if_valid 'en'
72 ['2012', 'ABC', '2012-15-20'].each do |invalid_date|
72 ['2012', 'ABC', '2012-15-20'].each do |invalid_date|
73 issue = Issue.new(:start_date => invalid_date)
73 issue = Issue.new(:start_date => invalid_date)
74 assert !issue.valid?
74 assert !issue.valid?
75 assert_include 'Start date is not a valid date', issue.errors.full_messages, "No error found for invalid date #{invalid_date}"
75 assert_include 'Start date is not a valid date', issue.errors.full_messages, "No error found for invalid date #{invalid_date}"
76 end
76 end
77 end
77 end
78
78
79 def test_due_date_format_should_be_validated
79 def test_due_date_format_should_be_validated
80 set_language_if_valid 'en'
80 set_language_if_valid 'en'
81 ['2012', 'ABC', '2012-15-20'].each do |invalid_date|
81 ['2012', 'ABC', '2012-15-20'].each do |invalid_date|
82 issue = Issue.new(:due_date => invalid_date)
82 issue = Issue.new(:due_date => invalid_date)
83 assert !issue.valid?
83 assert !issue.valid?
84 assert_include 'Due date is not a valid date', issue.errors.full_messages, "No error found for invalid date #{invalid_date}"
84 assert_include 'Due date is not a valid date', issue.errors.full_messages, "No error found for invalid date #{invalid_date}"
85 end
85 end
86 end
86 end
87
87
88 def test_due_date_lesser_than_start_date_should_not_validate
88 def test_due_date_lesser_than_start_date_should_not_validate
89 set_language_if_valid 'en'
89 set_language_if_valid 'en'
90 issue = Issue.new(:start_date => '2012-10-06', :due_date => '2012-10-02')
90 issue = Issue.new(:start_date => '2012-10-06', :due_date => '2012-10-02')
91 assert !issue.valid?
91 assert !issue.valid?
92 assert_include 'Due date must be greater than start date', issue.errors.full_messages
92 assert_include 'Due date must be greater than start date', issue.errors.full_messages
93 end
93 end
94
94
95 def test_start_date_lesser_than_soonest_start_should_not_validate_on_create
95 def test_start_date_lesser_than_soonest_start_should_not_validate_on_create
96 issue = Issue.generate(:start_date => '2013-06-04')
96 issue = Issue.generate(:start_date => '2013-06-04')
97 issue.stubs(:soonest_start).returns(Date.parse('2013-06-10'))
97 issue.stubs(:soonest_start).returns(Date.parse('2013-06-10'))
98 assert !issue.valid?
98 assert !issue.valid?
99 assert_include "Start date cannot be earlier than 06/10/2013 because of preceding issues", issue.errors.full_messages
99 assert_include "Start date cannot be earlier than 06/10/2013 because of preceding issues", issue.errors.full_messages
100 end
100 end
101
101
102 def test_start_date_lesser_than_soonest_start_should_not_validate_on_update_if_changed
102 def test_start_date_lesser_than_soonest_start_should_not_validate_on_update_if_changed
103 issue = Issue.generate!(:start_date => '2013-06-04')
103 issue = Issue.generate!(:start_date => '2013-06-04')
104 issue.stubs(:soonest_start).returns(Date.parse('2013-06-10'))
104 issue.stubs(:soonest_start).returns(Date.parse('2013-06-10'))
105 issue.start_date = '2013-06-07'
105 issue.start_date = '2013-06-07'
106 assert !issue.valid?
106 assert !issue.valid?
107 assert_include "Start date cannot be earlier than 06/10/2013 because of preceding issues", issue.errors.full_messages
107 assert_include "Start date cannot be earlier than 06/10/2013 because of preceding issues", issue.errors.full_messages
108 end
108 end
109
109
110 def test_start_date_lesser_than_soonest_start_should_validate_on_update_if_unchanged
110 def test_start_date_lesser_than_soonest_start_should_validate_on_update_if_unchanged
111 issue = Issue.generate!(:start_date => '2013-06-04')
111 issue = Issue.generate!(:start_date => '2013-06-04')
112 issue.stubs(:soonest_start).returns(Date.parse('2013-06-10'))
112 issue.stubs(:soonest_start).returns(Date.parse('2013-06-10'))
113 assert issue.valid?
113 assert issue.valid?
114 end
114 end
115
115
116 def test_estimated_hours_should_be_validated
116 def test_estimated_hours_should_be_validated
117 set_language_if_valid 'en'
117 set_language_if_valid 'en'
118 ['-2'].each do |invalid|
118 ['-2'].each do |invalid|
119 issue = Issue.new(:estimated_hours => invalid)
119 issue = Issue.new(:estimated_hours => invalid)
120 assert !issue.valid?
120 assert !issue.valid?
121 assert_include 'Estimated time is invalid', issue.errors.full_messages
121 assert_include 'Estimated time is invalid', issue.errors.full_messages
122 end
122 end
123 end
123 end
124
124
125 def test_create_with_required_custom_field
125 def test_create_with_required_custom_field
126 set_language_if_valid 'en'
126 set_language_if_valid 'en'
127 field = IssueCustomField.find_by_name('Database')
127 field = IssueCustomField.find_by_name('Database')
128 field.update_attribute(:is_required, true)
128 field.update_attribute(:is_required, true)
129
129
130 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
130 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
131 :status_id => 1, :subject => 'test_create',
131 :status_id => 1, :subject => 'test_create',
132 :description => 'IssueTest#test_create_with_required_custom_field')
132 :description => 'IssueTest#test_create_with_required_custom_field')
133 assert issue.available_custom_fields.include?(field)
133 assert issue.available_custom_fields.include?(field)
134 # No value for the custom field
134 # No value for the custom field
135 assert !issue.save
135 assert !issue.save
136 assert_equal ["Database can't be blank"], issue.errors.full_messages
136 assert_equal ["Database can't be blank"], issue.errors.full_messages
137 # Blank value
137 # Blank value
138 issue.custom_field_values = { field.id => '' }
138 issue.custom_field_values = { field.id => '' }
139 assert !issue.save
139 assert !issue.save
140 assert_equal ["Database can't be blank"], issue.errors.full_messages
140 assert_equal ["Database can't be blank"], issue.errors.full_messages
141 # Invalid value
141 # Invalid value
142 issue.custom_field_values = { field.id => 'SQLServer' }
142 issue.custom_field_values = { field.id => 'SQLServer' }
143 assert !issue.save
143 assert !issue.save
144 assert_equal ["Database is not included in the list"], issue.errors.full_messages
144 assert_equal ["Database is not included in the list"], issue.errors.full_messages
145 # Valid value
145 # Valid value
146 issue.custom_field_values = { field.id => 'PostgreSQL' }
146 issue.custom_field_values = { field.id => 'PostgreSQL' }
147 assert issue.save
147 assert issue.save
148 issue.reload
148 issue.reload
149 assert_equal 'PostgreSQL', issue.custom_value_for(field).value
149 assert_equal 'PostgreSQL', issue.custom_value_for(field).value
150 end
150 end
151
151
152 def test_create_with_group_assignment
152 def test_create_with_group_assignment
153 with_settings :issue_group_assignment => '1' do
153 with_settings :issue_group_assignment => '1' do
154 assert Issue.new(:project_id => 2, :tracker_id => 1, :author_id => 1,
154 assert Issue.new(:project_id => 2, :tracker_id => 1, :author_id => 1,
155 :subject => 'Group assignment',
155 :subject => 'Group assignment',
156 :assigned_to_id => 11).save
156 :assigned_to_id => 11).save
157 issue = Issue.first(:order => 'id DESC')
157 issue = Issue.first(:order => 'id DESC')
158 assert_kind_of Group, issue.assigned_to
158 assert_kind_of Group, issue.assigned_to
159 assert_equal Group.find(11), issue.assigned_to
159 assert_equal Group.find(11), issue.assigned_to
160 end
160 end
161 end
161 end
162
162
163 def test_create_with_parent_issue_id
163 def test_create_with_parent_issue_id
164 issue = Issue.new(:project_id => 1, :tracker_id => 1,
164 issue = Issue.new(:project_id => 1, :tracker_id => 1,
165 :author_id => 1, :subject => 'Group assignment',
165 :author_id => 1, :subject => 'Group assignment',
166 :parent_issue_id => 1)
166 :parent_issue_id => 1)
167 assert_save issue
167 assert_save issue
168 assert_equal 1, issue.parent_issue_id
168 assert_equal 1, issue.parent_issue_id
169 assert_equal Issue.find(1), issue.parent
169 assert_equal Issue.find(1), issue.parent
170 end
170 end
171
171
172 def test_create_with_sharp_parent_issue_id
172 def test_create_with_sharp_parent_issue_id
173 issue = Issue.new(:project_id => 1, :tracker_id => 1,
173 issue = Issue.new(:project_id => 1, :tracker_id => 1,
174 :author_id => 1, :subject => 'Group assignment',
174 :author_id => 1, :subject => 'Group assignment',
175 :parent_issue_id => "#1")
175 :parent_issue_id => "#1")
176 assert_save issue
176 assert_save issue
177 assert_equal 1, issue.parent_issue_id
177 assert_equal 1, issue.parent_issue_id
178 assert_equal Issue.find(1), issue.parent
178 assert_equal Issue.find(1), issue.parent
179 end
179 end
180
180
181 def test_create_with_invalid_parent_issue_id
181 def test_create_with_invalid_parent_issue_id
182 set_language_if_valid 'en'
182 set_language_if_valid 'en'
183 issue = Issue.new(:project_id => 1, :tracker_id => 1,
183 issue = Issue.new(:project_id => 1, :tracker_id => 1,
184 :author_id => 1, :subject => 'Group assignment',
184 :author_id => 1, :subject => 'Group assignment',
185 :parent_issue_id => '01ABC')
185 :parent_issue_id => '01ABC')
186 assert !issue.save
186 assert !issue.save
187 assert_equal '01ABC', issue.parent_issue_id
187 assert_equal '01ABC', issue.parent_issue_id
188 assert_include 'Parent task is invalid', issue.errors.full_messages
188 assert_include 'Parent task is invalid', issue.errors.full_messages
189 end
189 end
190
190
191 def test_create_with_invalid_sharp_parent_issue_id
191 def test_create_with_invalid_sharp_parent_issue_id
192 set_language_if_valid 'en'
192 set_language_if_valid 'en'
193 issue = Issue.new(:project_id => 1, :tracker_id => 1,
193 issue = Issue.new(:project_id => 1, :tracker_id => 1,
194 :author_id => 1, :subject => 'Group assignment',
194 :author_id => 1, :subject => 'Group assignment',
195 :parent_issue_id => '#01ABC')
195 :parent_issue_id => '#01ABC')
196 assert !issue.save
196 assert !issue.save
197 assert_equal '#01ABC', issue.parent_issue_id
197 assert_equal '#01ABC', issue.parent_issue_id
198 assert_include 'Parent task is invalid', issue.errors.full_messages
198 assert_include 'Parent task is invalid', issue.errors.full_messages
199 end
199 end
200
200
201 def assert_visibility_match(user, issues)
201 def assert_visibility_match(user, issues)
202 assert_equal issues.collect(&:id).sort, Issue.all.select {|issue| issue.visible?(user)}.collect(&:id).sort
202 assert_equal issues.collect(&:id).sort, Issue.all.select {|issue| issue.visible?(user)}.collect(&:id).sort
203 end
203 end
204
204
205 def test_visible_scope_for_anonymous
205 def test_visible_scope_for_anonymous
206 # Anonymous user should see issues of public projects only
206 # Anonymous user should see issues of public projects only
207 issues = Issue.visible(User.anonymous).all
207 issues = Issue.visible(User.anonymous).all
208 assert issues.any?
208 assert issues.any?
209 assert_nil issues.detect {|issue| !issue.project.is_public?}
209 assert_nil issues.detect {|issue| !issue.project.is_public?}
210 assert_nil issues.detect {|issue| issue.is_private?}
210 assert_nil issues.detect {|issue| issue.is_private?}
211 assert_visibility_match User.anonymous, issues
211 assert_visibility_match User.anonymous, issues
212 end
212 end
213
213
214 def test_visible_scope_for_anonymous_without_view_issues_permissions
214 def test_visible_scope_for_anonymous_without_view_issues_permissions
215 # Anonymous user should not see issues without permission
215 # Anonymous user should not see issues without permission
216 Role.anonymous.remove_permission!(:view_issues)
216 Role.anonymous.remove_permission!(:view_issues)
217 issues = Issue.visible(User.anonymous).all
217 issues = Issue.visible(User.anonymous).all
218 assert issues.empty?
218 assert issues.empty?
219 assert_visibility_match User.anonymous, issues
219 assert_visibility_match User.anonymous, issues
220 end
220 end
221
221
222 def test_anonymous_should_not_see_private_issues_with_issues_visibility_set_to_default
222 def test_anonymous_should_not_see_private_issues_with_issues_visibility_set_to_default
223 assert Role.anonymous.update_attribute(:issues_visibility, 'default')
223 assert Role.anonymous.update_attribute(:issues_visibility, 'default')
224 issue = Issue.generate!(:author => User.anonymous, :assigned_to => User.anonymous, :is_private => true)
224 issue = Issue.generate!(:author => User.anonymous, :assigned_to => User.anonymous, :is_private => true)
225 assert_nil Issue.where(:id => issue.id).visible(User.anonymous).first
225 assert_nil Issue.where(:id => issue.id).visible(User.anonymous).first
226 assert !issue.visible?(User.anonymous)
226 assert !issue.visible?(User.anonymous)
227 end
227 end
228
228
229 def test_anonymous_should_not_see_private_issues_with_issues_visibility_set_to_own
229 def test_anonymous_should_not_see_private_issues_with_issues_visibility_set_to_own
230 assert Role.anonymous.update_attribute(:issues_visibility, 'own')
230 assert Role.anonymous.update_attribute(:issues_visibility, 'own')
231 issue = Issue.generate!(:author => User.anonymous, :assigned_to => User.anonymous, :is_private => true)
231 issue = Issue.generate!(:author => User.anonymous, :assigned_to => User.anonymous, :is_private => true)
232 assert_nil Issue.where(:id => issue.id).visible(User.anonymous).first
232 assert_nil Issue.where(:id => issue.id).visible(User.anonymous).first
233 assert !issue.visible?(User.anonymous)
233 assert !issue.visible?(User.anonymous)
234 end
234 end
235
235
236 def test_visible_scope_for_non_member
236 def test_visible_scope_for_non_member
237 user = User.find(9)
237 user = User.find(9)
238 assert user.projects.empty?
238 assert user.projects.empty?
239 # Non member user should see issues of public projects only
239 # Non member user should see issues of public projects only
240 issues = Issue.visible(user).all
240 issues = Issue.visible(user).all
241 assert issues.any?
241 assert issues.any?
242 assert_nil issues.detect {|issue| !issue.project.is_public?}
242 assert_nil issues.detect {|issue| !issue.project.is_public?}
243 assert_nil issues.detect {|issue| issue.is_private?}
243 assert_nil issues.detect {|issue| issue.is_private?}
244 assert_visibility_match user, issues
244 assert_visibility_match user, issues
245 end
245 end
246
246
247 def test_visible_scope_for_non_member_with_own_issues_visibility
247 def test_visible_scope_for_non_member_with_own_issues_visibility
248 Role.non_member.update_attribute :issues_visibility, 'own'
248 Role.non_member.update_attribute :issues_visibility, 'own'
249 Issue.create!(:project_id => 1, :tracker_id => 1, :author_id => 9, :subject => 'Issue by non member')
249 Issue.create!(:project_id => 1, :tracker_id => 1, :author_id => 9, :subject => 'Issue by non member')
250 user = User.find(9)
250 user = User.find(9)
251
251
252 issues = Issue.visible(user).all
252 issues = Issue.visible(user).all
253 assert issues.any?
253 assert issues.any?
254 assert_nil issues.detect {|issue| issue.author != user}
254 assert_nil issues.detect {|issue| issue.author != user}
255 assert_visibility_match user, issues
255 assert_visibility_match user, issues
256 end
256 end
257
257
258 def test_visible_scope_for_non_member_without_view_issues_permissions
258 def test_visible_scope_for_non_member_without_view_issues_permissions
259 # Non member user should not see issues without permission
259 # Non member user should not see issues without permission
260 Role.non_member.remove_permission!(:view_issues)
260 Role.non_member.remove_permission!(:view_issues)
261 user = User.find(9)
261 user = User.find(9)
262 assert user.projects.empty?
262 assert user.projects.empty?
263 issues = Issue.visible(user).all
263 issues = Issue.visible(user).all
264 assert issues.empty?
264 assert issues.empty?
265 assert_visibility_match user, issues
265 assert_visibility_match user, issues
266 end
266 end
267
267
268 def test_visible_scope_for_member
268 def test_visible_scope_for_member
269 user = User.find(9)
269 user = User.find(9)
270 # User should see issues of projects for which user has view_issues permissions only
270 # User should see issues of projects for which user has view_issues permissions only
271 Role.non_member.remove_permission!(:view_issues)
271 Role.non_member.remove_permission!(:view_issues)
272 Member.create!(:principal => user, :project_id => 3, :role_ids => [2])
272 Member.create!(:principal => user, :project_id => 3, :role_ids => [2])
273 issues = Issue.visible(user).all
273 issues = Issue.visible(user).all
274 assert issues.any?
274 assert issues.any?
275 assert_nil issues.detect {|issue| issue.project_id != 3}
275 assert_nil issues.detect {|issue| issue.project_id != 3}
276 assert_nil issues.detect {|issue| issue.is_private?}
276 assert_nil issues.detect {|issue| issue.is_private?}
277 assert_visibility_match user, issues
277 assert_visibility_match user, issues
278 end
278 end
279
279
280 def test_visible_scope_for_member_with_groups_should_return_assigned_issues
280 def test_visible_scope_for_member_with_groups_should_return_assigned_issues
281 user = User.find(8)
281 user = User.find(8)
282 assert user.groups.any?
282 assert user.groups.any?
283 Member.create!(:principal => user.groups.first, :project_id => 1, :role_ids => [2])
283 Member.create!(:principal => user.groups.first, :project_id => 1, :role_ids => [2])
284 Role.non_member.remove_permission!(:view_issues)
284 Role.non_member.remove_permission!(:view_issues)
285
285
286 issue = Issue.create(:project_id => 1, :tracker_id => 1, :author_id => 3,
286 issue = Issue.create(:project_id => 1, :tracker_id => 1, :author_id => 3,
287 :status_id => 1, :priority => IssuePriority.all.first,
287 :status_id => 1, :priority => IssuePriority.all.first,
288 :subject => 'Assignment test',
288 :subject => 'Assignment test',
289 :assigned_to => user.groups.first,
289 :assigned_to => user.groups.first,
290 :is_private => true)
290 :is_private => true)
291
291
292 Role.find(2).update_attribute :issues_visibility, 'default'
292 Role.find(2).update_attribute :issues_visibility, 'default'
293 issues = Issue.visible(User.find(8)).all
293 issues = Issue.visible(User.find(8)).all
294 assert issues.any?
294 assert issues.any?
295 assert issues.include?(issue)
295 assert issues.include?(issue)
296
296
297 Role.find(2).update_attribute :issues_visibility, 'own'
297 Role.find(2).update_attribute :issues_visibility, 'own'
298 issues = Issue.visible(User.find(8)).all
298 issues = Issue.visible(User.find(8)).all
299 assert issues.any?
299 assert issues.any?
300 assert issues.include?(issue)
300 assert issues.include?(issue)
301 end
301 end
302
302
303 def test_visible_scope_for_admin
303 def test_visible_scope_for_admin
304 user = User.find(1)
304 user = User.find(1)
305 user.members.each(&:destroy)
305 user.members.each(&:destroy)
306 assert user.projects.empty?
306 assert user.projects.empty?
307 issues = Issue.visible(user).all
307 issues = Issue.visible(user).all
308 assert issues.any?
308 assert issues.any?
309 # Admin should see issues on private projects that admin does not belong to
309 # Admin should see issues on private projects that admin does not belong to
310 assert issues.detect {|issue| !issue.project.is_public?}
310 assert issues.detect {|issue| !issue.project.is_public?}
311 # Admin should see private issues of other users
311 # Admin should see private issues of other users
312 assert issues.detect {|issue| issue.is_private? && issue.author != user}
312 assert issues.detect {|issue| issue.is_private? && issue.author != user}
313 assert_visibility_match user, issues
313 assert_visibility_match user, issues
314 end
314 end
315
315
316 def test_visible_scope_with_project
316 def test_visible_scope_with_project
317 project = Project.find(1)
317 project = Project.find(1)
318 issues = Issue.visible(User.find(2), :project => project).all
318 issues = Issue.visible(User.find(2), :project => project).all
319 projects = issues.collect(&:project).uniq
319 projects = issues.collect(&:project).uniq
320 assert_equal 1, projects.size
320 assert_equal 1, projects.size
321 assert_equal project, projects.first
321 assert_equal project, projects.first
322 end
322 end
323
323
324 def test_visible_scope_with_project_and_subprojects
324 def test_visible_scope_with_project_and_subprojects
325 project = Project.find(1)
325 project = Project.find(1)
326 issues = Issue.visible(User.find(2), :project => project, :with_subprojects => true).all
326 issues = Issue.visible(User.find(2), :project => project, :with_subprojects => true).all
327 projects = issues.collect(&:project).uniq
327 projects = issues.collect(&:project).uniq
328 assert projects.size > 1
328 assert projects.size > 1
329 assert_equal [], projects.select {|p| !p.is_or_is_descendant_of?(project)}
329 assert_equal [], projects.select {|p| !p.is_or_is_descendant_of?(project)}
330 end
330 end
331
331
332 def test_visible_and_nested_set_scopes
332 def test_visible_and_nested_set_scopes
333 assert_equal 0, Issue.find(1).descendants.visible.all.size
333 assert_equal 0, Issue.find(1).descendants.visible.all.size
334 end
334 end
335
335
336 def test_open_scope
336 def test_open_scope
337 issues = Issue.open.all
337 issues = Issue.open.all
338 assert_nil issues.detect(&:closed?)
338 assert_nil issues.detect(&:closed?)
339 end
339 end
340
340
341 def test_open_scope_with_arg
341 def test_open_scope_with_arg
342 issues = Issue.open(false).all
342 issues = Issue.open(false).all
343 assert_equal issues, issues.select(&:closed?)
343 assert_equal issues, issues.select(&:closed?)
344 end
344 end
345
345
346 def test_fixed_version_scope_with_a_version_should_return_its_fixed_issues
346 def test_fixed_version_scope_with_a_version_should_return_its_fixed_issues
347 version = Version.find(2)
347 version = Version.find(2)
348 assert version.fixed_issues.any?
348 assert version.fixed_issues.any?
349 assert_equal version.fixed_issues.to_a.sort, Issue.fixed_version(version).to_a.sort
349 assert_equal version.fixed_issues.to_a.sort, Issue.fixed_version(version).to_a.sort
350 end
350 end
351
351
352 def test_fixed_version_scope_with_empty_array_should_return_no_result
352 def test_fixed_version_scope_with_empty_array_should_return_no_result
353 assert_equal 0, Issue.fixed_version([]).count
353 assert_equal 0, Issue.fixed_version([]).count
354 end
354 end
355
355
356 def test_errors_full_messages_should_include_custom_fields_errors
356 def test_errors_full_messages_should_include_custom_fields_errors
357 field = IssueCustomField.find_by_name('Database')
357 field = IssueCustomField.find_by_name('Database')
358
358
359 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
359 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
360 :status_id => 1, :subject => 'test_create',
360 :status_id => 1, :subject => 'test_create',
361 :description => 'IssueTest#test_create_with_required_custom_field')
361 :description => 'IssueTest#test_create_with_required_custom_field')
362 assert issue.available_custom_fields.include?(field)
362 assert issue.available_custom_fields.include?(field)
363 # Invalid value
363 # Invalid value
364 issue.custom_field_values = { field.id => 'SQLServer' }
364 issue.custom_field_values = { field.id => 'SQLServer' }
365
365
366 assert !issue.valid?
366 assert !issue.valid?
367 assert_equal 1, issue.errors.full_messages.size
367 assert_equal 1, issue.errors.full_messages.size
368 assert_equal "Database #{I18n.translate('activerecord.errors.messages.inclusion')}",
368 assert_equal "Database #{I18n.translate('activerecord.errors.messages.inclusion')}",
369 issue.errors.full_messages.first
369 issue.errors.full_messages.first
370 end
370 end
371
371
372 def test_update_issue_with_required_custom_field
372 def test_update_issue_with_required_custom_field
373 field = IssueCustomField.find_by_name('Database')
373 field = IssueCustomField.find_by_name('Database')
374 field.update_attribute(:is_required, true)
374 field.update_attribute(:is_required, true)
375
375
376 issue = Issue.find(1)
376 issue = Issue.find(1)
377 assert_nil issue.custom_value_for(field)
377 assert_nil issue.custom_value_for(field)
378 assert issue.available_custom_fields.include?(field)
378 assert issue.available_custom_fields.include?(field)
379 # No change to custom values, issue can be saved
379 # No change to custom values, issue can be saved
380 assert issue.save
380 assert issue.save
381 # Blank value
381 # Blank value
382 issue.custom_field_values = { field.id => '' }
382 issue.custom_field_values = { field.id => '' }
383 assert !issue.save
383 assert !issue.save
384 # Valid value
384 # Valid value
385 issue.custom_field_values = { field.id => 'PostgreSQL' }
385 issue.custom_field_values = { field.id => 'PostgreSQL' }
386 assert issue.save
386 assert issue.save
387 issue.reload
387 issue.reload
388 assert_equal 'PostgreSQL', issue.custom_value_for(field).value
388 assert_equal 'PostgreSQL', issue.custom_value_for(field).value
389 end
389 end
390
390
391 def test_should_not_update_attributes_if_custom_fields_validation_fails
391 def test_should_not_update_attributes_if_custom_fields_validation_fails
392 issue = Issue.find(1)
392 issue = Issue.find(1)
393 field = IssueCustomField.find_by_name('Database')
393 field = IssueCustomField.find_by_name('Database')
394 assert issue.available_custom_fields.include?(field)
394 assert issue.available_custom_fields.include?(field)
395
395
396 issue.custom_field_values = { field.id => 'Invalid' }
396 issue.custom_field_values = { field.id => 'Invalid' }
397 issue.subject = 'Should be not be saved'
397 issue.subject = 'Should be not be saved'
398 assert !issue.save
398 assert !issue.save
399
399
400 issue.reload
400 issue.reload
401 assert_equal "Can't print recipes", issue.subject
401 assert_equal "Can't print recipes", issue.subject
402 end
402 end
403
403
404 def test_should_not_recreate_custom_values_objects_on_update
404 def test_should_not_recreate_custom_values_objects_on_update
405 field = IssueCustomField.find_by_name('Database')
405 field = IssueCustomField.find_by_name('Database')
406
406
407 issue = Issue.find(1)
407 issue = Issue.find(1)
408 issue.custom_field_values = { field.id => 'PostgreSQL' }
408 issue.custom_field_values = { field.id => 'PostgreSQL' }
409 assert issue.save
409 assert issue.save
410 custom_value = issue.custom_value_for(field)
410 custom_value = issue.custom_value_for(field)
411 issue.reload
411 issue.reload
412 issue.custom_field_values = { field.id => 'MySQL' }
412 issue.custom_field_values = { field.id => 'MySQL' }
413 assert issue.save
413 assert issue.save
414 issue.reload
414 issue.reload
415 assert_equal custom_value.id, issue.custom_value_for(field).id
415 assert_equal custom_value.id, issue.custom_value_for(field).id
416 end
416 end
417
417
418 def test_should_not_update_custom_fields_on_changing_tracker_with_different_custom_fields
418 def test_should_not_update_custom_fields_on_changing_tracker_with_different_custom_fields
419 issue = Issue.create!(:project_id => 1, :tracker_id => 1, :author_id => 1,
419 issue = Issue.create!(:project_id => 1, :tracker_id => 1, :author_id => 1,
420 :status_id => 1, :subject => 'Test',
420 :status_id => 1, :subject => 'Test',
421 :custom_field_values => {'2' => 'Test'})
421 :custom_field_values => {'2' => 'Test'})
422 assert !Tracker.find(2).custom_field_ids.include?(2)
422 assert !Tracker.find(2).custom_field_ids.include?(2)
423
423
424 issue = Issue.find(issue.id)
424 issue = Issue.find(issue.id)
425 issue.attributes = {:tracker_id => 2, :custom_field_values => {'1' => ''}}
425 issue.attributes = {:tracker_id => 2, :custom_field_values => {'1' => ''}}
426
426
427 issue = Issue.find(issue.id)
427 issue = Issue.find(issue.id)
428 custom_value = issue.custom_value_for(2)
428 custom_value = issue.custom_value_for(2)
429 assert_not_nil custom_value
429 assert_not_nil custom_value
430 assert_equal 'Test', custom_value.value
430 assert_equal 'Test', custom_value.value
431 end
431 end
432
432
433 def test_assigning_tracker_id_should_reload_custom_fields_values
433 def test_assigning_tracker_id_should_reload_custom_fields_values
434 issue = Issue.new(:project => Project.find(1))
434 issue = Issue.new(:project => Project.find(1))
435 assert issue.custom_field_values.empty?
435 assert issue.custom_field_values.empty?
436 issue.tracker_id = 1
436 issue.tracker_id = 1
437 assert issue.custom_field_values.any?
437 assert issue.custom_field_values.any?
438 end
438 end
439
439
440 def test_assigning_attributes_should_assign_project_and_tracker_first
440 def test_assigning_attributes_should_assign_project_and_tracker_first
441 seq = sequence('seq')
441 seq = sequence('seq')
442 issue = Issue.new
442 issue = Issue.new
443 issue.expects(:project_id=).in_sequence(seq)
443 issue.expects(:project_id=).in_sequence(seq)
444 issue.expects(:tracker_id=).in_sequence(seq)
444 issue.expects(:tracker_id=).in_sequence(seq)
445 issue.expects(:subject=).in_sequence(seq)
445 issue.expects(:subject=).in_sequence(seq)
446 issue.attributes = {:tracker_id => 2, :project_id => 1, :subject => 'Test'}
446 issue.attributes = {:tracker_id => 2, :project_id => 1, :subject => 'Test'}
447 end
447 end
448
448
449 def test_assigning_tracker_and_custom_fields_should_assign_custom_fields
449 def test_assigning_tracker_and_custom_fields_should_assign_custom_fields
450 attributes = ActiveSupport::OrderedHash.new
450 attributes = ActiveSupport::OrderedHash.new
451 attributes['custom_field_values'] = { '1' => 'MySQL' }
451 attributes['custom_field_values'] = { '1' => 'MySQL' }
452 attributes['tracker_id'] = '1'
452 attributes['tracker_id'] = '1'
453 issue = Issue.new(:project => Project.find(1))
453 issue = Issue.new(:project => Project.find(1))
454 issue.attributes = attributes
454 issue.attributes = attributes
455 assert_equal 'MySQL', issue.custom_field_value(1)
455 assert_equal 'MySQL', issue.custom_field_value(1)
456 end
456 end
457
457
458 def test_reload_should_reload_custom_field_values
458 def test_reload_should_reload_custom_field_values
459 issue = Issue.generate!
459 issue = Issue.generate!
460 issue.custom_field_values = {'2' => 'Foo'}
460 issue.custom_field_values = {'2' => 'Foo'}
461 issue.save!
461 issue.save!
462
462
463 issue = Issue.order('id desc').first
463 issue = Issue.order('id desc').first
464 assert_equal 'Foo', issue.custom_field_value(2)
464 assert_equal 'Foo', issue.custom_field_value(2)
465
465
466 issue.custom_field_values = {'2' => 'Bar'}
466 issue.custom_field_values = {'2' => 'Bar'}
467 assert_equal 'Bar', issue.custom_field_value(2)
467 assert_equal 'Bar', issue.custom_field_value(2)
468
468
469 issue.reload
469 issue.reload
470 assert_equal 'Foo', issue.custom_field_value(2)
470 assert_equal 'Foo', issue.custom_field_value(2)
471 end
471 end
472
472
473 def test_should_update_issue_with_disabled_tracker
473 def test_should_update_issue_with_disabled_tracker
474 p = Project.find(1)
474 p = Project.find(1)
475 issue = Issue.find(1)
475 issue = Issue.find(1)
476
476
477 p.trackers.delete(issue.tracker)
477 p.trackers.delete(issue.tracker)
478 assert !p.trackers.include?(issue.tracker)
478 assert !p.trackers.include?(issue.tracker)
479
479
480 issue.reload
480 issue.reload
481 issue.subject = 'New subject'
481 issue.subject = 'New subject'
482 assert issue.save
482 assert issue.save
483 end
483 end
484
484
485 def test_should_not_set_a_disabled_tracker
485 def test_should_not_set_a_disabled_tracker
486 p = Project.find(1)
486 p = Project.find(1)
487 p.trackers.delete(Tracker.find(2))
487 p.trackers.delete(Tracker.find(2))
488
488
489 issue = Issue.find(1)
489 issue = Issue.find(1)
490 issue.tracker_id = 2
490 issue.tracker_id = 2
491 issue.subject = 'New subject'
491 issue.subject = 'New subject'
492 assert !issue.save
492 assert !issue.save
493 assert_not_nil issue.errors[:tracker_id]
493 assert_not_equal [], issue.errors[:tracker_id]
494 end
494 end
495
495
496 def test_category_based_assignment
496 def test_category_based_assignment
497 issue = Issue.create(:project_id => 1, :tracker_id => 1, :author_id => 3,
497 issue = Issue.create(:project_id => 1, :tracker_id => 1, :author_id => 3,
498 :status_id => 1, :priority => IssuePriority.all.first,
498 :status_id => 1, :priority => IssuePriority.all.first,
499 :subject => 'Assignment test',
499 :subject => 'Assignment test',
500 :description => 'Assignment test', :category_id => 1)
500 :description => 'Assignment test', :category_id => 1)
501 assert_equal IssueCategory.find(1).assigned_to, issue.assigned_to
501 assert_equal IssueCategory.find(1).assigned_to, issue.assigned_to
502 end
502 end
503
503
504 def test_new_statuses_allowed_to
504 def test_new_statuses_allowed_to
505 WorkflowTransition.delete_all
505 WorkflowTransition.delete_all
506 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
506 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
507 :old_status_id => 1, :new_status_id => 2,
507 :old_status_id => 1, :new_status_id => 2,
508 :author => false, :assignee => false)
508 :author => false, :assignee => false)
509 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
509 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
510 :old_status_id => 1, :new_status_id => 3,
510 :old_status_id => 1, :new_status_id => 3,
511 :author => true, :assignee => false)
511 :author => true, :assignee => false)
512 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
512 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
513 :old_status_id => 1, :new_status_id => 4,
513 :old_status_id => 1, :new_status_id => 4,
514 :author => false, :assignee => true)
514 :author => false, :assignee => true)
515 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
515 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
516 :old_status_id => 1, :new_status_id => 5,
516 :old_status_id => 1, :new_status_id => 5,
517 :author => true, :assignee => true)
517 :author => true, :assignee => true)
518 status = IssueStatus.find(1)
518 status = IssueStatus.find(1)
519 role = Role.find(1)
519 role = Role.find(1)
520 tracker = Tracker.find(1)
520 tracker = Tracker.find(1)
521 user = User.find(2)
521 user = User.find(2)
522
522
523 issue = Issue.generate!(:tracker => tracker, :status => status,
523 issue = Issue.generate!(:tracker => tracker, :status => status,
524 :project_id => 1, :author_id => 1)
524 :project_id => 1, :author_id => 1)
525 assert_equal [1, 2], issue.new_statuses_allowed_to(user).map(&:id)
525 assert_equal [1, 2], issue.new_statuses_allowed_to(user).map(&:id)
526
526
527 issue = Issue.generate!(:tracker => tracker, :status => status,
527 issue = Issue.generate!(:tracker => tracker, :status => status,
528 :project_id => 1, :author => user)
528 :project_id => 1, :author => user)
529 assert_equal [1, 2, 3, 5], issue.new_statuses_allowed_to(user).map(&:id)
529 assert_equal [1, 2, 3, 5], issue.new_statuses_allowed_to(user).map(&:id)
530
530
531 issue = Issue.generate!(:tracker => tracker, :status => status,
531 issue = Issue.generate!(:tracker => tracker, :status => status,
532 :project_id => 1, :author_id => 1,
532 :project_id => 1, :author_id => 1,
533 :assigned_to => user)
533 :assigned_to => user)
534 assert_equal [1, 2, 4, 5], issue.new_statuses_allowed_to(user).map(&:id)
534 assert_equal [1, 2, 4, 5], issue.new_statuses_allowed_to(user).map(&:id)
535
535
536 issue = Issue.generate!(:tracker => tracker, :status => status,
536 issue = Issue.generate!(:tracker => tracker, :status => status,
537 :project_id => 1, :author => user,
537 :project_id => 1, :author => user,
538 :assigned_to => user)
538 :assigned_to => user)
539 assert_equal [1, 2, 3, 4, 5], issue.new_statuses_allowed_to(user).map(&:id)
539 assert_equal [1, 2, 3, 4, 5], issue.new_statuses_allowed_to(user).map(&:id)
540
540
541 group = Group.generate!
541 group = Group.generate!
542 group.users << user
542 group.users << user
543 issue = Issue.generate!(:tracker => tracker, :status => status,
543 issue = Issue.generate!(:tracker => tracker, :status => status,
544 :project_id => 1, :author => user,
544 :project_id => 1, :author => user,
545 :assigned_to => group)
545 :assigned_to => group)
546 assert_equal [1, 2, 3, 4, 5], issue.new_statuses_allowed_to(user).map(&:id)
546 assert_equal [1, 2, 3, 4, 5], issue.new_statuses_allowed_to(user).map(&:id)
547 end
547 end
548
548
549 def test_new_statuses_allowed_to_should_consider_group_assignment
549 def test_new_statuses_allowed_to_should_consider_group_assignment
550 WorkflowTransition.delete_all
550 WorkflowTransition.delete_all
551 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
551 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
552 :old_status_id => 1, :new_status_id => 4,
552 :old_status_id => 1, :new_status_id => 4,
553 :author => false, :assignee => true)
553 :author => false, :assignee => true)
554 user = User.find(2)
554 user = User.find(2)
555 group = Group.generate!
555 group = Group.generate!
556 group.users << user
556 group.users << user
557
557
558 issue = Issue.generate!(:author_id => 1, :assigned_to => group)
558 issue = Issue.generate!(:author_id => 1, :assigned_to => group)
559 assert_include 4, issue.new_statuses_allowed_to(user).map(&:id)
559 assert_include 4, issue.new_statuses_allowed_to(user).map(&:id)
560 end
560 end
561
561
562 def test_new_statuses_allowed_to_should_return_all_transitions_for_admin
562 def test_new_statuses_allowed_to_should_return_all_transitions_for_admin
563 admin = User.find(1)
563 admin = User.find(1)
564 issue = Issue.find(1)
564 issue = Issue.find(1)
565 assert !admin.member_of?(issue.project)
565 assert !admin.member_of?(issue.project)
566 expected_statuses = [issue.status] +
566 expected_statuses = [issue.status] +
567 WorkflowTransition.find_all_by_old_status_id(
567 WorkflowTransition.find_all_by_old_status_id(
568 issue.status_id).map(&:new_status).uniq.sort
568 issue.status_id).map(&:new_status).uniq.sort
569 assert_equal expected_statuses, issue.new_statuses_allowed_to(admin)
569 assert_equal expected_statuses, issue.new_statuses_allowed_to(admin)
570 end
570 end
571
571
572 def test_new_statuses_allowed_to_should_return_default_and_current_status_when_copying
572 def test_new_statuses_allowed_to_should_return_default_and_current_status_when_copying
573 issue = Issue.find(1).copy
573 issue = Issue.find(1).copy
574 assert_equal [1], issue.new_statuses_allowed_to(User.find(2)).map(&:id)
574 assert_equal [1], issue.new_statuses_allowed_to(User.find(2)).map(&:id)
575
575
576 issue = Issue.find(2).copy
576 issue = Issue.find(2).copy
577 assert_equal [1, 2], issue.new_statuses_allowed_to(User.find(2)).map(&:id)
577 assert_equal [1, 2], issue.new_statuses_allowed_to(User.find(2)).map(&:id)
578 end
578 end
579
579
580 def test_safe_attributes_names_should_not_include_disabled_field
580 def test_safe_attributes_names_should_not_include_disabled_field
581 tracker = Tracker.new(:core_fields => %w(assigned_to_id fixed_version_id))
581 tracker = Tracker.new(:core_fields => %w(assigned_to_id fixed_version_id))
582
582
583 issue = Issue.new(:tracker => tracker)
583 issue = Issue.new(:tracker => tracker)
584 assert_include 'tracker_id', issue.safe_attribute_names
584 assert_include 'tracker_id', issue.safe_attribute_names
585 assert_include 'status_id', issue.safe_attribute_names
585 assert_include 'status_id', issue.safe_attribute_names
586 assert_include 'subject', issue.safe_attribute_names
586 assert_include 'subject', issue.safe_attribute_names
587 assert_include 'description', issue.safe_attribute_names
587 assert_include 'description', issue.safe_attribute_names
588 assert_include 'custom_field_values', issue.safe_attribute_names
588 assert_include 'custom_field_values', issue.safe_attribute_names
589 assert_include 'custom_fields', issue.safe_attribute_names
589 assert_include 'custom_fields', issue.safe_attribute_names
590 assert_include 'lock_version', issue.safe_attribute_names
590 assert_include 'lock_version', issue.safe_attribute_names
591
591
592 tracker.core_fields.each do |field|
592 tracker.core_fields.each do |field|
593 assert_include field, issue.safe_attribute_names
593 assert_include field, issue.safe_attribute_names
594 end
594 end
595
595
596 tracker.disabled_core_fields.each do |field|
596 tracker.disabled_core_fields.each do |field|
597 assert_not_include field, issue.safe_attribute_names
597 assert_not_include field, issue.safe_attribute_names
598 end
598 end
599 end
599 end
600
600
601 def test_safe_attributes_should_ignore_disabled_fields
601 def test_safe_attributes_should_ignore_disabled_fields
602 tracker = Tracker.find(1)
602 tracker = Tracker.find(1)
603 tracker.core_fields = %w(assigned_to_id due_date)
603 tracker.core_fields = %w(assigned_to_id due_date)
604 tracker.save!
604 tracker.save!
605
605
606 issue = Issue.new(:tracker => tracker)
606 issue = Issue.new(:tracker => tracker)
607 issue.safe_attributes = {'start_date' => '2012-07-14', 'due_date' => '2012-07-14'}
607 issue.safe_attributes = {'start_date' => '2012-07-14', 'due_date' => '2012-07-14'}
608 assert_nil issue.start_date
608 assert_nil issue.start_date
609 assert_equal Date.parse('2012-07-14'), issue.due_date
609 assert_equal Date.parse('2012-07-14'), issue.due_date
610 end
610 end
611
611
612 def test_safe_attributes_should_accept_target_tracker_enabled_fields
612 def test_safe_attributes_should_accept_target_tracker_enabled_fields
613 source = Tracker.find(1)
613 source = Tracker.find(1)
614 source.core_fields = []
614 source.core_fields = []
615 source.save!
615 source.save!
616 target = Tracker.find(2)
616 target = Tracker.find(2)
617 target.core_fields = %w(assigned_to_id due_date)
617 target.core_fields = %w(assigned_to_id due_date)
618 target.save!
618 target.save!
619
619
620 issue = Issue.new(:tracker => source)
620 issue = Issue.new(:tracker => source)
621 issue.safe_attributes = {'tracker_id' => 2, 'due_date' => '2012-07-14'}
621 issue.safe_attributes = {'tracker_id' => 2, 'due_date' => '2012-07-14'}
622 assert_equal target, issue.tracker
622 assert_equal target, issue.tracker
623 assert_equal Date.parse('2012-07-14'), issue.due_date
623 assert_equal Date.parse('2012-07-14'), issue.due_date
624 end
624 end
625
625
626 def test_safe_attributes_should_not_include_readonly_fields
626 def test_safe_attributes_should_not_include_readonly_fields
627 WorkflowPermission.delete_all
627 WorkflowPermission.delete_all
628 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
628 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
629 :role_id => 1, :field_name => 'due_date',
629 :role_id => 1, :field_name => 'due_date',
630 :rule => 'readonly')
630 :rule => 'readonly')
631 user = User.find(2)
631 user = User.find(2)
632
632
633 issue = Issue.new(:project_id => 1, :tracker_id => 1)
633 issue = Issue.new(:project_id => 1, :tracker_id => 1)
634 assert_equal %w(due_date), issue.read_only_attribute_names(user)
634 assert_equal %w(due_date), issue.read_only_attribute_names(user)
635 assert_not_include 'due_date', issue.safe_attribute_names(user)
635 assert_not_include 'due_date', issue.safe_attribute_names(user)
636
636
637 issue.send :safe_attributes=, {'start_date' => '2012-07-14', 'due_date' => '2012-07-14'}, user
637 issue.send :safe_attributes=, {'start_date' => '2012-07-14', 'due_date' => '2012-07-14'}, user
638 assert_equal Date.parse('2012-07-14'), issue.start_date
638 assert_equal Date.parse('2012-07-14'), issue.start_date
639 assert_nil issue.due_date
639 assert_nil issue.due_date
640 end
640 end
641
641
642 def test_safe_attributes_should_not_include_readonly_custom_fields
642 def test_safe_attributes_should_not_include_readonly_custom_fields
643 cf1 = IssueCustomField.create!(:name => 'Writable field',
643 cf1 = IssueCustomField.create!(:name => 'Writable field',
644 :field_format => 'string',
644 :field_format => 'string',
645 :is_for_all => true, :tracker_ids => [1])
645 :is_for_all => true, :tracker_ids => [1])
646 cf2 = IssueCustomField.create!(:name => 'Readonly field',
646 cf2 = IssueCustomField.create!(:name => 'Readonly field',
647 :field_format => 'string',
647 :field_format => 'string',
648 :is_for_all => true, :tracker_ids => [1])
648 :is_for_all => true, :tracker_ids => [1])
649 WorkflowPermission.delete_all
649 WorkflowPermission.delete_all
650 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
650 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
651 :role_id => 1, :field_name => cf2.id.to_s,
651 :role_id => 1, :field_name => cf2.id.to_s,
652 :rule => 'readonly')
652 :rule => 'readonly')
653 user = User.find(2)
653 user = User.find(2)
654 issue = Issue.new(:project_id => 1, :tracker_id => 1)
654 issue = Issue.new(:project_id => 1, :tracker_id => 1)
655 assert_equal [cf2.id.to_s], issue.read_only_attribute_names(user)
655 assert_equal [cf2.id.to_s], issue.read_only_attribute_names(user)
656 assert_not_include cf2.id.to_s, issue.safe_attribute_names(user)
656 assert_not_include cf2.id.to_s, issue.safe_attribute_names(user)
657
657
658 issue.send :safe_attributes=, {'custom_field_values' => {
658 issue.send :safe_attributes=, {'custom_field_values' => {
659 cf1.id.to_s => 'value1', cf2.id.to_s => 'value2'
659 cf1.id.to_s => 'value1', cf2.id.to_s => 'value2'
660 }}, user
660 }}, user
661 assert_equal 'value1', issue.custom_field_value(cf1)
661 assert_equal 'value1', issue.custom_field_value(cf1)
662 assert_nil issue.custom_field_value(cf2)
662 assert_nil issue.custom_field_value(cf2)
663
663
664 issue.send :safe_attributes=, {'custom_fields' => [
664 issue.send :safe_attributes=, {'custom_fields' => [
665 {'id' => cf1.id.to_s, 'value' => 'valuea'},
665 {'id' => cf1.id.to_s, 'value' => 'valuea'},
666 {'id' => cf2.id.to_s, 'value' => 'valueb'}
666 {'id' => cf2.id.to_s, 'value' => 'valueb'}
667 ]}, user
667 ]}, user
668 assert_equal 'valuea', issue.custom_field_value(cf1)
668 assert_equal 'valuea', issue.custom_field_value(cf1)
669 assert_nil issue.custom_field_value(cf2)
669 assert_nil issue.custom_field_value(cf2)
670 end
670 end
671
671
672 def test_editable_custom_field_values_should_return_non_readonly_custom_values
672 def test_editable_custom_field_values_should_return_non_readonly_custom_values
673 cf1 = IssueCustomField.create!(:name => 'Writable field', :field_format => 'string',
673 cf1 = IssueCustomField.create!(:name => 'Writable field', :field_format => 'string',
674 :is_for_all => true, :tracker_ids => [1, 2])
674 :is_for_all => true, :tracker_ids => [1, 2])
675 cf2 = IssueCustomField.create!(:name => 'Readonly field', :field_format => 'string',
675 cf2 = IssueCustomField.create!(:name => 'Readonly field', :field_format => 'string',
676 :is_for_all => true, :tracker_ids => [1, 2])
676 :is_for_all => true, :tracker_ids => [1, 2])
677 WorkflowPermission.delete_all
677 WorkflowPermission.delete_all
678 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, :role_id => 1,
678 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, :role_id => 1,
679 :field_name => cf2.id.to_s, :rule => 'readonly')
679 :field_name => cf2.id.to_s, :rule => 'readonly')
680 user = User.find(2)
680 user = User.find(2)
681
681
682 issue = Issue.new(:project_id => 1, :tracker_id => 1)
682 issue = Issue.new(:project_id => 1, :tracker_id => 1)
683 values = issue.editable_custom_field_values(user)
683 values = issue.editable_custom_field_values(user)
684 assert values.detect {|value| value.custom_field == cf1}
684 assert values.detect {|value| value.custom_field == cf1}
685 assert_nil values.detect {|value| value.custom_field == cf2}
685 assert_nil values.detect {|value| value.custom_field == cf2}
686
686
687 issue.tracker_id = 2
687 issue.tracker_id = 2
688 values = issue.editable_custom_field_values(user)
688 values = issue.editable_custom_field_values(user)
689 assert values.detect {|value| value.custom_field == cf1}
689 assert values.detect {|value| value.custom_field == cf1}
690 assert values.detect {|value| value.custom_field == cf2}
690 assert values.detect {|value| value.custom_field == cf2}
691 end
691 end
692
692
693 def test_safe_attributes_should_accept_target_tracker_writable_fields
693 def test_safe_attributes_should_accept_target_tracker_writable_fields
694 WorkflowPermission.delete_all
694 WorkflowPermission.delete_all
695 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
695 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
696 :role_id => 1, :field_name => 'due_date',
696 :role_id => 1, :field_name => 'due_date',
697 :rule => 'readonly')
697 :rule => 'readonly')
698 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2,
698 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2,
699 :role_id => 1, :field_name => 'start_date',
699 :role_id => 1, :field_name => 'start_date',
700 :rule => 'readonly')
700 :rule => 'readonly')
701 user = User.find(2)
701 user = User.find(2)
702
702
703 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1)
703 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1)
704
704
705 issue.send :safe_attributes=, {'start_date' => '2012-07-12',
705 issue.send :safe_attributes=, {'start_date' => '2012-07-12',
706 'due_date' => '2012-07-14'}, user
706 'due_date' => '2012-07-14'}, user
707 assert_equal Date.parse('2012-07-12'), issue.start_date
707 assert_equal Date.parse('2012-07-12'), issue.start_date
708 assert_nil issue.due_date
708 assert_nil issue.due_date
709
709
710 issue.send :safe_attributes=, {'start_date' => '2012-07-15',
710 issue.send :safe_attributes=, {'start_date' => '2012-07-15',
711 'due_date' => '2012-07-16',
711 'due_date' => '2012-07-16',
712 'tracker_id' => 2}, user
712 'tracker_id' => 2}, user
713 assert_equal Date.parse('2012-07-12'), issue.start_date
713 assert_equal Date.parse('2012-07-12'), issue.start_date
714 assert_equal Date.parse('2012-07-16'), issue.due_date
714 assert_equal Date.parse('2012-07-16'), issue.due_date
715 end
715 end
716
716
717 def test_safe_attributes_should_accept_target_status_writable_fields
717 def test_safe_attributes_should_accept_target_status_writable_fields
718 WorkflowPermission.delete_all
718 WorkflowPermission.delete_all
719 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
719 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
720 :role_id => 1, :field_name => 'due_date',
720 :role_id => 1, :field_name => 'due_date',
721 :rule => 'readonly')
721 :rule => 'readonly')
722 WorkflowPermission.create!(:old_status_id => 2, :tracker_id => 1,
722 WorkflowPermission.create!(:old_status_id => 2, :tracker_id => 1,
723 :role_id => 1, :field_name => 'start_date',
723 :role_id => 1, :field_name => 'start_date',
724 :rule => 'readonly')
724 :rule => 'readonly')
725 user = User.find(2)
725 user = User.find(2)
726
726
727 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1)
727 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1)
728
728
729 issue.send :safe_attributes=, {'start_date' => '2012-07-12',
729 issue.send :safe_attributes=, {'start_date' => '2012-07-12',
730 'due_date' => '2012-07-14'},
730 'due_date' => '2012-07-14'},
731 user
731 user
732 assert_equal Date.parse('2012-07-12'), issue.start_date
732 assert_equal Date.parse('2012-07-12'), issue.start_date
733 assert_nil issue.due_date
733 assert_nil issue.due_date
734
734
735 issue.send :safe_attributes=, {'start_date' => '2012-07-15',
735 issue.send :safe_attributes=, {'start_date' => '2012-07-15',
736 'due_date' => '2012-07-16',
736 'due_date' => '2012-07-16',
737 'status_id' => 2},
737 'status_id' => 2},
738 user
738 user
739 assert_equal Date.parse('2012-07-12'), issue.start_date
739 assert_equal Date.parse('2012-07-12'), issue.start_date
740 assert_equal Date.parse('2012-07-16'), issue.due_date
740 assert_equal Date.parse('2012-07-16'), issue.due_date
741 end
741 end
742
742
743 def test_required_attributes_should_be_validated
743 def test_required_attributes_should_be_validated
744 cf = IssueCustomField.create!(:name => 'Foo', :field_format => 'string',
744 cf = IssueCustomField.create!(:name => 'Foo', :field_format => 'string',
745 :is_for_all => true, :tracker_ids => [1, 2])
745 :is_for_all => true, :tracker_ids => [1, 2])
746
746
747 WorkflowPermission.delete_all
747 WorkflowPermission.delete_all
748 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
748 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
749 :role_id => 1, :field_name => 'due_date',
749 :role_id => 1, :field_name => 'due_date',
750 :rule => 'required')
750 :rule => 'required')
751 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
751 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
752 :role_id => 1, :field_name => 'category_id',
752 :role_id => 1, :field_name => 'category_id',
753 :rule => 'required')
753 :rule => 'required')
754 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
754 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
755 :role_id => 1, :field_name => cf.id.to_s,
755 :role_id => 1, :field_name => cf.id.to_s,
756 :rule => 'required')
756 :rule => 'required')
757
757
758 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2,
758 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2,
759 :role_id => 1, :field_name => 'start_date',
759 :role_id => 1, :field_name => 'start_date',
760 :rule => 'required')
760 :rule => 'required')
761 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2,
761 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2,
762 :role_id => 1, :field_name => cf.id.to_s,
762 :role_id => 1, :field_name => cf.id.to_s,
763 :rule => 'required')
763 :rule => 'required')
764 user = User.find(2)
764 user = User.find(2)
765
765
766 issue = Issue.new(:project_id => 1, :tracker_id => 1,
766 issue = Issue.new(:project_id => 1, :tracker_id => 1,
767 :status_id => 1, :subject => 'Required fields',
767 :status_id => 1, :subject => 'Required fields',
768 :author => user)
768 :author => user)
769 assert_equal [cf.id.to_s, "category_id", "due_date"],
769 assert_equal [cf.id.to_s, "category_id", "due_date"],
770 issue.required_attribute_names(user).sort
770 issue.required_attribute_names(user).sort
771 assert !issue.save, "Issue was saved"
771 assert !issue.save, "Issue was saved"
772 assert_equal ["Category can't be blank", "Due date can't be blank", "Foo can't be blank"],
772 assert_equal ["Category can't be blank", "Due date can't be blank", "Foo can't be blank"],
773 issue.errors.full_messages.sort
773 issue.errors.full_messages.sort
774
774
775 issue.tracker_id = 2
775 issue.tracker_id = 2
776 assert_equal [cf.id.to_s, "start_date"], issue.required_attribute_names(user).sort
776 assert_equal [cf.id.to_s, "start_date"], issue.required_attribute_names(user).sort
777 assert !issue.save, "Issue was saved"
777 assert !issue.save, "Issue was saved"
778 assert_equal ["Foo can't be blank", "Start date can't be blank"],
778 assert_equal ["Foo can't be blank", "Start date can't be blank"],
779 issue.errors.full_messages.sort
779 issue.errors.full_messages.sort
780
780
781 issue.start_date = Date.today
781 issue.start_date = Date.today
782 issue.custom_field_values = {cf.id.to_s => 'bar'}
782 issue.custom_field_values = {cf.id.to_s => 'bar'}
783 assert issue.save
783 assert issue.save
784 end
784 end
785
785
786 def test_required_attribute_names_for_multiple_roles_should_intersect_rules
786 def test_required_attribute_names_for_multiple_roles_should_intersect_rules
787 WorkflowPermission.delete_all
787 WorkflowPermission.delete_all
788 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
788 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
789 :role_id => 1, :field_name => 'due_date',
789 :role_id => 1, :field_name => 'due_date',
790 :rule => 'required')
790 :rule => 'required')
791 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
791 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
792 :role_id => 1, :field_name => 'start_date',
792 :role_id => 1, :field_name => 'start_date',
793 :rule => 'required')
793 :rule => 'required')
794 user = User.find(2)
794 user = User.find(2)
795 member = Member.find(1)
795 member = Member.find(1)
796 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1)
796 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1)
797
797
798 assert_equal %w(due_date start_date), issue.required_attribute_names(user).sort
798 assert_equal %w(due_date start_date), issue.required_attribute_names(user).sort
799
799
800 member.role_ids = [1, 2]
800 member.role_ids = [1, 2]
801 member.save!
801 member.save!
802 assert_equal [], issue.required_attribute_names(user.reload)
802 assert_equal [], issue.required_attribute_names(user.reload)
803
803
804 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
804 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
805 :role_id => 2, :field_name => 'due_date',
805 :role_id => 2, :field_name => 'due_date',
806 :rule => 'required')
806 :rule => 'required')
807 assert_equal %w(due_date), issue.required_attribute_names(user)
807 assert_equal %w(due_date), issue.required_attribute_names(user)
808
808
809 member.role_ids = [1, 2, 3]
809 member.role_ids = [1, 2, 3]
810 member.save!
810 member.save!
811 assert_equal [], issue.required_attribute_names(user.reload)
811 assert_equal [], issue.required_attribute_names(user.reload)
812
812
813 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
813 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
814 :role_id => 2, :field_name => 'due_date',
814 :role_id => 2, :field_name => 'due_date',
815 :rule => 'readonly')
815 :rule => 'readonly')
816 # required + readonly => required
816 # required + readonly => required
817 assert_equal %w(due_date), issue.required_attribute_names(user)
817 assert_equal %w(due_date), issue.required_attribute_names(user)
818 end
818 end
819
819
820 def test_read_only_attribute_names_for_multiple_roles_should_intersect_rules
820 def test_read_only_attribute_names_for_multiple_roles_should_intersect_rules
821 WorkflowPermission.delete_all
821 WorkflowPermission.delete_all
822 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
822 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
823 :role_id => 1, :field_name => 'due_date',
823 :role_id => 1, :field_name => 'due_date',
824 :rule => 'readonly')
824 :rule => 'readonly')
825 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
825 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
826 :role_id => 1, :field_name => 'start_date',
826 :role_id => 1, :field_name => 'start_date',
827 :rule => 'readonly')
827 :rule => 'readonly')
828 user = User.find(2)
828 user = User.find(2)
829 member = Member.find(1)
829 member = Member.find(1)
830 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1)
830 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1)
831
831
832 assert_equal %w(due_date start_date), issue.read_only_attribute_names(user).sort
832 assert_equal %w(due_date start_date), issue.read_only_attribute_names(user).sort
833
833
834 member.role_ids = [1, 2]
834 member.role_ids = [1, 2]
835 member.save!
835 member.save!
836 assert_equal [], issue.read_only_attribute_names(user.reload)
836 assert_equal [], issue.read_only_attribute_names(user.reload)
837
837
838 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
838 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
839 :role_id => 2, :field_name => 'due_date',
839 :role_id => 2, :field_name => 'due_date',
840 :rule => 'readonly')
840 :rule => 'readonly')
841 assert_equal %w(due_date), issue.read_only_attribute_names(user)
841 assert_equal %w(due_date), issue.read_only_attribute_names(user)
842 end
842 end
843
843
844 def test_copy
844 def test_copy
845 issue = Issue.new.copy_from(1)
845 issue = Issue.new.copy_from(1)
846 assert issue.copy?
846 assert issue.copy?
847 assert issue.save
847 assert issue.save
848 issue.reload
848 issue.reload
849 orig = Issue.find(1)
849 orig = Issue.find(1)
850 assert_equal orig.subject, issue.subject
850 assert_equal orig.subject, issue.subject
851 assert_equal orig.tracker, issue.tracker
851 assert_equal orig.tracker, issue.tracker
852 assert_equal "125", issue.custom_value_for(2).value
852 assert_equal "125", issue.custom_value_for(2).value
853 end
853 end
854
854
855 def test_copy_should_copy_status
855 def test_copy_should_copy_status
856 orig = Issue.find(8)
856 orig = Issue.find(8)
857 assert orig.status != IssueStatus.default
857 assert orig.status != IssueStatus.default
858
858
859 issue = Issue.new.copy_from(orig)
859 issue = Issue.new.copy_from(orig)
860 assert issue.save
860 assert issue.save
861 issue.reload
861 issue.reload
862 assert_equal orig.status, issue.status
862 assert_equal orig.status, issue.status
863 end
863 end
864
864
865 def test_copy_should_add_relation_with_copied_issue
865 def test_copy_should_add_relation_with_copied_issue
866 copied = Issue.find(1)
866 copied = Issue.find(1)
867 issue = Issue.new.copy_from(copied)
867 issue = Issue.new.copy_from(copied)
868 assert issue.save
868 assert issue.save
869 issue.reload
869 issue.reload
870
870
871 assert_equal 1, issue.relations.size
871 assert_equal 1, issue.relations.size
872 relation = issue.relations.first
872 relation = issue.relations.first
873 assert_equal 'copied_to', relation.relation_type
873 assert_equal 'copied_to', relation.relation_type
874 assert_equal copied, relation.issue_from
874 assert_equal copied, relation.issue_from
875 assert_equal issue, relation.issue_to
875 assert_equal issue, relation.issue_to
876 end
876 end
877
877
878 def test_copy_should_copy_subtasks
878 def test_copy_should_copy_subtasks
879 issue = Issue.generate_with_descendants!
879 issue = Issue.generate_with_descendants!
880
880
881 copy = issue.reload.copy
881 copy = issue.reload.copy
882 copy.author = User.find(7)
882 copy.author = User.find(7)
883 assert_difference 'Issue.count', 1+issue.descendants.count do
883 assert_difference 'Issue.count', 1+issue.descendants.count do
884 assert copy.save
884 assert copy.save
885 end
885 end
886 copy.reload
886 copy.reload
887 assert_equal %w(Child1 Child2), copy.children.map(&:subject).sort
887 assert_equal %w(Child1 Child2), copy.children.map(&:subject).sort
888 child_copy = copy.children.detect {|c| c.subject == 'Child1'}
888 child_copy = copy.children.detect {|c| c.subject == 'Child1'}
889 assert_equal %w(Child11), child_copy.children.map(&:subject).sort
889 assert_equal %w(Child11), child_copy.children.map(&:subject).sort
890 assert_equal copy.author, child_copy.author
890 assert_equal copy.author, child_copy.author
891 end
891 end
892
892
893 def test_copy_as_a_child_of_copied_issue_should_not_copy_itself
893 def test_copy_as_a_child_of_copied_issue_should_not_copy_itself
894 parent = Issue.generate!
894 parent = Issue.generate!
895 child1 = Issue.generate!(:parent_issue_id => parent.id, :subject => 'Child 1')
895 child1 = Issue.generate!(:parent_issue_id => parent.id, :subject => 'Child 1')
896 child2 = Issue.generate!(:parent_issue_id => parent.id, :subject => 'Child 2')
896 child2 = Issue.generate!(:parent_issue_id => parent.id, :subject => 'Child 2')
897
897
898 copy = parent.reload.copy
898 copy = parent.reload.copy
899 copy.parent_issue_id = parent.id
899 copy.parent_issue_id = parent.id
900 copy.author = User.find(7)
900 copy.author = User.find(7)
901 assert_difference 'Issue.count', 3 do
901 assert_difference 'Issue.count', 3 do
902 assert copy.save
902 assert copy.save
903 end
903 end
904 parent.reload
904 parent.reload
905 copy.reload
905 copy.reload
906 assert_equal parent, copy.parent
906 assert_equal parent, copy.parent
907 assert_equal 3, parent.children.count
907 assert_equal 3, parent.children.count
908 assert_equal 5, parent.descendants.count
908 assert_equal 5, parent.descendants.count
909 assert_equal 2, copy.children.count
909 assert_equal 2, copy.children.count
910 assert_equal 2, copy.descendants.count
910 assert_equal 2, copy.descendants.count
911 end
911 end
912
912
913 def test_copy_as_a_descendant_of_copied_issue_should_not_copy_itself
913 def test_copy_as_a_descendant_of_copied_issue_should_not_copy_itself
914 parent = Issue.generate!
914 parent = Issue.generate!
915 child1 = Issue.generate!(:parent_issue_id => parent.id, :subject => 'Child 1')
915 child1 = Issue.generate!(:parent_issue_id => parent.id, :subject => 'Child 1')
916 child2 = Issue.generate!(:parent_issue_id => parent.id, :subject => 'Child 2')
916 child2 = Issue.generate!(:parent_issue_id => parent.id, :subject => 'Child 2')
917
917
918 copy = parent.reload.copy
918 copy = parent.reload.copy
919 copy.parent_issue_id = child1.id
919 copy.parent_issue_id = child1.id
920 copy.author = User.find(7)
920 copy.author = User.find(7)
921 assert_difference 'Issue.count', 3 do
921 assert_difference 'Issue.count', 3 do
922 assert copy.save
922 assert copy.save
923 end
923 end
924 parent.reload
924 parent.reload
925 child1.reload
925 child1.reload
926 copy.reload
926 copy.reload
927 assert_equal child1, copy.parent
927 assert_equal child1, copy.parent
928 assert_equal 2, parent.children.count
928 assert_equal 2, parent.children.count
929 assert_equal 5, parent.descendants.count
929 assert_equal 5, parent.descendants.count
930 assert_equal 1, child1.children.count
930 assert_equal 1, child1.children.count
931 assert_equal 3, child1.descendants.count
931 assert_equal 3, child1.descendants.count
932 assert_equal 2, copy.children.count
932 assert_equal 2, copy.children.count
933 assert_equal 2, copy.descendants.count
933 assert_equal 2, copy.descendants.count
934 end
934 end
935
935
936 def test_copy_should_copy_subtasks_to_target_project
936 def test_copy_should_copy_subtasks_to_target_project
937 issue = Issue.generate_with_descendants!
937 issue = Issue.generate_with_descendants!
938
938
939 copy = issue.copy(:project_id => 3)
939 copy = issue.copy(:project_id => 3)
940 assert_difference 'Issue.count', 1+issue.descendants.count do
940 assert_difference 'Issue.count', 1+issue.descendants.count do
941 assert copy.save
941 assert copy.save
942 end
942 end
943 assert_equal [3], copy.reload.descendants.map(&:project_id).uniq
943 assert_equal [3], copy.reload.descendants.map(&:project_id).uniq
944 end
944 end
945
945
946 def test_copy_should_not_copy_subtasks_twice_when_saving_twice
946 def test_copy_should_not_copy_subtasks_twice_when_saving_twice
947 issue = Issue.generate_with_descendants!
947 issue = Issue.generate_with_descendants!
948
948
949 copy = issue.reload.copy
949 copy = issue.reload.copy
950 assert_difference 'Issue.count', 1+issue.descendants.count do
950 assert_difference 'Issue.count', 1+issue.descendants.count do
951 assert copy.save
951 assert copy.save
952 assert copy.save
952 assert copy.save
953 end
953 end
954 end
954 end
955
955
956 def test_should_not_call_after_project_change_on_creation
956 def test_should_not_call_after_project_change_on_creation
957 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1,
957 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1,
958 :subject => 'Test', :author_id => 1)
958 :subject => 'Test', :author_id => 1)
959 issue.expects(:after_project_change).never
959 issue.expects(:after_project_change).never
960 issue.save!
960 issue.save!
961 end
961 end
962
962
963 def test_should_not_call_after_project_change_on_update
963 def test_should_not_call_after_project_change_on_update
964 issue = Issue.find(1)
964 issue = Issue.find(1)
965 issue.project = Project.find(1)
965 issue.project = Project.find(1)
966 issue.subject = 'No project change'
966 issue.subject = 'No project change'
967 issue.expects(:after_project_change).never
967 issue.expects(:after_project_change).never
968 issue.save!
968 issue.save!
969 end
969 end
970
970
971 def test_should_call_after_project_change_on_project_change
971 def test_should_call_after_project_change_on_project_change
972 issue = Issue.find(1)
972 issue = Issue.find(1)
973 issue.project = Project.find(2)
973 issue.project = Project.find(2)
974 issue.expects(:after_project_change).once
974 issue.expects(:after_project_change).once
975 issue.save!
975 issue.save!
976 end
976 end
977
977
978 def test_adding_journal_should_update_timestamp
978 def test_adding_journal_should_update_timestamp
979 issue = Issue.find(1)
979 issue = Issue.find(1)
980 updated_on_was = issue.updated_on
980 updated_on_was = issue.updated_on
981
981
982 issue.init_journal(User.first, "Adding notes")
982 issue.init_journal(User.first, "Adding notes")
983 assert_difference 'Journal.count' do
983 assert_difference 'Journal.count' do
984 assert issue.save
984 assert issue.save
985 end
985 end
986 issue.reload
986 issue.reload
987
987
988 assert_not_equal updated_on_was, issue.updated_on
988 assert_not_equal updated_on_was, issue.updated_on
989 end
989 end
990
990
991 def test_should_close_duplicates
991 def test_should_close_duplicates
992 # Create 3 issues
992 # Create 3 issues
993 issue1 = Issue.generate!
993 issue1 = Issue.generate!
994 issue2 = Issue.generate!
994 issue2 = Issue.generate!
995 issue3 = Issue.generate!
995 issue3 = Issue.generate!
996
996
997 # 2 is a dupe of 1
997 # 2 is a dupe of 1
998 IssueRelation.create!(:issue_from => issue2, :issue_to => issue1,
998 IssueRelation.create!(:issue_from => issue2, :issue_to => issue1,
999 :relation_type => IssueRelation::TYPE_DUPLICATES)
999 :relation_type => IssueRelation::TYPE_DUPLICATES)
1000 # And 3 is a dupe of 2
1000 # And 3 is a dupe of 2
1001 IssueRelation.create!(:issue_from => issue3, :issue_to => issue2,
1001 IssueRelation.create!(:issue_from => issue3, :issue_to => issue2,
1002 :relation_type => IssueRelation::TYPE_DUPLICATES)
1002 :relation_type => IssueRelation::TYPE_DUPLICATES)
1003 # And 3 is a dupe of 1 (circular duplicates)
1003 # And 3 is a dupe of 1 (circular duplicates)
1004 IssueRelation.create!(:issue_from => issue3, :issue_to => issue1,
1004 IssueRelation.create!(:issue_from => issue3, :issue_to => issue1,
1005 :relation_type => IssueRelation::TYPE_DUPLICATES)
1005 :relation_type => IssueRelation::TYPE_DUPLICATES)
1006
1006
1007 assert issue1.reload.duplicates.include?(issue2)
1007 assert issue1.reload.duplicates.include?(issue2)
1008
1008
1009 # Closing issue 1
1009 # Closing issue 1
1010 issue1.init_journal(User.first, "Closing issue1")
1010 issue1.init_journal(User.first, "Closing issue1")
1011 issue1.status = IssueStatus.where(:is_closed => true).first
1011 issue1.status = IssueStatus.where(:is_closed => true).first
1012 assert issue1.save
1012 assert issue1.save
1013 # 2 and 3 should be also closed
1013 # 2 and 3 should be also closed
1014 assert issue2.reload.closed?
1014 assert issue2.reload.closed?
1015 assert issue3.reload.closed?
1015 assert issue3.reload.closed?
1016 end
1016 end
1017
1017
1018 def test_should_not_close_duplicated_issue
1018 def test_should_not_close_duplicated_issue
1019 issue1 = Issue.generate!
1019 issue1 = Issue.generate!
1020 issue2 = Issue.generate!
1020 issue2 = Issue.generate!
1021
1021
1022 # 2 is a dupe of 1
1022 # 2 is a dupe of 1
1023 IssueRelation.create(:issue_from => issue2, :issue_to => issue1,
1023 IssueRelation.create(:issue_from => issue2, :issue_to => issue1,
1024 :relation_type => IssueRelation::TYPE_DUPLICATES)
1024 :relation_type => IssueRelation::TYPE_DUPLICATES)
1025 # 2 is a dup of 1 but 1 is not a duplicate of 2
1025 # 2 is a dup of 1 but 1 is not a duplicate of 2
1026 assert !issue2.reload.duplicates.include?(issue1)
1026 assert !issue2.reload.duplicates.include?(issue1)
1027
1027
1028 # Closing issue 2
1028 # Closing issue 2
1029 issue2.init_journal(User.first, "Closing issue2")
1029 issue2.init_journal(User.first, "Closing issue2")
1030 issue2.status = IssueStatus.where(:is_closed => true).first
1030 issue2.status = IssueStatus.where(:is_closed => true).first
1031 assert issue2.save
1031 assert issue2.save
1032 # 1 should not be also closed
1032 # 1 should not be also closed
1033 assert !issue1.reload.closed?
1033 assert !issue1.reload.closed?
1034 end
1034 end
1035
1035
1036 def test_assignable_versions
1036 def test_assignable_versions
1037 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
1037 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
1038 :status_id => 1, :fixed_version_id => 1,
1038 :status_id => 1, :fixed_version_id => 1,
1039 :subject => 'New issue')
1039 :subject => 'New issue')
1040 assert_equal ['open'], issue.assignable_versions.collect(&:status).uniq
1040 assert_equal ['open'], issue.assignable_versions.collect(&:status).uniq
1041 end
1041 end
1042
1042
1043 def test_should_not_be_able_to_assign_a_new_issue_to_a_closed_version
1043 def test_should_not_be_able_to_assign_a_new_issue_to_a_closed_version
1044 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
1044 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
1045 :status_id => 1, :fixed_version_id => 1,
1045 :status_id => 1, :fixed_version_id => 1,
1046 :subject => 'New issue')
1046 :subject => 'New issue')
1047 assert !issue.save
1047 assert !issue.save
1048 assert_not_nil issue.errors[:fixed_version_id]
1048 assert_not_equal [], issue.errors[:fixed_version_id]
1049 end
1049 end
1050
1050
1051 def test_should_not_be_able_to_assign_a_new_issue_to_a_locked_version
1051 def test_should_not_be_able_to_assign_a_new_issue_to_a_locked_version
1052 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
1052 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
1053 :status_id => 1, :fixed_version_id => 2,
1053 :status_id => 1, :fixed_version_id => 2,
1054 :subject => 'New issue')
1054 :subject => 'New issue')
1055 assert !issue.save
1055 assert !issue.save
1056 assert_not_nil issue.errors[:fixed_version_id]
1056 assert_not_equal [], issue.errors[:fixed_version_id]
1057 end
1057 end
1058
1058
1059 def test_should_be_able_to_assign_a_new_issue_to_an_open_version
1059 def test_should_be_able_to_assign_a_new_issue_to_an_open_version
1060 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
1060 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
1061 :status_id => 1, :fixed_version_id => 3,
1061 :status_id => 1, :fixed_version_id => 3,
1062 :subject => 'New issue')
1062 :subject => 'New issue')
1063 assert issue.save
1063 assert issue.save
1064 end
1064 end
1065
1065
1066 def test_should_be_able_to_update_an_issue_assigned_to_a_closed_version
1066 def test_should_be_able_to_update_an_issue_assigned_to_a_closed_version
1067 issue = Issue.find(11)
1067 issue = Issue.find(11)
1068 assert_equal 'closed', issue.fixed_version.status
1068 assert_equal 'closed', issue.fixed_version.status
1069 issue.subject = 'Subject changed'
1069 issue.subject = 'Subject changed'
1070 assert issue.save
1070 assert issue.save
1071 end
1071 end
1072
1072
1073 def test_should_not_be_able_to_reopen_an_issue_assigned_to_a_closed_version
1073 def test_should_not_be_able_to_reopen_an_issue_assigned_to_a_closed_version
1074 issue = Issue.find(11)
1074 issue = Issue.find(11)
1075 issue.status_id = 1
1075 issue.status_id = 1
1076 assert !issue.save
1076 assert !issue.save
1077 assert_not_nil issue.errors[:base]
1077 assert_not_equal [], issue.errors[:base]
1078 end
1078 end
1079
1079
1080 def test_should_be_able_to_reopen_and_reassign_an_issue_assigned_to_a_closed_version
1080 def test_should_be_able_to_reopen_and_reassign_an_issue_assigned_to_a_closed_version
1081 issue = Issue.find(11)
1081 issue = Issue.find(11)
1082 issue.status_id = 1
1082 issue.status_id = 1
1083 issue.fixed_version_id = 3
1083 issue.fixed_version_id = 3
1084 assert issue.save
1084 assert issue.save
1085 end
1085 end
1086
1086
1087 def test_should_be_able_to_reopen_an_issue_assigned_to_a_locked_version
1087 def test_should_be_able_to_reopen_an_issue_assigned_to_a_locked_version
1088 issue = Issue.find(12)
1088 issue = Issue.find(12)
1089 assert_equal 'locked', issue.fixed_version.status
1089 assert_equal 'locked', issue.fixed_version.status
1090 issue.status_id = 1
1090 issue.status_id = 1
1091 assert issue.save
1091 assert issue.save
1092 end
1092 end
1093
1093
1094 def test_should_not_be_able_to_keep_unshared_version_when_changing_project
1094 def test_should_not_be_able_to_keep_unshared_version_when_changing_project
1095 issue = Issue.find(2)
1095 issue = Issue.find(2)
1096 assert_equal 2, issue.fixed_version_id
1096 assert_equal 2, issue.fixed_version_id
1097 issue.project_id = 3
1097 issue.project_id = 3
1098 assert_nil issue.fixed_version_id
1098 assert_nil issue.fixed_version_id
1099 issue.fixed_version_id = 2
1099 issue.fixed_version_id = 2
1100 assert !issue.save
1100 assert !issue.save
1101 assert_include 'Target version is not included in the list', issue.errors.full_messages
1101 assert_include 'Target version is not included in the list', issue.errors.full_messages
1102 end
1102 end
1103
1103
1104 def test_should_keep_shared_version_when_changing_project
1104 def test_should_keep_shared_version_when_changing_project
1105 Version.find(2).update_attribute :sharing, 'tree'
1105 Version.find(2).update_attribute :sharing, 'tree'
1106
1106
1107 issue = Issue.find(2)
1107 issue = Issue.find(2)
1108 assert_equal 2, issue.fixed_version_id
1108 assert_equal 2, issue.fixed_version_id
1109 issue.project_id = 3
1109 issue.project_id = 3
1110 assert_equal 2, issue.fixed_version_id
1110 assert_equal 2, issue.fixed_version_id
1111 assert issue.save
1111 assert issue.save
1112 end
1112 end
1113
1113
1114 def test_allowed_target_projects_on_move_should_include_projects_with_issue_tracking_enabled
1114 def test_allowed_target_projects_on_move_should_include_projects_with_issue_tracking_enabled
1115 assert_include Project.find(2), Issue.allowed_target_projects_on_move(User.find(2))
1115 assert_include Project.find(2), Issue.allowed_target_projects_on_move(User.find(2))
1116 end
1116 end
1117
1117
1118 def test_allowed_target_projects_on_move_should_not_include_projects_with_issue_tracking_disabled
1118 def test_allowed_target_projects_on_move_should_not_include_projects_with_issue_tracking_disabled
1119 Project.find(2).disable_module! :issue_tracking
1119 Project.find(2).disable_module! :issue_tracking
1120 assert_not_include Project.find(2), Issue.allowed_target_projects_on_move(User.find(2))
1120 assert_not_include Project.find(2), Issue.allowed_target_projects_on_move(User.find(2))
1121 end
1121 end
1122
1122
1123 def test_move_to_another_project_with_same_category
1123 def test_move_to_another_project_with_same_category
1124 issue = Issue.find(1)
1124 issue = Issue.find(1)
1125 issue.project = Project.find(2)
1125 issue.project = Project.find(2)
1126 assert issue.save
1126 assert issue.save
1127 issue.reload
1127 issue.reload
1128 assert_equal 2, issue.project_id
1128 assert_equal 2, issue.project_id
1129 # Category changes
1129 # Category changes
1130 assert_equal 4, issue.category_id
1130 assert_equal 4, issue.category_id
1131 # Make sure time entries were move to the target project
1131 # Make sure time entries were move to the target project
1132 assert_equal 2, issue.time_entries.first.project_id
1132 assert_equal 2, issue.time_entries.first.project_id
1133 end
1133 end
1134
1134
1135 def test_move_to_another_project_without_same_category
1135 def test_move_to_another_project_without_same_category
1136 issue = Issue.find(2)
1136 issue = Issue.find(2)
1137 issue.project = Project.find(2)
1137 issue.project = Project.find(2)
1138 assert issue.save
1138 assert issue.save
1139 issue.reload
1139 issue.reload
1140 assert_equal 2, issue.project_id
1140 assert_equal 2, issue.project_id
1141 # Category cleared
1141 # Category cleared
1142 assert_nil issue.category_id
1142 assert_nil issue.category_id
1143 end
1143 end
1144
1144
1145 def test_move_to_another_project_should_clear_fixed_version_when_not_shared
1145 def test_move_to_another_project_should_clear_fixed_version_when_not_shared
1146 issue = Issue.find(1)
1146 issue = Issue.find(1)
1147 issue.update_attribute(:fixed_version_id, 1)
1147 issue.update_attribute(:fixed_version_id, 1)
1148 issue.project = Project.find(2)
1148 issue.project = Project.find(2)
1149 assert issue.save
1149 assert issue.save
1150 issue.reload
1150 issue.reload
1151 assert_equal 2, issue.project_id
1151 assert_equal 2, issue.project_id
1152 # Cleared fixed_version
1152 # Cleared fixed_version
1153 assert_equal nil, issue.fixed_version
1153 assert_equal nil, issue.fixed_version
1154 end
1154 end
1155
1155
1156 def test_move_to_another_project_should_keep_fixed_version_when_shared_with_the_target_project
1156 def test_move_to_another_project_should_keep_fixed_version_when_shared_with_the_target_project
1157 issue = Issue.find(1)
1157 issue = Issue.find(1)
1158 issue.update_attribute(:fixed_version_id, 4)
1158 issue.update_attribute(:fixed_version_id, 4)
1159 issue.project = Project.find(5)
1159 issue.project = Project.find(5)
1160 assert issue.save
1160 assert issue.save
1161 issue.reload
1161 issue.reload
1162 assert_equal 5, issue.project_id
1162 assert_equal 5, issue.project_id
1163 # Keep fixed_version
1163 # Keep fixed_version
1164 assert_equal 4, issue.fixed_version_id
1164 assert_equal 4, issue.fixed_version_id
1165 end
1165 end
1166
1166
1167 def test_move_to_another_project_should_clear_fixed_version_when_not_shared_with_the_target_project
1167 def test_move_to_another_project_should_clear_fixed_version_when_not_shared_with_the_target_project
1168 issue = Issue.find(1)
1168 issue = Issue.find(1)
1169 issue.update_attribute(:fixed_version_id, 1)
1169 issue.update_attribute(:fixed_version_id, 1)
1170 issue.project = Project.find(5)
1170 issue.project = Project.find(5)
1171 assert issue.save
1171 assert issue.save
1172 issue.reload
1172 issue.reload
1173 assert_equal 5, issue.project_id
1173 assert_equal 5, issue.project_id
1174 # Cleared fixed_version
1174 # Cleared fixed_version
1175 assert_equal nil, issue.fixed_version
1175 assert_equal nil, issue.fixed_version
1176 end
1176 end
1177
1177
1178 def test_move_to_another_project_should_keep_fixed_version_when_shared_systemwide
1178 def test_move_to_another_project_should_keep_fixed_version_when_shared_systemwide
1179 issue = Issue.find(1)
1179 issue = Issue.find(1)
1180 issue.update_attribute(:fixed_version_id, 7)
1180 issue.update_attribute(:fixed_version_id, 7)
1181 issue.project = Project.find(2)
1181 issue.project = Project.find(2)
1182 assert issue.save
1182 assert issue.save
1183 issue.reload
1183 issue.reload
1184 assert_equal 2, issue.project_id
1184 assert_equal 2, issue.project_id
1185 # Keep fixed_version
1185 # Keep fixed_version
1186 assert_equal 7, issue.fixed_version_id
1186 assert_equal 7, issue.fixed_version_id
1187 end
1187 end
1188
1188
1189 def test_move_to_another_project_should_keep_parent_if_valid
1189 def test_move_to_another_project_should_keep_parent_if_valid
1190 issue = Issue.find(1)
1190 issue = Issue.find(1)
1191 issue.update_attribute(:parent_issue_id, 2)
1191 issue.update_attribute(:parent_issue_id, 2)
1192 issue.project = Project.find(3)
1192 issue.project = Project.find(3)
1193 assert issue.save
1193 assert issue.save
1194 issue.reload
1194 issue.reload
1195 assert_equal 2, issue.parent_id
1195 assert_equal 2, issue.parent_id
1196 end
1196 end
1197
1197
1198 def test_move_to_another_project_should_clear_parent_if_not_valid
1198 def test_move_to_another_project_should_clear_parent_if_not_valid
1199 issue = Issue.find(1)
1199 issue = Issue.find(1)
1200 issue.update_attribute(:parent_issue_id, 2)
1200 issue.update_attribute(:parent_issue_id, 2)
1201 issue.project = Project.find(2)
1201 issue.project = Project.find(2)
1202 assert issue.save
1202 assert issue.save
1203 issue.reload
1203 issue.reload
1204 assert_nil issue.parent_id
1204 assert_nil issue.parent_id
1205 end
1205 end
1206
1206
1207 def test_move_to_another_project_with_disabled_tracker
1207 def test_move_to_another_project_with_disabled_tracker
1208 issue = Issue.find(1)
1208 issue = Issue.find(1)
1209 target = Project.find(2)
1209 target = Project.find(2)
1210 target.tracker_ids = [3]
1210 target.tracker_ids = [3]
1211 target.save
1211 target.save
1212 issue.project = target
1212 issue.project = target
1213 assert issue.save
1213 assert issue.save
1214 issue.reload
1214 issue.reload
1215 assert_equal 2, issue.project_id
1215 assert_equal 2, issue.project_id
1216 assert_equal 3, issue.tracker_id
1216 assert_equal 3, issue.tracker_id
1217 end
1217 end
1218
1218
1219 def test_copy_to_the_same_project
1219 def test_copy_to_the_same_project
1220 issue = Issue.find(1)
1220 issue = Issue.find(1)
1221 copy = issue.copy
1221 copy = issue.copy
1222 assert_difference 'Issue.count' do
1222 assert_difference 'Issue.count' do
1223 copy.save!
1223 copy.save!
1224 end
1224 end
1225 assert_kind_of Issue, copy
1225 assert_kind_of Issue, copy
1226 assert_equal issue.project, copy.project
1226 assert_equal issue.project, copy.project
1227 assert_equal "125", copy.custom_value_for(2).value
1227 assert_equal "125", copy.custom_value_for(2).value
1228 end
1228 end
1229
1229
1230 def test_copy_to_another_project_and_tracker
1230 def test_copy_to_another_project_and_tracker
1231 issue = Issue.find(1)
1231 issue = Issue.find(1)
1232 copy = issue.copy(:project_id => 3, :tracker_id => 2)
1232 copy = issue.copy(:project_id => 3, :tracker_id => 2)
1233 assert_difference 'Issue.count' do
1233 assert_difference 'Issue.count' do
1234 copy.save!
1234 copy.save!
1235 end
1235 end
1236 copy.reload
1236 copy.reload
1237 assert_kind_of Issue, copy
1237 assert_kind_of Issue, copy
1238 assert_equal Project.find(3), copy.project
1238 assert_equal Project.find(3), copy.project
1239 assert_equal Tracker.find(2), copy.tracker
1239 assert_equal Tracker.find(2), copy.tracker
1240 # Custom field #2 is not associated with target tracker
1240 # Custom field #2 is not associated with target tracker
1241 assert_nil copy.custom_value_for(2)
1241 assert_nil copy.custom_value_for(2)
1242 end
1242 end
1243
1243
1244 test "#copy should not create a journal" do
1244 test "#copy should not create a journal" do
1245 copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2, :assigned_to_id => 3)
1245 copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2, :assigned_to_id => 3)
1246 copy.save!
1246 copy.save!
1247 assert_equal 0, copy.reload.journals.size
1247 assert_equal 0, copy.reload.journals.size
1248 end
1248 end
1249
1249
1250 test "#copy should allow assigned_to changes" do
1250 test "#copy should allow assigned_to changes" do
1251 copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2, :assigned_to_id => 3)
1251 copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2, :assigned_to_id => 3)
1252 assert_equal 3, copy.assigned_to_id
1252 assert_equal 3, copy.assigned_to_id
1253 end
1253 end
1254
1254
1255 test "#copy should allow status changes" do
1255 test "#copy should allow status changes" do
1256 copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2, :status_id => 2)
1256 copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2, :status_id => 2)
1257 assert_equal 2, copy.status_id
1257 assert_equal 2, copy.status_id
1258 end
1258 end
1259
1259
1260 test "#copy should allow start date changes" do
1260 test "#copy should allow start date changes" do
1261 date = Date.today
1261 date = Date.today
1262 copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2, :start_date => date)
1262 copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2, :start_date => date)
1263 assert_equal date, copy.start_date
1263 assert_equal date, copy.start_date
1264 end
1264 end
1265
1265
1266 test "#copy should allow due date changes" do
1266 test "#copy should allow due date changes" do
1267 date = Date.today
1267 date = Date.today
1268 copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2, :due_date => date)
1268 copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2, :due_date => date)
1269 assert_equal date, copy.due_date
1269 assert_equal date, copy.due_date
1270 end
1270 end
1271
1271
1272 test "#copy should set current user as author" do
1272 test "#copy should set current user as author" do
1273 User.current = User.find(9)
1273 User.current = User.find(9)
1274 copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2)
1274 copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2)
1275 assert_equal User.current, copy.author
1275 assert_equal User.current, copy.author
1276 end
1276 end
1277
1277
1278 test "#copy should create a journal with notes" do
1278 test "#copy should create a journal with notes" do
1279 date = Date.today
1279 date = Date.today
1280 notes = "Notes added when copying"
1280 notes = "Notes added when copying"
1281 copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2, :start_date => date)
1281 copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2, :start_date => date)
1282 copy.init_journal(User.current, notes)
1282 copy.init_journal(User.current, notes)
1283 copy.save!
1283 copy.save!
1284
1284
1285 assert_equal 1, copy.journals.size
1285 assert_equal 1, copy.journals.size
1286 journal = copy.journals.first
1286 journal = copy.journals.first
1287 assert_equal 0, journal.details.size
1287 assert_equal 0, journal.details.size
1288 assert_equal notes, journal.notes
1288 assert_equal notes, journal.notes
1289 end
1289 end
1290
1290
1291 def test_valid_parent_project
1291 def test_valid_parent_project
1292 issue = Issue.find(1)
1292 issue = Issue.find(1)
1293 issue_in_same_project = Issue.find(2)
1293 issue_in_same_project = Issue.find(2)
1294 issue_in_child_project = Issue.find(5)
1294 issue_in_child_project = Issue.find(5)
1295 issue_in_grandchild_project = Issue.generate!(:project_id => 6, :tracker_id => 1)
1295 issue_in_grandchild_project = Issue.generate!(:project_id => 6, :tracker_id => 1)
1296 issue_in_other_child_project = Issue.find(6)
1296 issue_in_other_child_project = Issue.find(6)
1297 issue_in_different_tree = Issue.find(4)
1297 issue_in_different_tree = Issue.find(4)
1298
1298
1299 with_settings :cross_project_subtasks => '' do
1299 with_settings :cross_project_subtasks => '' do
1300 assert_equal true, issue.valid_parent_project?(issue_in_same_project)
1300 assert_equal true, issue.valid_parent_project?(issue_in_same_project)
1301 assert_equal false, issue.valid_parent_project?(issue_in_child_project)
1301 assert_equal false, issue.valid_parent_project?(issue_in_child_project)
1302 assert_equal false, issue.valid_parent_project?(issue_in_grandchild_project)
1302 assert_equal false, issue.valid_parent_project?(issue_in_grandchild_project)
1303 assert_equal false, issue.valid_parent_project?(issue_in_different_tree)
1303 assert_equal false, issue.valid_parent_project?(issue_in_different_tree)
1304 end
1304 end
1305
1305
1306 with_settings :cross_project_subtasks => 'system' do
1306 with_settings :cross_project_subtasks => 'system' do
1307 assert_equal true, issue.valid_parent_project?(issue_in_same_project)
1307 assert_equal true, issue.valid_parent_project?(issue_in_same_project)
1308 assert_equal true, issue.valid_parent_project?(issue_in_child_project)
1308 assert_equal true, issue.valid_parent_project?(issue_in_child_project)
1309 assert_equal true, issue.valid_parent_project?(issue_in_different_tree)
1309 assert_equal true, issue.valid_parent_project?(issue_in_different_tree)
1310 end
1310 end
1311
1311
1312 with_settings :cross_project_subtasks => 'tree' do
1312 with_settings :cross_project_subtasks => 'tree' do
1313 assert_equal true, issue.valid_parent_project?(issue_in_same_project)
1313 assert_equal true, issue.valid_parent_project?(issue_in_same_project)
1314 assert_equal true, issue.valid_parent_project?(issue_in_child_project)
1314 assert_equal true, issue.valid_parent_project?(issue_in_child_project)
1315 assert_equal true, issue.valid_parent_project?(issue_in_grandchild_project)
1315 assert_equal true, issue.valid_parent_project?(issue_in_grandchild_project)
1316 assert_equal false, issue.valid_parent_project?(issue_in_different_tree)
1316 assert_equal false, issue.valid_parent_project?(issue_in_different_tree)
1317
1317
1318 assert_equal true, issue_in_child_project.valid_parent_project?(issue_in_same_project)
1318 assert_equal true, issue_in_child_project.valid_parent_project?(issue_in_same_project)
1319 assert_equal true, issue_in_child_project.valid_parent_project?(issue_in_other_child_project)
1319 assert_equal true, issue_in_child_project.valid_parent_project?(issue_in_other_child_project)
1320 end
1320 end
1321
1321
1322 with_settings :cross_project_subtasks => 'descendants' do
1322 with_settings :cross_project_subtasks => 'descendants' do
1323 assert_equal true, issue.valid_parent_project?(issue_in_same_project)
1323 assert_equal true, issue.valid_parent_project?(issue_in_same_project)
1324 assert_equal false, issue.valid_parent_project?(issue_in_child_project)
1324 assert_equal false, issue.valid_parent_project?(issue_in_child_project)
1325 assert_equal false, issue.valid_parent_project?(issue_in_grandchild_project)
1325 assert_equal false, issue.valid_parent_project?(issue_in_grandchild_project)
1326 assert_equal false, issue.valid_parent_project?(issue_in_different_tree)
1326 assert_equal false, issue.valid_parent_project?(issue_in_different_tree)
1327
1327
1328 assert_equal true, issue_in_child_project.valid_parent_project?(issue)
1328 assert_equal true, issue_in_child_project.valid_parent_project?(issue)
1329 assert_equal false, issue_in_child_project.valid_parent_project?(issue_in_other_child_project)
1329 assert_equal false, issue_in_child_project.valid_parent_project?(issue_in_other_child_project)
1330 end
1330 end
1331 end
1331 end
1332
1332
1333 def test_recipients_should_include_previous_assignee
1333 def test_recipients_should_include_previous_assignee
1334 user = User.find(3)
1334 user = User.find(3)
1335 user.members.update_all ["mail_notification = ?", false]
1335 user.members.update_all ["mail_notification = ?", false]
1336 user.update_attribute :mail_notification, 'only_assigned'
1336 user.update_attribute :mail_notification, 'only_assigned'
1337
1337
1338 issue = Issue.find(2)
1338 issue = Issue.find(2)
1339 issue.assigned_to = nil
1339 issue.assigned_to = nil
1340 assert_include user.mail, issue.recipients
1340 assert_include user.mail, issue.recipients
1341 issue.save!
1341 issue.save!
1342 assert !issue.recipients.include?(user.mail)
1342 assert !issue.recipients.include?(user.mail)
1343 end
1343 end
1344
1344
1345 def test_recipients_should_not_include_users_that_cannot_view_the_issue
1345 def test_recipients_should_not_include_users_that_cannot_view_the_issue
1346 issue = Issue.find(12)
1346 issue = Issue.find(12)
1347 assert issue.recipients.include?(issue.author.mail)
1347 assert issue.recipients.include?(issue.author.mail)
1348 # copy the issue to a private project
1348 # copy the issue to a private project
1349 copy = issue.copy(:project_id => 5, :tracker_id => 2)
1349 copy = issue.copy(:project_id => 5, :tracker_id => 2)
1350 # author is not a member of project anymore
1350 # author is not a member of project anymore
1351 assert !copy.recipients.include?(copy.author.mail)
1351 assert !copy.recipients.include?(copy.author.mail)
1352 end
1352 end
1353
1353
1354 def test_recipients_should_include_the_assigned_group_members
1354 def test_recipients_should_include_the_assigned_group_members
1355 group_member = User.generate!
1355 group_member = User.generate!
1356 group = Group.generate!
1356 group = Group.generate!
1357 group.users << group_member
1357 group.users << group_member
1358
1358
1359 issue = Issue.find(12)
1359 issue = Issue.find(12)
1360 issue.assigned_to = group
1360 issue.assigned_to = group
1361 assert issue.recipients.include?(group_member.mail)
1361 assert issue.recipients.include?(group_member.mail)
1362 end
1362 end
1363
1363
1364 def test_watcher_recipients_should_not_include_users_that_cannot_view_the_issue
1364 def test_watcher_recipients_should_not_include_users_that_cannot_view_the_issue
1365 user = User.find(3)
1365 user = User.find(3)
1366 issue = Issue.find(9)
1366 issue = Issue.find(9)
1367 Watcher.create!(:user => user, :watchable => issue)
1367 Watcher.create!(:user => user, :watchable => issue)
1368 assert issue.watched_by?(user)
1368 assert issue.watched_by?(user)
1369 assert !issue.watcher_recipients.include?(user.mail)
1369 assert !issue.watcher_recipients.include?(user.mail)
1370 end
1370 end
1371
1371
1372 def test_issue_destroy
1372 def test_issue_destroy
1373 Issue.find(1).destroy
1373 Issue.find(1).destroy
1374 assert_nil Issue.find_by_id(1)
1374 assert_nil Issue.find_by_id(1)
1375 assert_nil TimeEntry.find_by_issue_id(1)
1375 assert_nil TimeEntry.find_by_issue_id(1)
1376 end
1376 end
1377
1377
1378 def test_destroying_a_deleted_issue_should_not_raise_an_error
1378 def test_destroying_a_deleted_issue_should_not_raise_an_error
1379 issue = Issue.find(1)
1379 issue = Issue.find(1)
1380 Issue.find(1).destroy
1380 Issue.find(1).destroy
1381
1381
1382 assert_nothing_raised do
1382 assert_nothing_raised do
1383 assert_no_difference 'Issue.count' do
1383 assert_no_difference 'Issue.count' do
1384 issue.destroy
1384 issue.destroy
1385 end
1385 end
1386 assert issue.destroyed?
1386 assert issue.destroyed?
1387 end
1387 end
1388 end
1388 end
1389
1389
1390 def test_destroying_a_stale_issue_should_not_raise_an_error
1390 def test_destroying_a_stale_issue_should_not_raise_an_error
1391 issue = Issue.find(1)
1391 issue = Issue.find(1)
1392 Issue.find(1).update_attribute :subject, "Updated"
1392 Issue.find(1).update_attribute :subject, "Updated"
1393
1393
1394 assert_nothing_raised do
1394 assert_nothing_raised do
1395 assert_difference 'Issue.count', -1 do
1395 assert_difference 'Issue.count', -1 do
1396 issue.destroy
1396 issue.destroy
1397 end
1397 end
1398 assert issue.destroyed?
1398 assert issue.destroyed?
1399 end
1399 end
1400 end
1400 end
1401
1401
1402 def test_blocked
1402 def test_blocked
1403 blocked_issue = Issue.find(9)
1403 blocked_issue = Issue.find(9)
1404 blocking_issue = Issue.find(10)
1404 blocking_issue = Issue.find(10)
1405
1405
1406 assert blocked_issue.blocked?
1406 assert blocked_issue.blocked?
1407 assert !blocking_issue.blocked?
1407 assert !blocking_issue.blocked?
1408 end
1408 end
1409
1409
1410 def test_blocked_issues_dont_allow_closed_statuses
1410 def test_blocked_issues_dont_allow_closed_statuses
1411 blocked_issue = Issue.find(9)
1411 blocked_issue = Issue.find(9)
1412
1412
1413 allowed_statuses = blocked_issue.new_statuses_allowed_to(users(:users_002))
1413 allowed_statuses = blocked_issue.new_statuses_allowed_to(users(:users_002))
1414 assert !allowed_statuses.empty?
1414 assert !allowed_statuses.empty?
1415 closed_statuses = allowed_statuses.select {|st| st.is_closed?}
1415 closed_statuses = allowed_statuses.select {|st| st.is_closed?}
1416 assert closed_statuses.empty?
1416 assert closed_statuses.empty?
1417 end
1417 end
1418
1418
1419 def test_unblocked_issues_allow_closed_statuses
1419 def test_unblocked_issues_allow_closed_statuses
1420 blocking_issue = Issue.find(10)
1420 blocking_issue = Issue.find(10)
1421
1421
1422 allowed_statuses = blocking_issue.new_statuses_allowed_to(users(:users_002))
1422 allowed_statuses = blocking_issue.new_statuses_allowed_to(users(:users_002))
1423 assert !allowed_statuses.empty?
1423 assert !allowed_statuses.empty?
1424 closed_statuses = allowed_statuses.select {|st| st.is_closed?}
1424 closed_statuses = allowed_statuses.select {|st| st.is_closed?}
1425 assert !closed_statuses.empty?
1425 assert !closed_statuses.empty?
1426 end
1426 end
1427
1427
1428 def test_reschedule_an_issue_without_dates
1428 def test_reschedule_an_issue_without_dates
1429 with_settings :non_working_week_days => [] do
1429 with_settings :non_working_week_days => [] do
1430 issue = Issue.new(:start_date => nil, :due_date => nil)
1430 issue = Issue.new(:start_date => nil, :due_date => nil)
1431 issue.reschedule_on '2012-10-09'.to_date
1431 issue.reschedule_on '2012-10-09'.to_date
1432 assert_equal '2012-10-09'.to_date, issue.start_date
1432 assert_equal '2012-10-09'.to_date, issue.start_date
1433 assert_equal '2012-10-09'.to_date, issue.due_date
1433 assert_equal '2012-10-09'.to_date, issue.due_date
1434 end
1434 end
1435
1435
1436 with_settings :non_working_week_days => %w(6 7) do
1436 with_settings :non_working_week_days => %w(6 7) do
1437 issue = Issue.new(:start_date => nil, :due_date => nil)
1437 issue = Issue.new(:start_date => nil, :due_date => nil)
1438 issue.reschedule_on '2012-10-09'.to_date
1438 issue.reschedule_on '2012-10-09'.to_date
1439 assert_equal '2012-10-09'.to_date, issue.start_date
1439 assert_equal '2012-10-09'.to_date, issue.start_date
1440 assert_equal '2012-10-09'.to_date, issue.due_date
1440 assert_equal '2012-10-09'.to_date, issue.due_date
1441
1441
1442 issue = Issue.new(:start_date => nil, :due_date => nil)
1442 issue = Issue.new(:start_date => nil, :due_date => nil)
1443 issue.reschedule_on '2012-10-13'.to_date
1443 issue.reschedule_on '2012-10-13'.to_date
1444 assert_equal '2012-10-15'.to_date, issue.start_date
1444 assert_equal '2012-10-15'.to_date, issue.start_date
1445 assert_equal '2012-10-15'.to_date, issue.due_date
1445 assert_equal '2012-10-15'.to_date, issue.due_date
1446 end
1446 end
1447 end
1447 end
1448
1448
1449 def test_reschedule_an_issue_with_start_date
1449 def test_reschedule_an_issue_with_start_date
1450 with_settings :non_working_week_days => [] do
1450 with_settings :non_working_week_days => [] do
1451 issue = Issue.new(:start_date => '2012-10-09', :due_date => nil)
1451 issue = Issue.new(:start_date => '2012-10-09', :due_date => nil)
1452 issue.reschedule_on '2012-10-13'.to_date
1452 issue.reschedule_on '2012-10-13'.to_date
1453 assert_equal '2012-10-13'.to_date, issue.start_date
1453 assert_equal '2012-10-13'.to_date, issue.start_date
1454 assert_equal '2012-10-13'.to_date, issue.due_date
1454 assert_equal '2012-10-13'.to_date, issue.due_date
1455 end
1455 end
1456
1456
1457 with_settings :non_working_week_days => %w(6 7) do
1457 with_settings :non_working_week_days => %w(6 7) do
1458 issue = Issue.new(:start_date => '2012-10-09', :due_date => nil)
1458 issue = Issue.new(:start_date => '2012-10-09', :due_date => nil)
1459 issue.reschedule_on '2012-10-11'.to_date
1459 issue.reschedule_on '2012-10-11'.to_date
1460 assert_equal '2012-10-11'.to_date, issue.start_date
1460 assert_equal '2012-10-11'.to_date, issue.start_date
1461 assert_equal '2012-10-11'.to_date, issue.due_date
1461 assert_equal '2012-10-11'.to_date, issue.due_date
1462
1462
1463 issue = Issue.new(:start_date => '2012-10-09', :due_date => nil)
1463 issue = Issue.new(:start_date => '2012-10-09', :due_date => nil)
1464 issue.reschedule_on '2012-10-13'.to_date
1464 issue.reschedule_on '2012-10-13'.to_date
1465 assert_equal '2012-10-15'.to_date, issue.start_date
1465 assert_equal '2012-10-15'.to_date, issue.start_date
1466 assert_equal '2012-10-15'.to_date, issue.due_date
1466 assert_equal '2012-10-15'.to_date, issue.due_date
1467 end
1467 end
1468 end
1468 end
1469
1469
1470 def test_reschedule_an_issue_with_start_and_due_dates
1470 def test_reschedule_an_issue_with_start_and_due_dates
1471 with_settings :non_working_week_days => [] do
1471 with_settings :non_working_week_days => [] do
1472 issue = Issue.new(:start_date => '2012-10-09', :due_date => '2012-10-15')
1472 issue = Issue.new(:start_date => '2012-10-09', :due_date => '2012-10-15')
1473 issue.reschedule_on '2012-10-13'.to_date
1473 issue.reschedule_on '2012-10-13'.to_date
1474 assert_equal '2012-10-13'.to_date, issue.start_date
1474 assert_equal '2012-10-13'.to_date, issue.start_date
1475 assert_equal '2012-10-19'.to_date, issue.due_date
1475 assert_equal '2012-10-19'.to_date, issue.due_date
1476 end
1476 end
1477
1477
1478 with_settings :non_working_week_days => %w(6 7) do
1478 with_settings :non_working_week_days => %w(6 7) do
1479 issue = Issue.new(:start_date => '2012-10-09', :due_date => '2012-10-19') # 8 working days
1479 issue = Issue.new(:start_date => '2012-10-09', :due_date => '2012-10-19') # 8 working days
1480 issue.reschedule_on '2012-10-11'.to_date
1480 issue.reschedule_on '2012-10-11'.to_date
1481 assert_equal '2012-10-11'.to_date, issue.start_date
1481 assert_equal '2012-10-11'.to_date, issue.start_date
1482 assert_equal '2012-10-23'.to_date, issue.due_date
1482 assert_equal '2012-10-23'.to_date, issue.due_date
1483
1483
1484 issue = Issue.new(:start_date => '2012-10-09', :due_date => '2012-10-19')
1484 issue = Issue.new(:start_date => '2012-10-09', :due_date => '2012-10-19')
1485 issue.reschedule_on '2012-10-13'.to_date
1485 issue.reschedule_on '2012-10-13'.to_date
1486 assert_equal '2012-10-15'.to_date, issue.start_date
1486 assert_equal '2012-10-15'.to_date, issue.start_date
1487 assert_equal '2012-10-25'.to_date, issue.due_date
1487 assert_equal '2012-10-25'.to_date, issue.due_date
1488 end
1488 end
1489 end
1489 end
1490
1490
1491 def test_rescheduling_an_issue_to_a_later_due_date_should_reschedule_following_issue
1491 def test_rescheduling_an_issue_to_a_later_due_date_should_reschedule_following_issue
1492 issue1 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1492 issue1 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1493 issue2 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1493 issue2 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1494 IssueRelation.create!(:issue_from => issue1, :issue_to => issue2,
1494 IssueRelation.create!(:issue_from => issue1, :issue_to => issue2,
1495 :relation_type => IssueRelation::TYPE_PRECEDES)
1495 :relation_type => IssueRelation::TYPE_PRECEDES)
1496 assert_equal Date.parse('2012-10-18'), issue2.reload.start_date
1496 assert_equal Date.parse('2012-10-18'), issue2.reload.start_date
1497
1497
1498 issue1.reload
1498 issue1.reload
1499 issue1.due_date = '2012-10-23'
1499 issue1.due_date = '2012-10-23'
1500 issue1.save!
1500 issue1.save!
1501 issue2.reload
1501 issue2.reload
1502 assert_equal Date.parse('2012-10-24'), issue2.start_date
1502 assert_equal Date.parse('2012-10-24'), issue2.start_date
1503 assert_equal Date.parse('2012-10-26'), issue2.due_date
1503 assert_equal Date.parse('2012-10-26'), issue2.due_date
1504 end
1504 end
1505
1505
1506 def test_rescheduling_an_issue_to_an_earlier_due_date_should_reschedule_following_issue
1506 def test_rescheduling_an_issue_to_an_earlier_due_date_should_reschedule_following_issue
1507 issue1 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1507 issue1 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1508 issue2 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1508 issue2 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1509 IssueRelation.create!(:issue_from => issue1, :issue_to => issue2,
1509 IssueRelation.create!(:issue_from => issue1, :issue_to => issue2,
1510 :relation_type => IssueRelation::TYPE_PRECEDES)
1510 :relation_type => IssueRelation::TYPE_PRECEDES)
1511 assert_equal Date.parse('2012-10-18'), issue2.reload.start_date
1511 assert_equal Date.parse('2012-10-18'), issue2.reload.start_date
1512
1512
1513 issue1.reload
1513 issue1.reload
1514 issue1.start_date = '2012-09-17'
1514 issue1.start_date = '2012-09-17'
1515 issue1.due_date = '2012-09-18'
1515 issue1.due_date = '2012-09-18'
1516 issue1.save!
1516 issue1.save!
1517 issue2.reload
1517 issue2.reload
1518 assert_equal Date.parse('2012-09-19'), issue2.start_date
1518 assert_equal Date.parse('2012-09-19'), issue2.start_date
1519 assert_equal Date.parse('2012-09-21'), issue2.due_date
1519 assert_equal Date.parse('2012-09-21'), issue2.due_date
1520 end
1520 end
1521
1521
1522 def test_rescheduling_reschedule_following_issue_earlier_should_consider_other_preceding_issues
1522 def test_rescheduling_reschedule_following_issue_earlier_should_consider_other_preceding_issues
1523 issue1 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1523 issue1 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1524 issue2 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1524 issue2 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1525 issue3 = Issue.generate!(:start_date => '2012-10-01', :due_date => '2012-10-02')
1525 issue3 = Issue.generate!(:start_date => '2012-10-01', :due_date => '2012-10-02')
1526 IssueRelation.create!(:issue_from => issue1, :issue_to => issue2,
1526 IssueRelation.create!(:issue_from => issue1, :issue_to => issue2,
1527 :relation_type => IssueRelation::TYPE_PRECEDES)
1527 :relation_type => IssueRelation::TYPE_PRECEDES)
1528 IssueRelation.create!(:issue_from => issue3, :issue_to => issue2,
1528 IssueRelation.create!(:issue_from => issue3, :issue_to => issue2,
1529 :relation_type => IssueRelation::TYPE_PRECEDES)
1529 :relation_type => IssueRelation::TYPE_PRECEDES)
1530 assert_equal Date.parse('2012-10-18'), issue2.reload.start_date
1530 assert_equal Date.parse('2012-10-18'), issue2.reload.start_date
1531
1531
1532 issue1.reload
1532 issue1.reload
1533 issue1.start_date = '2012-09-17'
1533 issue1.start_date = '2012-09-17'
1534 issue1.due_date = '2012-09-18'
1534 issue1.due_date = '2012-09-18'
1535 issue1.save!
1535 issue1.save!
1536 issue2.reload
1536 issue2.reload
1537 # Issue 2 must start after Issue 3
1537 # Issue 2 must start after Issue 3
1538 assert_equal Date.parse('2012-10-03'), issue2.start_date
1538 assert_equal Date.parse('2012-10-03'), issue2.start_date
1539 assert_equal Date.parse('2012-10-05'), issue2.due_date
1539 assert_equal Date.parse('2012-10-05'), issue2.due_date
1540 end
1540 end
1541
1541
1542 def test_rescheduling_a_stale_issue_should_not_raise_an_error
1542 def test_rescheduling_a_stale_issue_should_not_raise_an_error
1543 with_settings :non_working_week_days => [] do
1543 with_settings :non_working_week_days => [] do
1544 stale = Issue.find(1)
1544 stale = Issue.find(1)
1545 issue = Issue.find(1)
1545 issue = Issue.find(1)
1546 issue.subject = "Updated"
1546 issue.subject = "Updated"
1547 issue.save!
1547 issue.save!
1548 date = 10.days.from_now.to_date
1548 date = 10.days.from_now.to_date
1549 assert_nothing_raised do
1549 assert_nothing_raised do
1550 stale.reschedule_on!(date)
1550 stale.reschedule_on!(date)
1551 end
1551 end
1552 assert_equal date, stale.reload.start_date
1552 assert_equal date, stale.reload.start_date
1553 end
1553 end
1554 end
1554 end
1555
1555
1556 def test_child_issue_should_consider_parent_soonest_start_on_create
1556 def test_child_issue_should_consider_parent_soonest_start_on_create
1557 set_language_if_valid 'en'
1557 set_language_if_valid 'en'
1558 issue1 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1558 issue1 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1559 issue2 = Issue.generate!(:start_date => '2012-10-18', :due_date => '2012-10-20')
1559 issue2 = Issue.generate!(:start_date => '2012-10-18', :due_date => '2012-10-20')
1560 IssueRelation.create!(:issue_from => issue1, :issue_to => issue2,
1560 IssueRelation.create!(:issue_from => issue1, :issue_to => issue2,
1561 :relation_type => IssueRelation::TYPE_PRECEDES)
1561 :relation_type => IssueRelation::TYPE_PRECEDES)
1562 issue1.reload
1562 issue1.reload
1563 issue2.reload
1563 issue2.reload
1564 assert_equal Date.parse('2012-10-18'), issue2.start_date
1564 assert_equal Date.parse('2012-10-18'), issue2.start_date
1565
1565
1566 child = Issue.new(:parent_issue_id => issue2.id, :start_date => '2012-10-16',
1566 child = Issue.new(:parent_issue_id => issue2.id, :start_date => '2012-10-16',
1567 :project_id => 1, :tracker_id => 1, :status_id => 1, :subject => 'Child', :author_id => 1)
1567 :project_id => 1, :tracker_id => 1, :status_id => 1, :subject => 'Child', :author_id => 1)
1568 assert !child.valid?
1568 assert !child.valid?
1569 assert_include 'Start date cannot be earlier than 10/18/2012 because of preceding issues', child.errors.full_messages
1569 assert_include 'Start date cannot be earlier than 10/18/2012 because of preceding issues', child.errors.full_messages
1570 assert_equal Date.parse('2012-10-18'), child.soonest_start
1570 assert_equal Date.parse('2012-10-18'), child.soonest_start
1571 child.start_date = '2012-10-18'
1571 child.start_date = '2012-10-18'
1572 assert child.save
1572 assert child.save
1573 end
1573 end
1574
1574
1575 def test_setting_parent_to_a_dependent_issue_should_not_validate
1575 def test_setting_parent_to_a_dependent_issue_should_not_validate
1576 set_language_if_valid 'en'
1576 set_language_if_valid 'en'
1577 issue1 = Issue.generate!
1577 issue1 = Issue.generate!
1578 issue2 = Issue.generate!
1578 issue2 = Issue.generate!
1579 issue3 = Issue.generate!
1579 issue3 = Issue.generate!
1580 IssueRelation.create!(:issue_from => issue1, :issue_to => issue2, :relation_type => IssueRelation::TYPE_PRECEDES)
1580 IssueRelation.create!(:issue_from => issue1, :issue_to => issue2, :relation_type => IssueRelation::TYPE_PRECEDES)
1581 IssueRelation.create!(:issue_from => issue3, :issue_to => issue1, :relation_type => IssueRelation::TYPE_PRECEDES)
1581 IssueRelation.create!(:issue_from => issue3, :issue_to => issue1, :relation_type => IssueRelation::TYPE_PRECEDES)
1582 issue3.reload
1582 issue3.reload
1583 issue3.parent_issue_id = issue2.id
1583 issue3.parent_issue_id = issue2.id
1584 assert !issue3.valid?
1584 assert !issue3.valid?
1585 assert_include 'Parent task is invalid', issue3.errors.full_messages
1585 assert_include 'Parent task is invalid', issue3.errors.full_messages
1586 end
1586 end
1587
1587
1588 def test_setting_parent_should_not_allow_circular_dependency
1588 def test_setting_parent_should_not_allow_circular_dependency
1589 set_language_if_valid 'en'
1589 set_language_if_valid 'en'
1590 issue1 = Issue.generate!
1590 issue1 = Issue.generate!
1591 issue2 = Issue.generate!
1591 issue2 = Issue.generate!
1592 IssueRelation.create!(:issue_from => issue1, :issue_to => issue2, :relation_type => IssueRelation::TYPE_PRECEDES)
1592 IssueRelation.create!(:issue_from => issue1, :issue_to => issue2, :relation_type => IssueRelation::TYPE_PRECEDES)
1593 issue3 = Issue.generate!
1593 issue3 = Issue.generate!
1594 issue2.reload
1594 issue2.reload
1595 issue2.parent_issue_id = issue3.id
1595 issue2.parent_issue_id = issue3.id
1596 issue2.save!
1596 issue2.save!
1597 issue4 = Issue.generate!
1597 issue4 = Issue.generate!
1598 IssueRelation.create!(:issue_from => issue3, :issue_to => issue4, :relation_type => IssueRelation::TYPE_PRECEDES)
1598 IssueRelation.create!(:issue_from => issue3, :issue_to => issue4, :relation_type => IssueRelation::TYPE_PRECEDES)
1599 issue4.reload
1599 issue4.reload
1600 issue4.parent_issue_id = issue1.id
1600 issue4.parent_issue_id = issue1.id
1601 assert !issue4.valid?
1601 assert !issue4.valid?
1602 assert_include 'Parent task is invalid', issue4.errors.full_messages
1602 assert_include 'Parent task is invalid', issue4.errors.full_messages
1603 end
1603 end
1604
1604
1605 def test_overdue
1605 def test_overdue
1606 assert Issue.new(:due_date => 1.day.ago.to_date).overdue?
1606 assert Issue.new(:due_date => 1.day.ago.to_date).overdue?
1607 assert !Issue.new(:due_date => Date.today).overdue?
1607 assert !Issue.new(:due_date => Date.today).overdue?
1608 assert !Issue.new(:due_date => 1.day.from_now.to_date).overdue?
1608 assert !Issue.new(:due_date => 1.day.from_now.to_date).overdue?
1609 assert !Issue.new(:due_date => nil).overdue?
1609 assert !Issue.new(:due_date => nil).overdue?
1610 assert !Issue.new(:due_date => 1.day.ago.to_date,
1610 assert !Issue.new(:due_date => 1.day.ago.to_date,
1611 :status => IssueStatus.where(:is_closed => true).first
1611 :status => IssueStatus.where(:is_closed => true).first
1612 ).overdue?
1612 ).overdue?
1613 end
1613 end
1614
1614
1615 test "#behind_schedule? should be false if the issue has no start_date" do
1615 test "#behind_schedule? should be false if the issue has no start_date" do
1616 assert !Issue.new(:start_date => nil,
1616 assert !Issue.new(:start_date => nil,
1617 :due_date => 1.day.from_now.to_date,
1617 :due_date => 1.day.from_now.to_date,
1618 :done_ratio => 0).behind_schedule?
1618 :done_ratio => 0).behind_schedule?
1619 end
1619 end
1620
1620
1621 test "#behind_schedule? should be false if the issue has no end_date" do
1621 test "#behind_schedule? should be false if the issue has no end_date" do
1622 assert !Issue.new(:start_date => 1.day.from_now.to_date,
1622 assert !Issue.new(:start_date => 1.day.from_now.to_date,
1623 :due_date => nil,
1623 :due_date => nil,
1624 :done_ratio => 0).behind_schedule?
1624 :done_ratio => 0).behind_schedule?
1625 end
1625 end
1626
1626
1627 test "#behind_schedule? should be false if the issue has more done than it's calendar time" do
1627 test "#behind_schedule? should be false if the issue has more done than it's calendar time" do
1628 assert !Issue.new(:start_date => 50.days.ago.to_date,
1628 assert !Issue.new(:start_date => 50.days.ago.to_date,
1629 :due_date => 50.days.from_now.to_date,
1629 :due_date => 50.days.from_now.to_date,
1630 :done_ratio => 90).behind_schedule?
1630 :done_ratio => 90).behind_schedule?
1631 end
1631 end
1632
1632
1633 test "#behind_schedule? should be true if the issue hasn't been started at all" do
1633 test "#behind_schedule? should be true if the issue hasn't been started at all" do
1634 assert Issue.new(:start_date => 1.day.ago.to_date,
1634 assert Issue.new(:start_date => 1.day.ago.to_date,
1635 :due_date => 1.day.from_now.to_date,
1635 :due_date => 1.day.from_now.to_date,
1636 :done_ratio => 0).behind_schedule?
1636 :done_ratio => 0).behind_schedule?
1637 end
1637 end
1638
1638
1639 test "#behind_schedule? should be true if the issue has used more calendar time than it's done ratio" do
1639 test "#behind_schedule? should be true if the issue has used more calendar time than it's done ratio" do
1640 assert Issue.new(:start_date => 100.days.ago.to_date,
1640 assert Issue.new(:start_date => 100.days.ago.to_date,
1641 :due_date => Date.today,
1641 :due_date => Date.today,
1642 :done_ratio => 90).behind_schedule?
1642 :done_ratio => 90).behind_schedule?
1643 end
1643 end
1644
1644
1645 test "#assignable_users should be Users" do
1645 test "#assignable_users should be Users" do
1646 assert_kind_of User, Issue.find(1).assignable_users.first
1646 assert_kind_of User, Issue.find(1).assignable_users.first
1647 end
1647 end
1648
1648
1649 test "#assignable_users should include the issue author" do
1649 test "#assignable_users should include the issue author" do
1650 non_project_member = User.generate!
1650 non_project_member = User.generate!
1651 issue = Issue.generate!(:author => non_project_member)
1651 issue = Issue.generate!(:author => non_project_member)
1652
1652
1653 assert issue.assignable_users.include?(non_project_member)
1653 assert issue.assignable_users.include?(non_project_member)
1654 end
1654 end
1655
1655
1656 test "#assignable_users should include the current assignee" do
1656 test "#assignable_users should include the current assignee" do
1657 user = User.generate!
1657 user = User.generate!
1658 issue = Issue.generate!(:assigned_to => user)
1658 issue = Issue.generate!(:assigned_to => user)
1659 user.lock!
1659 user.lock!
1660
1660
1661 assert Issue.find(issue.id).assignable_users.include?(user)
1661 assert Issue.find(issue.id).assignable_users.include?(user)
1662 end
1662 end
1663
1663
1664 test "#assignable_users should not show the issue author twice" do
1664 test "#assignable_users should not show the issue author twice" do
1665 assignable_user_ids = Issue.find(1).assignable_users.collect(&:id)
1665 assignable_user_ids = Issue.find(1).assignable_users.collect(&:id)
1666 assert_equal 2, assignable_user_ids.length
1666 assert_equal 2, assignable_user_ids.length
1667
1667
1668 assignable_user_ids.each do |user_id|
1668 assignable_user_ids.each do |user_id|
1669 assert_equal 1, assignable_user_ids.select {|i| i == user_id}.length,
1669 assert_equal 1, assignable_user_ids.select {|i| i == user_id}.length,
1670 "User #{user_id} appears more or less than once"
1670 "User #{user_id} appears more or less than once"
1671 end
1671 end
1672 end
1672 end
1673
1673
1674 test "#assignable_users with issue_group_assignment should include groups" do
1674 test "#assignable_users with issue_group_assignment should include groups" do
1675 issue = Issue.new(:project => Project.find(2))
1675 issue = Issue.new(:project => Project.find(2))
1676
1676
1677 with_settings :issue_group_assignment => '1' do
1677 with_settings :issue_group_assignment => '1' do
1678 assert_equal %w(Group User), issue.assignable_users.map {|a| a.class.name}.uniq.sort
1678 assert_equal %w(Group User), issue.assignable_users.map {|a| a.class.name}.uniq.sort
1679 assert issue.assignable_users.include?(Group.find(11))
1679 assert issue.assignable_users.include?(Group.find(11))
1680 end
1680 end
1681 end
1681 end
1682
1682
1683 test "#assignable_users without issue_group_assignment should not include groups" do
1683 test "#assignable_users without issue_group_assignment should not include groups" do
1684 issue = Issue.new(:project => Project.find(2))
1684 issue = Issue.new(:project => Project.find(2))
1685
1685
1686 with_settings :issue_group_assignment => '0' do
1686 with_settings :issue_group_assignment => '0' do
1687 assert_equal %w(User), issue.assignable_users.map {|a| a.class.name}.uniq.sort
1687 assert_equal %w(User), issue.assignable_users.map {|a| a.class.name}.uniq.sort
1688 assert !issue.assignable_users.include?(Group.find(11))
1688 assert !issue.assignable_users.include?(Group.find(11))
1689 end
1689 end
1690 end
1690 end
1691
1691
1692 def test_create_should_send_email_notification
1692 def test_create_should_send_email_notification
1693 ActionMailer::Base.deliveries.clear
1693 ActionMailer::Base.deliveries.clear
1694 issue = Issue.new(:project_id => 1, :tracker_id => 1,
1694 issue = Issue.new(:project_id => 1, :tracker_id => 1,
1695 :author_id => 3, :status_id => 1,
1695 :author_id => 3, :status_id => 1,
1696 :priority => IssuePriority.all.first,
1696 :priority => IssuePriority.all.first,
1697 :subject => 'test_create', :estimated_hours => '1:30')
1697 :subject => 'test_create', :estimated_hours => '1:30')
1698
1698
1699 assert issue.save
1699 assert issue.save
1700 assert_equal 1, ActionMailer::Base.deliveries.size
1700 assert_equal 1, ActionMailer::Base.deliveries.size
1701 end
1701 end
1702
1702
1703 def test_stale_issue_should_not_send_email_notification
1703 def test_stale_issue_should_not_send_email_notification
1704 ActionMailer::Base.deliveries.clear
1704 ActionMailer::Base.deliveries.clear
1705 issue = Issue.find(1)
1705 issue = Issue.find(1)
1706 stale = Issue.find(1)
1706 stale = Issue.find(1)
1707
1707
1708 issue.init_journal(User.find(1))
1708 issue.init_journal(User.find(1))
1709 issue.subject = 'Subjet update'
1709 issue.subject = 'Subjet update'
1710 assert issue.save
1710 assert issue.save
1711 assert_equal 1, ActionMailer::Base.deliveries.size
1711 assert_equal 1, ActionMailer::Base.deliveries.size
1712 ActionMailer::Base.deliveries.clear
1712 ActionMailer::Base.deliveries.clear
1713
1713
1714 stale.init_journal(User.find(1))
1714 stale.init_journal(User.find(1))
1715 stale.subject = 'Another subjet update'
1715 stale.subject = 'Another subjet update'
1716 assert_raise ActiveRecord::StaleObjectError do
1716 assert_raise ActiveRecord::StaleObjectError do
1717 stale.save
1717 stale.save
1718 end
1718 end
1719 assert ActionMailer::Base.deliveries.empty?
1719 assert ActionMailer::Base.deliveries.empty?
1720 end
1720 end
1721
1721
1722 def test_journalized_description
1722 def test_journalized_description
1723 IssueCustomField.delete_all
1723 IssueCustomField.delete_all
1724
1724
1725 i = Issue.first
1725 i = Issue.first
1726 old_description = i.description
1726 old_description = i.description
1727 new_description = "This is the new description"
1727 new_description = "This is the new description"
1728
1728
1729 i.init_journal(User.find(2))
1729 i.init_journal(User.find(2))
1730 i.description = new_description
1730 i.description = new_description
1731 assert_difference 'Journal.count', 1 do
1731 assert_difference 'Journal.count', 1 do
1732 assert_difference 'JournalDetail.count', 1 do
1732 assert_difference 'JournalDetail.count', 1 do
1733 i.save!
1733 i.save!
1734 end
1734 end
1735 end
1735 end
1736
1736
1737 detail = JournalDetail.first(:order => 'id DESC')
1737 detail = JournalDetail.first(:order => 'id DESC')
1738 assert_equal i, detail.journal.journalized
1738 assert_equal i, detail.journal.journalized
1739 assert_equal 'attr', detail.property
1739 assert_equal 'attr', detail.property
1740 assert_equal 'description', detail.prop_key
1740 assert_equal 'description', detail.prop_key
1741 assert_equal old_description, detail.old_value
1741 assert_equal old_description, detail.old_value
1742 assert_equal new_description, detail.value
1742 assert_equal new_description, detail.value
1743 end
1743 end
1744
1744
1745 def test_blank_descriptions_should_not_be_journalized
1745 def test_blank_descriptions_should_not_be_journalized
1746 IssueCustomField.delete_all
1746 IssueCustomField.delete_all
1747 Issue.update_all("description = NULL", "id=1")
1747 Issue.update_all("description = NULL", "id=1")
1748
1748
1749 i = Issue.find(1)
1749 i = Issue.find(1)
1750 i.init_journal(User.find(2))
1750 i.init_journal(User.find(2))
1751 i.subject = "blank description"
1751 i.subject = "blank description"
1752 i.description = "\r\n"
1752 i.description = "\r\n"
1753
1753
1754 assert_difference 'Journal.count', 1 do
1754 assert_difference 'Journal.count', 1 do
1755 assert_difference 'JournalDetail.count', 1 do
1755 assert_difference 'JournalDetail.count', 1 do
1756 i.save!
1756 i.save!
1757 end
1757 end
1758 end
1758 end
1759 end
1759 end
1760
1760
1761 def test_journalized_multi_custom_field
1761 def test_journalized_multi_custom_field
1762 field = IssueCustomField.create!(:name => 'filter', :field_format => 'list',
1762 field = IssueCustomField.create!(:name => 'filter', :field_format => 'list',
1763 :is_filter => true, :is_for_all => true,
1763 :is_filter => true, :is_for_all => true,
1764 :tracker_ids => [1],
1764 :tracker_ids => [1],
1765 :possible_values => ['value1', 'value2', 'value3'],
1765 :possible_values => ['value1', 'value2', 'value3'],
1766 :multiple => true)
1766 :multiple => true)
1767
1767
1768 issue = Issue.create!(:project_id => 1, :tracker_id => 1,
1768 issue = Issue.create!(:project_id => 1, :tracker_id => 1,
1769 :subject => 'Test', :author_id => 1)
1769 :subject => 'Test', :author_id => 1)
1770
1770
1771 assert_difference 'Journal.count' do
1771 assert_difference 'Journal.count' do
1772 assert_difference 'JournalDetail.count' do
1772 assert_difference 'JournalDetail.count' do
1773 issue.init_journal(User.first)
1773 issue.init_journal(User.first)
1774 issue.custom_field_values = {field.id => ['value1']}
1774 issue.custom_field_values = {field.id => ['value1']}
1775 issue.save!
1775 issue.save!
1776 end
1776 end
1777 assert_difference 'JournalDetail.count' do
1777 assert_difference 'JournalDetail.count' do
1778 issue.init_journal(User.first)
1778 issue.init_journal(User.first)
1779 issue.custom_field_values = {field.id => ['value1', 'value2']}
1779 issue.custom_field_values = {field.id => ['value1', 'value2']}
1780 issue.save!
1780 issue.save!
1781 end
1781 end
1782 assert_difference 'JournalDetail.count', 2 do
1782 assert_difference 'JournalDetail.count', 2 do
1783 issue.init_journal(User.first)
1783 issue.init_journal(User.first)
1784 issue.custom_field_values = {field.id => ['value3', 'value2']}
1784 issue.custom_field_values = {field.id => ['value3', 'value2']}
1785 issue.save!
1785 issue.save!
1786 end
1786 end
1787 assert_difference 'JournalDetail.count', 2 do
1787 assert_difference 'JournalDetail.count', 2 do
1788 issue.init_journal(User.first)
1788 issue.init_journal(User.first)
1789 issue.custom_field_values = {field.id => nil}
1789 issue.custom_field_values = {field.id => nil}
1790 issue.save!
1790 issue.save!
1791 end
1791 end
1792 end
1792 end
1793 end
1793 end
1794
1794
1795 def test_description_eol_should_be_normalized
1795 def test_description_eol_should_be_normalized
1796 i = Issue.new(:description => "CR \r LF \n CRLF \r\n")
1796 i = Issue.new(:description => "CR \r LF \n CRLF \r\n")
1797 assert_equal "CR \r\n LF \r\n CRLF \r\n", i.description
1797 assert_equal "CR \r\n LF \r\n CRLF \r\n", i.description
1798 end
1798 end
1799
1799
1800 def test_saving_twice_should_not_duplicate_journal_details
1800 def test_saving_twice_should_not_duplicate_journal_details
1801 i = Issue.first
1801 i = Issue.first
1802 i.init_journal(User.find(2), 'Some notes')
1802 i.init_journal(User.find(2), 'Some notes')
1803 # initial changes
1803 # initial changes
1804 i.subject = 'New subject'
1804 i.subject = 'New subject'
1805 i.done_ratio = i.done_ratio + 10
1805 i.done_ratio = i.done_ratio + 10
1806 assert_difference 'Journal.count' do
1806 assert_difference 'Journal.count' do
1807 assert i.save
1807 assert i.save
1808 end
1808 end
1809 # 1 more change
1809 # 1 more change
1810 i.priority = IssuePriority.where("id <> ?", i.priority_id).first
1810 i.priority = IssuePriority.where("id <> ?", i.priority_id).first
1811 assert_no_difference 'Journal.count' do
1811 assert_no_difference 'Journal.count' do
1812 assert_difference 'JournalDetail.count', 1 do
1812 assert_difference 'JournalDetail.count', 1 do
1813 i.save
1813 i.save
1814 end
1814 end
1815 end
1815 end
1816 # no more change
1816 # no more change
1817 assert_no_difference 'Journal.count' do
1817 assert_no_difference 'Journal.count' do
1818 assert_no_difference 'JournalDetail.count' do
1818 assert_no_difference 'JournalDetail.count' do
1819 i.save
1819 i.save
1820 end
1820 end
1821 end
1821 end
1822 end
1822 end
1823
1823
1824 def test_all_dependent_issues
1824 def test_all_dependent_issues
1825 IssueRelation.delete_all
1825 IssueRelation.delete_all
1826 assert IssueRelation.create!(:issue_from => Issue.find(1),
1826 assert IssueRelation.create!(:issue_from => Issue.find(1),
1827 :issue_to => Issue.find(2),
1827 :issue_to => Issue.find(2),
1828 :relation_type => IssueRelation::TYPE_PRECEDES)
1828 :relation_type => IssueRelation::TYPE_PRECEDES)
1829 assert IssueRelation.create!(:issue_from => Issue.find(2),
1829 assert IssueRelation.create!(:issue_from => Issue.find(2),
1830 :issue_to => Issue.find(3),
1830 :issue_to => Issue.find(3),
1831 :relation_type => IssueRelation::TYPE_PRECEDES)
1831 :relation_type => IssueRelation::TYPE_PRECEDES)
1832 assert IssueRelation.create!(:issue_from => Issue.find(3),
1832 assert IssueRelation.create!(:issue_from => Issue.find(3),
1833 :issue_to => Issue.find(8),
1833 :issue_to => Issue.find(8),
1834 :relation_type => IssueRelation::TYPE_PRECEDES)
1834 :relation_type => IssueRelation::TYPE_PRECEDES)
1835
1835
1836 assert_equal [2, 3, 8], Issue.find(1).all_dependent_issues.collect(&:id).sort
1836 assert_equal [2, 3, 8], Issue.find(1).all_dependent_issues.collect(&:id).sort
1837 end
1837 end
1838
1838
1839 def test_all_dependent_issues_with_subtask
1839 def test_all_dependent_issues_with_subtask
1840 IssueRelation.delete_all
1840 IssueRelation.delete_all
1841
1841
1842 project = Project.generate!(:name => "testproject")
1842 project = Project.generate!(:name => "testproject")
1843
1843
1844 parentIssue = Issue.generate!(:project => project)
1844 parentIssue = Issue.generate!(:project => project)
1845 childIssue1 = Issue.generate!(:project => project, :parent_issue_id => parentIssue.id)
1845 childIssue1 = Issue.generate!(:project => project, :parent_issue_id => parentIssue.id)
1846 childIssue2 = Issue.generate!(:project => project, :parent_issue_id => parentIssue.id)
1846 childIssue2 = Issue.generate!(:project => project, :parent_issue_id => parentIssue.id)
1847
1847
1848 assert_equal [childIssue1.id, childIssue2.id].sort, parentIssue.all_dependent_issues.collect(&:id).uniq.sort
1848 assert_equal [childIssue1.id, childIssue2.id].sort, parentIssue.all_dependent_issues.collect(&:id).uniq.sort
1849 end
1849 end
1850
1850
1851 def test_all_dependent_issues_does_not_include_self
1851 def test_all_dependent_issues_does_not_include_self
1852 IssueRelation.delete_all
1852 IssueRelation.delete_all
1853
1853
1854 project = Project.generate!(:name => "testproject")
1854 project = Project.generate!(:name => "testproject")
1855
1855
1856 parentIssue = Issue.generate!(:project => project)
1856 parentIssue = Issue.generate!(:project => project)
1857 childIssue = Issue.generate!(:project => project, :parent_issue_id => parentIssue.id)
1857 childIssue = Issue.generate!(:project => project, :parent_issue_id => parentIssue.id)
1858
1858
1859 assert_equal [childIssue.id], parentIssue.all_dependent_issues.collect(&:id)
1859 assert_equal [childIssue.id], parentIssue.all_dependent_issues.collect(&:id)
1860 end
1860 end
1861
1861
1862 def test_all_dependent_issues_with_parenttask_and_sibling
1862 def test_all_dependent_issues_with_parenttask_and_sibling
1863 IssueRelation.delete_all
1863 IssueRelation.delete_all
1864
1864
1865 project = Project.generate!(:name => "testproject")
1865 project = Project.generate!(:name => "testproject")
1866
1866
1867 parentIssue = Issue.generate!(:project => project)
1867 parentIssue = Issue.generate!(:project => project)
1868 childIssue1 = Issue.generate!(:project => project, :parent_issue_id => parentIssue.id)
1868 childIssue1 = Issue.generate!(:project => project, :parent_issue_id => parentIssue.id)
1869 childIssue2 = Issue.generate!(:project => project, :parent_issue_id => parentIssue.id)
1869 childIssue2 = Issue.generate!(:project => project, :parent_issue_id => parentIssue.id)
1870
1870
1871 assert_equal [parentIssue.id].sort, childIssue1.all_dependent_issues.collect(&:id)
1871 assert_equal [parentIssue.id].sort, childIssue1.all_dependent_issues.collect(&:id)
1872 end
1872 end
1873
1873
1874 def test_all_dependent_issues_with_relation_to_leaf_in_other_tree
1874 def test_all_dependent_issues_with_relation_to_leaf_in_other_tree
1875 IssueRelation.delete_all
1875 IssueRelation.delete_all
1876
1876
1877 project = Project.generate!(:name => "testproject")
1877 project = Project.generate!(:name => "testproject")
1878
1878
1879 parentIssue1 = Issue.generate!(:project => project)
1879 parentIssue1 = Issue.generate!(:project => project)
1880 childIssue1_1 = Issue.generate!(:project => project, :parent_issue_id => parentIssue1.id)
1880 childIssue1_1 = Issue.generate!(:project => project, :parent_issue_id => parentIssue1.id)
1881 childIssue1_2 = Issue.generate!(:project => project, :parent_issue_id => parentIssue1.id)
1881 childIssue1_2 = Issue.generate!(:project => project, :parent_issue_id => parentIssue1.id)
1882
1882
1883 parentIssue2 = Issue.generate!(:project => project)
1883 parentIssue2 = Issue.generate!(:project => project)
1884 childIssue2_1 = Issue.generate!(:project => project, :parent_issue_id => parentIssue2.id)
1884 childIssue2_1 = Issue.generate!(:project => project, :parent_issue_id => parentIssue2.id)
1885 childIssue2_2 = Issue.generate!(:project => project, :parent_issue_id => parentIssue2.id)
1885 childIssue2_2 = Issue.generate!(:project => project, :parent_issue_id => parentIssue2.id)
1886
1886
1887
1887
1888 assert IssueRelation.create(:issue_from => parentIssue1,
1888 assert IssueRelation.create(:issue_from => parentIssue1,
1889 :issue_to => childIssue2_2,
1889 :issue_to => childIssue2_2,
1890 :relation_type => IssueRelation::TYPE_BLOCKS)
1890 :relation_type => IssueRelation::TYPE_BLOCKS)
1891
1891
1892 assert_equal [childIssue1_1.id, childIssue1_2.id, parentIssue2.id, childIssue2_2.id].sort,
1892 assert_equal [childIssue1_1.id, childIssue1_2.id, parentIssue2.id, childIssue2_2.id].sort,
1893 parentIssue1.all_dependent_issues.collect(&:id).uniq.sort
1893 parentIssue1.all_dependent_issues.collect(&:id).uniq.sort
1894 end
1894 end
1895
1895
1896 def test_all_dependent_issues_with_relation_to_parent_in_other_tree
1896 def test_all_dependent_issues_with_relation_to_parent_in_other_tree
1897 IssueRelation.delete_all
1897 IssueRelation.delete_all
1898
1898
1899 project = Project.generate!(:name => "testproject")
1899 project = Project.generate!(:name => "testproject")
1900
1900
1901 parentIssue1 = Issue.generate!(:project => project)
1901 parentIssue1 = Issue.generate!(:project => project)
1902 childIssue1_1 = Issue.generate!(:project => project, :parent_issue_id => parentIssue1.id)
1902 childIssue1_1 = Issue.generate!(:project => project, :parent_issue_id => parentIssue1.id)
1903 childIssue1_2 = Issue.generate!(:project => project, :parent_issue_id => parentIssue1.id)
1903 childIssue1_2 = Issue.generate!(:project => project, :parent_issue_id => parentIssue1.id)
1904
1904
1905 parentIssue2 = Issue.generate!(:project => project)
1905 parentIssue2 = Issue.generate!(:project => project)
1906 childIssue2_1 = Issue.generate!(:project => project, :parent_issue_id => parentIssue2.id)
1906 childIssue2_1 = Issue.generate!(:project => project, :parent_issue_id => parentIssue2.id)
1907 childIssue2_2 = Issue.generate!(:project => project, :parent_issue_id => parentIssue2.id)
1907 childIssue2_2 = Issue.generate!(:project => project, :parent_issue_id => parentIssue2.id)
1908
1908
1909
1909
1910 assert IssueRelation.create(:issue_from => parentIssue1,
1910 assert IssueRelation.create(:issue_from => parentIssue1,
1911 :issue_to => parentIssue2,
1911 :issue_to => parentIssue2,
1912 :relation_type => IssueRelation::TYPE_BLOCKS)
1912 :relation_type => IssueRelation::TYPE_BLOCKS)
1913
1913
1914 assert_equal [childIssue1_1.id, childIssue1_2.id, parentIssue2.id, childIssue2_1.id, childIssue2_2.id].sort,
1914 assert_equal [childIssue1_1.id, childIssue1_2.id, parentIssue2.id, childIssue2_1.id, childIssue2_2.id].sort,
1915 parentIssue1.all_dependent_issues.collect(&:id).uniq.sort
1915 parentIssue1.all_dependent_issues.collect(&:id).uniq.sort
1916 end
1916 end
1917
1917
1918 def test_all_dependent_issues_with_transitive_relation
1918 def test_all_dependent_issues_with_transitive_relation
1919 IssueRelation.delete_all
1919 IssueRelation.delete_all
1920
1920
1921 project = Project.generate!(:name => "testproject")
1921 project = Project.generate!(:name => "testproject")
1922
1922
1923 parentIssue1 = Issue.generate!(:project => project)
1923 parentIssue1 = Issue.generate!(:project => project)
1924 childIssue1_1 = Issue.generate!(:project => project, :parent_issue_id => parentIssue1.id)
1924 childIssue1_1 = Issue.generate!(:project => project, :parent_issue_id => parentIssue1.id)
1925
1925
1926 parentIssue2 = Issue.generate!(:project => project)
1926 parentIssue2 = Issue.generate!(:project => project)
1927 childIssue2_1 = Issue.generate!(:project => project, :parent_issue_id => parentIssue2.id)
1927 childIssue2_1 = Issue.generate!(:project => project, :parent_issue_id => parentIssue2.id)
1928
1928
1929 independentIssue = Issue.generate!(:project => project)
1929 independentIssue = Issue.generate!(:project => project)
1930
1930
1931 assert IssueRelation.create(:issue_from => parentIssue1,
1931 assert IssueRelation.create(:issue_from => parentIssue1,
1932 :issue_to => childIssue2_1,
1932 :issue_to => childIssue2_1,
1933 :relation_type => IssueRelation::TYPE_RELATES)
1933 :relation_type => IssueRelation::TYPE_RELATES)
1934
1934
1935 assert IssueRelation.create(:issue_from => childIssue2_1,
1935 assert IssueRelation.create(:issue_from => childIssue2_1,
1936 :issue_to => independentIssue,
1936 :issue_to => independentIssue,
1937 :relation_type => IssueRelation::TYPE_RELATES)
1937 :relation_type => IssueRelation::TYPE_RELATES)
1938
1938
1939 assert_equal [childIssue1_1.id, parentIssue2.id, childIssue2_1.id, independentIssue.id].sort,
1939 assert_equal [childIssue1_1.id, parentIssue2.id, childIssue2_1.id, independentIssue.id].sort,
1940 parentIssue1.all_dependent_issues.collect(&:id).uniq.sort
1940 parentIssue1.all_dependent_issues.collect(&:id).uniq.sort
1941 end
1941 end
1942
1942
1943 def test_all_dependent_issues_with_transitive_relation2
1943 def test_all_dependent_issues_with_transitive_relation2
1944 IssueRelation.delete_all
1944 IssueRelation.delete_all
1945
1945
1946 project = Project.generate!(:name => "testproject")
1946 project = Project.generate!(:name => "testproject")
1947
1947
1948 parentIssue1 = Issue.generate!(:project => project)
1948 parentIssue1 = Issue.generate!(:project => project)
1949 childIssue1_1 = Issue.generate!(:project => project, :parent_issue_id => parentIssue1.id)
1949 childIssue1_1 = Issue.generate!(:project => project, :parent_issue_id => parentIssue1.id)
1950
1950
1951 parentIssue2 = Issue.generate!(:project => project)
1951 parentIssue2 = Issue.generate!(:project => project)
1952 childIssue2_1 = Issue.generate!(:project => project, :parent_issue_id => parentIssue2.id)
1952 childIssue2_1 = Issue.generate!(:project => project, :parent_issue_id => parentIssue2.id)
1953
1953
1954 independentIssue = Issue.generate!(:project => project)
1954 independentIssue = Issue.generate!(:project => project)
1955
1955
1956 assert IssueRelation.create(:issue_from => parentIssue1,
1956 assert IssueRelation.create(:issue_from => parentIssue1,
1957 :issue_to => independentIssue,
1957 :issue_to => independentIssue,
1958 :relation_type => IssueRelation::TYPE_RELATES)
1958 :relation_type => IssueRelation::TYPE_RELATES)
1959
1959
1960 assert IssueRelation.create(:issue_from => independentIssue,
1960 assert IssueRelation.create(:issue_from => independentIssue,
1961 :issue_to => childIssue2_1,
1961 :issue_to => childIssue2_1,
1962 :relation_type => IssueRelation::TYPE_RELATES)
1962 :relation_type => IssueRelation::TYPE_RELATES)
1963
1963
1964 assert_equal [childIssue1_1.id, parentIssue2.id, childIssue2_1.id, independentIssue.id].sort,
1964 assert_equal [childIssue1_1.id, parentIssue2.id, childIssue2_1.id, independentIssue.id].sort,
1965 parentIssue1.all_dependent_issues.collect(&:id).uniq.sort
1965 parentIssue1.all_dependent_issues.collect(&:id).uniq.sort
1966
1966
1967 end
1967 end
1968
1968
1969 def test_all_dependent_issues_with_persistent_circular_dependency
1969 def test_all_dependent_issues_with_persistent_circular_dependency
1970 IssueRelation.delete_all
1970 IssueRelation.delete_all
1971 assert IssueRelation.create!(:issue_from => Issue.find(1),
1971 assert IssueRelation.create!(:issue_from => Issue.find(1),
1972 :issue_to => Issue.find(2),
1972 :issue_to => Issue.find(2),
1973 :relation_type => IssueRelation::TYPE_PRECEDES)
1973 :relation_type => IssueRelation::TYPE_PRECEDES)
1974 assert IssueRelation.create!(:issue_from => Issue.find(2),
1974 assert IssueRelation.create!(:issue_from => Issue.find(2),
1975 :issue_to => Issue.find(3),
1975 :issue_to => Issue.find(3),
1976 :relation_type => IssueRelation::TYPE_PRECEDES)
1976 :relation_type => IssueRelation::TYPE_PRECEDES)
1977
1977
1978 r = IssueRelation.create!(:issue_from => Issue.find(3),
1978 r = IssueRelation.create!(:issue_from => Issue.find(3),
1979 :issue_to => Issue.find(7),
1979 :issue_to => Issue.find(7),
1980 :relation_type => IssueRelation::TYPE_PRECEDES)
1980 :relation_type => IssueRelation::TYPE_PRECEDES)
1981 IssueRelation.update_all("issue_to_id = 1", ["id = ?", r.id])
1981 IssueRelation.update_all("issue_to_id = 1", ["id = ?", r.id])
1982
1982
1983 assert_equal [2, 3], Issue.find(1).all_dependent_issues.collect(&:id).sort
1983 assert_equal [2, 3], Issue.find(1).all_dependent_issues.collect(&:id).sort
1984 end
1984 end
1985
1985
1986 def test_all_dependent_issues_with_persistent_multiple_circular_dependencies
1986 def test_all_dependent_issues_with_persistent_multiple_circular_dependencies
1987 IssueRelation.delete_all
1987 IssueRelation.delete_all
1988 assert IssueRelation.create!(:issue_from => Issue.find(1),
1988 assert IssueRelation.create!(:issue_from => Issue.find(1),
1989 :issue_to => Issue.find(2),
1989 :issue_to => Issue.find(2),
1990 :relation_type => IssueRelation::TYPE_RELATES)
1990 :relation_type => IssueRelation::TYPE_RELATES)
1991 assert IssueRelation.create!(:issue_from => Issue.find(2),
1991 assert IssueRelation.create!(:issue_from => Issue.find(2),
1992 :issue_to => Issue.find(3),
1992 :issue_to => Issue.find(3),
1993 :relation_type => IssueRelation::TYPE_RELATES)
1993 :relation_type => IssueRelation::TYPE_RELATES)
1994 assert IssueRelation.create!(:issue_from => Issue.find(3),
1994 assert IssueRelation.create!(:issue_from => Issue.find(3),
1995 :issue_to => Issue.find(8),
1995 :issue_to => Issue.find(8),
1996 :relation_type => IssueRelation::TYPE_RELATES)
1996 :relation_type => IssueRelation::TYPE_RELATES)
1997
1997
1998 r = IssueRelation.create!(:issue_from => Issue.find(8),
1998 r = IssueRelation.create!(:issue_from => Issue.find(8),
1999 :issue_to => Issue.find(7),
1999 :issue_to => Issue.find(7),
2000 :relation_type => IssueRelation::TYPE_RELATES)
2000 :relation_type => IssueRelation::TYPE_RELATES)
2001 IssueRelation.update_all("issue_to_id = 2", ["id = ?", r.id])
2001 IssueRelation.update_all("issue_to_id = 2", ["id = ?", r.id])
2002
2002
2003 r = IssueRelation.create!(:issue_from => Issue.find(3),
2003 r = IssueRelation.create!(:issue_from => Issue.find(3),
2004 :issue_to => Issue.find(7),
2004 :issue_to => Issue.find(7),
2005 :relation_type => IssueRelation::TYPE_RELATES)
2005 :relation_type => IssueRelation::TYPE_RELATES)
2006 IssueRelation.update_all("issue_to_id = 1", ["id = ?", r.id])
2006 IssueRelation.update_all("issue_to_id = 1", ["id = ?", r.id])
2007
2007
2008 assert_equal [2, 3, 8], Issue.find(1).all_dependent_issues.collect(&:id).sort
2008 assert_equal [2, 3, 8], Issue.find(1).all_dependent_issues.collect(&:id).sort
2009 end
2009 end
2010
2010
2011 test "#done_ratio should use the issue_status according to Setting.issue_done_ratio" do
2011 test "#done_ratio should use the issue_status according to Setting.issue_done_ratio" do
2012 @issue = Issue.find(1)
2012 @issue = Issue.find(1)
2013 @issue_status = IssueStatus.find(1)
2013 @issue_status = IssueStatus.find(1)
2014 @issue_status.update_attribute(:default_done_ratio, 50)
2014 @issue_status.update_attribute(:default_done_ratio, 50)
2015 @issue2 = Issue.find(2)
2015 @issue2 = Issue.find(2)
2016 @issue_status2 = IssueStatus.find(2)
2016 @issue_status2 = IssueStatus.find(2)
2017 @issue_status2.update_attribute(:default_done_ratio, 0)
2017 @issue_status2.update_attribute(:default_done_ratio, 0)
2018
2018
2019 with_settings :issue_done_ratio => 'issue_field' do
2019 with_settings :issue_done_ratio => 'issue_field' do
2020 assert_equal 0, @issue.done_ratio
2020 assert_equal 0, @issue.done_ratio
2021 assert_equal 30, @issue2.done_ratio
2021 assert_equal 30, @issue2.done_ratio
2022 end
2022 end
2023
2023
2024 with_settings :issue_done_ratio => 'issue_status' do
2024 with_settings :issue_done_ratio => 'issue_status' do
2025 assert_equal 50, @issue.done_ratio
2025 assert_equal 50, @issue.done_ratio
2026 assert_equal 0, @issue2.done_ratio
2026 assert_equal 0, @issue2.done_ratio
2027 end
2027 end
2028 end
2028 end
2029
2029
2030 test "#update_done_ratio_from_issue_status should update done_ratio according to Setting.issue_done_ratio" do
2030 test "#update_done_ratio_from_issue_status should update done_ratio according to Setting.issue_done_ratio" do
2031 @issue = Issue.find(1)
2031 @issue = Issue.find(1)
2032 @issue_status = IssueStatus.find(1)
2032 @issue_status = IssueStatus.find(1)
2033 @issue_status.update_attribute(:default_done_ratio, 50)
2033 @issue_status.update_attribute(:default_done_ratio, 50)
2034 @issue2 = Issue.find(2)
2034 @issue2 = Issue.find(2)
2035 @issue_status2 = IssueStatus.find(2)
2035 @issue_status2 = IssueStatus.find(2)
2036 @issue_status2.update_attribute(:default_done_ratio, 0)
2036 @issue_status2.update_attribute(:default_done_ratio, 0)
2037
2037
2038 with_settings :issue_done_ratio => 'issue_field' do
2038 with_settings :issue_done_ratio => 'issue_field' do
2039 @issue.update_done_ratio_from_issue_status
2039 @issue.update_done_ratio_from_issue_status
2040 @issue2.update_done_ratio_from_issue_status
2040 @issue2.update_done_ratio_from_issue_status
2041
2041
2042 assert_equal 0, @issue.read_attribute(:done_ratio)
2042 assert_equal 0, @issue.read_attribute(:done_ratio)
2043 assert_equal 30, @issue2.read_attribute(:done_ratio)
2043 assert_equal 30, @issue2.read_attribute(:done_ratio)
2044 end
2044 end
2045
2045
2046 with_settings :issue_done_ratio => 'issue_status' do
2046 with_settings :issue_done_ratio => 'issue_status' do
2047 @issue.update_done_ratio_from_issue_status
2047 @issue.update_done_ratio_from_issue_status
2048 @issue2.update_done_ratio_from_issue_status
2048 @issue2.update_done_ratio_from_issue_status
2049
2049
2050 assert_equal 50, @issue.read_attribute(:done_ratio)
2050 assert_equal 50, @issue.read_attribute(:done_ratio)
2051 assert_equal 0, @issue2.read_attribute(:done_ratio)
2051 assert_equal 0, @issue2.read_attribute(:done_ratio)
2052 end
2052 end
2053 end
2053 end
2054
2054
2055 test "#by_tracker" do
2055 test "#by_tracker" do
2056 User.current = User.anonymous
2056 User.current = User.anonymous
2057 groups = Issue.by_tracker(Project.find(1))
2057 groups = Issue.by_tracker(Project.find(1))
2058 assert_equal 3, groups.count
2058 assert_equal 3, groups.count
2059 assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i}
2059 assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i}
2060 end
2060 end
2061
2061
2062 test "#by_version" do
2062 test "#by_version" do
2063 User.current = User.anonymous
2063 User.current = User.anonymous
2064 groups = Issue.by_version(Project.find(1))
2064 groups = Issue.by_version(Project.find(1))
2065 assert_equal 3, groups.count
2065 assert_equal 3, groups.count
2066 assert_equal 3, groups.inject(0) {|sum, group| sum + group['total'].to_i}
2066 assert_equal 3, groups.inject(0) {|sum, group| sum + group['total'].to_i}
2067 end
2067 end
2068
2068
2069 test "#by_priority" do
2069 test "#by_priority" do
2070 User.current = User.anonymous
2070 User.current = User.anonymous
2071 groups = Issue.by_priority(Project.find(1))
2071 groups = Issue.by_priority(Project.find(1))
2072 assert_equal 4, groups.count
2072 assert_equal 4, groups.count
2073 assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i}
2073 assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i}
2074 end
2074 end
2075
2075
2076 test "#by_category" do
2076 test "#by_category" do
2077 User.current = User.anonymous
2077 User.current = User.anonymous
2078 groups = Issue.by_category(Project.find(1))
2078 groups = Issue.by_category(Project.find(1))
2079 assert_equal 2, groups.count
2079 assert_equal 2, groups.count
2080 assert_equal 3, groups.inject(0) {|sum, group| sum + group['total'].to_i}
2080 assert_equal 3, groups.inject(0) {|sum, group| sum + group['total'].to_i}
2081 end
2081 end
2082
2082
2083 test "#by_assigned_to" do
2083 test "#by_assigned_to" do
2084 User.current = User.anonymous
2084 User.current = User.anonymous
2085 groups = Issue.by_assigned_to(Project.find(1))
2085 groups = Issue.by_assigned_to(Project.find(1))
2086 assert_equal 2, groups.count
2086 assert_equal 2, groups.count
2087 assert_equal 2, groups.inject(0) {|sum, group| sum + group['total'].to_i}
2087 assert_equal 2, groups.inject(0) {|sum, group| sum + group['total'].to_i}
2088 end
2088 end
2089
2089
2090 test "#by_author" do
2090 test "#by_author" do
2091 User.current = User.anonymous
2091 User.current = User.anonymous
2092 groups = Issue.by_author(Project.find(1))
2092 groups = Issue.by_author(Project.find(1))
2093 assert_equal 4, groups.count
2093 assert_equal 4, groups.count
2094 assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i}
2094 assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i}
2095 end
2095 end
2096
2096
2097 test "#by_subproject" do
2097 test "#by_subproject" do
2098 User.current = User.anonymous
2098 User.current = User.anonymous
2099 groups = Issue.by_subproject(Project.find(1))
2099 groups = Issue.by_subproject(Project.find(1))
2100 # Private descendant not visible
2100 # Private descendant not visible
2101 assert_equal 1, groups.count
2101 assert_equal 1, groups.count
2102 assert_equal 2, groups.inject(0) {|sum, group| sum + group['total'].to_i}
2102 assert_equal 2, groups.inject(0) {|sum, group| sum + group['total'].to_i}
2103 end
2103 end
2104
2104
2105 def test_recently_updated_scope
2105 def test_recently_updated_scope
2106 #should return the last updated issue
2106 #should return the last updated issue
2107 assert_equal Issue.reorder("updated_on DESC").first, Issue.recently_updated.limit(1).first
2107 assert_equal Issue.reorder("updated_on DESC").first, Issue.recently_updated.limit(1).first
2108 end
2108 end
2109
2109
2110 def test_on_active_projects_scope
2110 def test_on_active_projects_scope
2111 assert Project.find(2).archive
2111 assert Project.find(2).archive
2112
2112
2113 before = Issue.on_active_project.length
2113 before = Issue.on_active_project.length
2114 # test inclusion to results
2114 # test inclusion to results
2115 issue = Issue.generate!(:tracker => Project.find(2).trackers.first)
2115 issue = Issue.generate!(:tracker => Project.find(2).trackers.first)
2116 assert_equal before + 1, Issue.on_active_project.length
2116 assert_equal before + 1, Issue.on_active_project.length
2117
2117
2118 # Move to an archived project
2118 # Move to an archived project
2119 issue.project = Project.find(2)
2119 issue.project = Project.find(2)
2120 assert issue.save
2120 assert issue.save
2121 assert_equal before, Issue.on_active_project.length
2121 assert_equal before, Issue.on_active_project.length
2122 end
2122 end
2123
2123
2124 test "Issue#recipients should include project recipients" do
2124 test "Issue#recipients should include project recipients" do
2125 issue = Issue.generate!
2125 issue = Issue.generate!
2126 assert issue.project.recipients.present?
2126 assert issue.project.recipients.present?
2127 issue.project.recipients.each do |project_recipient|
2127 issue.project.recipients.each do |project_recipient|
2128 assert issue.recipients.include?(project_recipient)
2128 assert issue.recipients.include?(project_recipient)
2129 end
2129 end
2130 end
2130 end
2131
2131
2132 test "Issue#recipients should include the author if the author is active" do
2132 test "Issue#recipients should include the author if the author is active" do
2133 issue = Issue.generate!(:author => User.generate!)
2133 issue = Issue.generate!(:author => User.generate!)
2134 assert issue.author, "No author set for Issue"
2134 assert issue.author, "No author set for Issue"
2135 assert issue.recipients.include?(issue.author.mail)
2135 assert issue.recipients.include?(issue.author.mail)
2136 end
2136 end
2137
2137
2138 test "Issue#recipients should include the assigned to user if the assigned to user is active" do
2138 test "Issue#recipients should include the assigned to user if the assigned to user is active" do
2139 issue = Issue.generate!(:assigned_to => User.generate!)
2139 issue = Issue.generate!(:assigned_to => User.generate!)
2140 assert issue.assigned_to, "No assigned_to set for Issue"
2140 assert issue.assigned_to, "No assigned_to set for Issue"
2141 assert issue.recipients.include?(issue.assigned_to.mail)
2141 assert issue.recipients.include?(issue.assigned_to.mail)
2142 end
2142 end
2143
2143
2144 test "Issue#recipients should not include users who opt out of all email" do
2144 test "Issue#recipients should not include users who opt out of all email" do
2145 issue = Issue.generate!(:author => User.generate!)
2145 issue = Issue.generate!(:author => User.generate!)
2146 issue.author.update_attribute(:mail_notification, :none)
2146 issue.author.update_attribute(:mail_notification, :none)
2147 assert !issue.recipients.include?(issue.author.mail)
2147 assert !issue.recipients.include?(issue.author.mail)
2148 end
2148 end
2149
2149
2150 test "Issue#recipients should not include the issue author if they are only notified of assigned issues" do
2150 test "Issue#recipients should not include the issue author if they are only notified of assigned issues" do
2151 issue = Issue.generate!(:author => User.generate!)
2151 issue = Issue.generate!(:author => User.generate!)
2152 issue.author.update_attribute(:mail_notification, :only_assigned)
2152 issue.author.update_attribute(:mail_notification, :only_assigned)
2153 assert !issue.recipients.include?(issue.author.mail)
2153 assert !issue.recipients.include?(issue.author.mail)
2154 end
2154 end
2155
2155
2156 test "Issue#recipients should not include the assigned user if they are only notified of owned issues" do
2156 test "Issue#recipients should not include the assigned user if they are only notified of owned issues" do
2157 issue = Issue.generate!(:assigned_to => User.generate!)
2157 issue = Issue.generate!(:assigned_to => User.generate!)
2158 issue.assigned_to.update_attribute(:mail_notification, :only_owner)
2158 issue.assigned_to.update_attribute(:mail_notification, :only_owner)
2159 assert !issue.recipients.include?(issue.assigned_to.mail)
2159 assert !issue.recipients.include?(issue.assigned_to.mail)
2160 end
2160 end
2161
2161
2162 def test_last_journal_id_with_journals_should_return_the_journal_id
2162 def test_last_journal_id_with_journals_should_return_the_journal_id
2163 assert_equal 2, Issue.find(1).last_journal_id
2163 assert_equal 2, Issue.find(1).last_journal_id
2164 end
2164 end
2165
2165
2166 def test_last_journal_id_without_journals_should_return_nil
2166 def test_last_journal_id_without_journals_should_return_nil
2167 assert_nil Issue.find(3).last_journal_id
2167 assert_nil Issue.find(3).last_journal_id
2168 end
2168 end
2169
2169
2170 def test_journals_after_should_return_journals_with_greater_id
2170 def test_journals_after_should_return_journals_with_greater_id
2171 assert_equal [Journal.find(2)], Issue.find(1).journals_after('1')
2171 assert_equal [Journal.find(2)], Issue.find(1).journals_after('1')
2172 assert_equal [], Issue.find(1).journals_after('2')
2172 assert_equal [], Issue.find(1).journals_after('2')
2173 end
2173 end
2174
2174
2175 def test_journals_after_with_blank_arg_should_return_all_journals
2175 def test_journals_after_with_blank_arg_should_return_all_journals
2176 assert_equal [Journal.find(1), Journal.find(2)], Issue.find(1).journals_after('')
2176 assert_equal [Journal.find(1), Journal.find(2)], Issue.find(1).journals_after('')
2177 end
2177 end
2178
2178
2179 def test_css_classes_should_include_tracker
2179 def test_css_classes_should_include_tracker
2180 issue = Issue.new(:tracker => Tracker.find(2))
2180 issue = Issue.new(:tracker => Tracker.find(2))
2181 classes = issue.css_classes.split(' ')
2181 classes = issue.css_classes.split(' ')
2182 assert_include 'tracker-2', classes
2182 assert_include 'tracker-2', classes
2183 end
2183 end
2184
2184
2185 def test_css_classes_should_include_priority
2185 def test_css_classes_should_include_priority
2186 issue = Issue.new(:priority => IssuePriority.find(8))
2186 issue = Issue.new(:priority => IssuePriority.find(8))
2187 classes = issue.css_classes.split(' ')
2187 classes = issue.css_classes.split(' ')
2188 assert_include 'priority-8', classes
2188 assert_include 'priority-8', classes
2189 assert_include 'priority-highest', classes
2189 assert_include 'priority-highest', classes
2190 end
2190 end
2191
2191
2192 def test_css_classes_should_include_user_assignment
2192 def test_css_classes_should_include_user_assignment
2193 issue = Issue.generate(:assigned_to_id => 2)
2193 issue = Issue.generate(:assigned_to_id => 2)
2194 assert_include 'assigned-to-me', issue.css_classes(User.find(2))
2194 assert_include 'assigned-to-me', issue.css_classes(User.find(2))
2195 assert_not_include 'assigned-to-me', issue.css_classes(User.find(3))
2195 assert_not_include 'assigned-to-me', issue.css_classes(User.find(3))
2196 end
2196 end
2197
2197
2198 def test_css_classes_should_include_user_group_assignment
2198 def test_css_classes_should_include_user_group_assignment
2199 issue = Issue.generate(:assigned_to_id => 10)
2199 issue = Issue.generate(:assigned_to_id => 10)
2200 assert_include 'assigned-to-my-group', issue.css_classes(Group.find(10).users.first)
2200 assert_include 'assigned-to-my-group', issue.css_classes(Group.find(10).users.first)
2201 assert_not_include 'assigned-to-my-group', issue.css_classes(User.find(3))
2201 assert_not_include 'assigned-to-my-group', issue.css_classes(User.find(3))
2202 end
2202 end
2203
2203
2204 def test_save_attachments_with_hash_should_save_attachments_in_keys_order
2204 def test_save_attachments_with_hash_should_save_attachments_in_keys_order
2205 set_tmp_attachments_directory
2205 set_tmp_attachments_directory
2206 issue = Issue.generate!
2206 issue = Issue.generate!
2207 issue.save_attachments({
2207 issue.save_attachments({
2208 'p0' => {'file' => mock_file_with_options(:original_filename => 'upload')},
2208 'p0' => {'file' => mock_file_with_options(:original_filename => 'upload')},
2209 '3' => {'file' => mock_file_with_options(:original_filename => 'bar')},
2209 '3' => {'file' => mock_file_with_options(:original_filename => 'bar')},
2210 '1' => {'file' => mock_file_with_options(:original_filename => 'foo')}
2210 '1' => {'file' => mock_file_with_options(:original_filename => 'foo')}
2211 })
2211 })
2212 issue.attach_saved_attachments
2212 issue.attach_saved_attachments
2213
2213
2214 assert_equal 3, issue.reload.attachments.count
2214 assert_equal 3, issue.reload.attachments.count
2215 assert_equal %w(upload foo bar), issue.attachments.map(&:filename)
2215 assert_equal %w(upload foo bar), issue.attachments.map(&:filename)
2216 end
2216 end
2217
2217
2218 def test_closed_on_should_be_nil_when_creating_an_open_issue
2218 def test_closed_on_should_be_nil_when_creating_an_open_issue
2219 issue = Issue.generate!(:status_id => 1).reload
2219 issue = Issue.generate!(:status_id => 1).reload
2220 assert !issue.closed?
2220 assert !issue.closed?
2221 assert_nil issue.closed_on
2221 assert_nil issue.closed_on
2222 end
2222 end
2223
2223
2224 def test_closed_on_should_be_set_when_creating_a_closed_issue
2224 def test_closed_on_should_be_set_when_creating_a_closed_issue
2225 issue = Issue.generate!(:status_id => 5).reload
2225 issue = Issue.generate!(:status_id => 5).reload
2226 assert issue.closed?
2226 assert issue.closed?
2227 assert_not_nil issue.closed_on
2227 assert_not_nil issue.closed_on
2228 assert_equal issue.updated_on, issue.closed_on
2228 assert_equal issue.updated_on, issue.closed_on
2229 assert_equal issue.created_on, issue.closed_on
2229 assert_equal issue.created_on, issue.closed_on
2230 end
2230 end
2231
2231
2232 def test_closed_on_should_be_nil_when_updating_an_open_issue
2232 def test_closed_on_should_be_nil_when_updating_an_open_issue
2233 issue = Issue.find(1)
2233 issue = Issue.find(1)
2234 issue.subject = 'Not closed yet'
2234 issue.subject = 'Not closed yet'
2235 issue.save!
2235 issue.save!
2236 issue.reload
2236 issue.reload
2237 assert_nil issue.closed_on
2237 assert_nil issue.closed_on
2238 end
2238 end
2239
2239
2240 def test_closed_on_should_be_set_when_closing_an_open_issue
2240 def test_closed_on_should_be_set_when_closing_an_open_issue
2241 issue = Issue.find(1)
2241 issue = Issue.find(1)
2242 issue.subject = 'Now closed'
2242 issue.subject = 'Now closed'
2243 issue.status_id = 5
2243 issue.status_id = 5
2244 issue.save!
2244 issue.save!
2245 issue.reload
2245 issue.reload
2246 assert_not_nil issue.closed_on
2246 assert_not_nil issue.closed_on
2247 assert_equal issue.updated_on, issue.closed_on
2247 assert_equal issue.updated_on, issue.closed_on
2248 end
2248 end
2249
2249
2250 def test_closed_on_should_not_be_updated_when_updating_a_closed_issue
2250 def test_closed_on_should_not_be_updated_when_updating_a_closed_issue
2251 issue = Issue.open(false).first
2251 issue = Issue.open(false).first
2252 was_closed_on = issue.closed_on
2252 was_closed_on = issue.closed_on
2253 assert_not_nil was_closed_on
2253 assert_not_nil was_closed_on
2254 issue.subject = 'Updating a closed issue'
2254 issue.subject = 'Updating a closed issue'
2255 issue.save!
2255 issue.save!
2256 issue.reload
2256 issue.reload
2257 assert_equal was_closed_on, issue.closed_on
2257 assert_equal was_closed_on, issue.closed_on
2258 end
2258 end
2259
2259
2260 def test_closed_on_should_be_preserved_when_reopening_a_closed_issue
2260 def test_closed_on_should_be_preserved_when_reopening_a_closed_issue
2261 issue = Issue.open(false).first
2261 issue = Issue.open(false).first
2262 was_closed_on = issue.closed_on
2262 was_closed_on = issue.closed_on
2263 assert_not_nil was_closed_on
2263 assert_not_nil was_closed_on
2264 issue.subject = 'Reopening a closed issue'
2264 issue.subject = 'Reopening a closed issue'
2265 issue.status_id = 1
2265 issue.status_id = 1
2266 issue.save!
2266 issue.save!
2267 issue.reload
2267 issue.reload
2268 assert !issue.closed?
2268 assert !issue.closed?
2269 assert_equal was_closed_on, issue.closed_on
2269 assert_equal was_closed_on, issue.closed_on
2270 end
2270 end
2271
2271
2272 def test_status_was_should_return_nil_for_new_issue
2272 def test_status_was_should_return_nil_for_new_issue
2273 issue = Issue.new
2273 issue = Issue.new
2274 assert_nil issue.status_was
2274 assert_nil issue.status_was
2275 end
2275 end
2276
2276
2277 def test_status_was_should_return_status_before_change
2277 def test_status_was_should_return_status_before_change
2278 issue = Issue.find(1)
2278 issue = Issue.find(1)
2279 issue.status = IssueStatus.find(2)
2279 issue.status = IssueStatus.find(2)
2280 assert_equal IssueStatus.find(1), issue.status_was
2280 assert_equal IssueStatus.find(1), issue.status_was
2281 end
2281 end
2282
2282
2283 def test_status_was_should_be_reset_on_save
2283 def test_status_was_should_be_reset_on_save
2284 issue = Issue.find(1)
2284 issue = Issue.find(1)
2285 issue.status = IssueStatus.find(2)
2285 issue.status = IssueStatus.find(2)
2286 assert_equal IssueStatus.find(1), issue.status_was
2286 assert_equal IssueStatus.find(1), issue.status_was
2287 assert issue.save!
2287 assert issue.save!
2288 assert_equal IssueStatus.find(2), issue.status_was
2288 assert_equal IssueStatus.find(2), issue.status_was
2289 end
2289 end
2290 end
2290 end
@@ -1,1135 +1,1135
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2013 Jean-Philippe Lang
2 # Copyright (C) 2006-2013 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 UserTest < ActiveSupport::TestCase
20 class UserTest < ActiveSupport::TestCase
21 fixtures :users, :members, :projects, :roles, :member_roles, :auth_sources,
21 fixtures :users, :members, :projects, :roles, :member_roles, :auth_sources,
22 :trackers, :issue_statuses,
22 :trackers, :issue_statuses,
23 :projects_trackers,
23 :projects_trackers,
24 :watchers,
24 :watchers,
25 :issue_categories, :enumerations, :issues,
25 :issue_categories, :enumerations, :issues,
26 :journals, :journal_details,
26 :journals, :journal_details,
27 :groups_users,
27 :groups_users,
28 :enabled_modules
28 :enabled_modules
29
29
30 def setup
30 def setup
31 @admin = User.find(1)
31 @admin = User.find(1)
32 @jsmith = User.find(2)
32 @jsmith = User.find(2)
33 @dlopper = User.find(3)
33 @dlopper = User.find(3)
34 end
34 end
35
35
36 def test_sorted_scope_should_sort_user_by_display_name
36 def test_sorted_scope_should_sort_user_by_display_name
37 assert_equal User.all.map(&:name).map(&:downcase).sort, User.sorted.all.map(&:name).map(&:downcase)
37 assert_equal User.all.map(&:name).map(&:downcase).sort, User.sorted.all.map(&:name).map(&:downcase)
38 end
38 end
39
39
40 def test_generate
40 def test_generate
41 User.generate!(:firstname => 'Testing connection')
41 User.generate!(:firstname => 'Testing connection')
42 User.generate!(:firstname => 'Testing connection')
42 User.generate!(:firstname => 'Testing connection')
43 assert_equal 2, User.where(:firstname => 'Testing connection').count
43 assert_equal 2, User.where(:firstname => 'Testing connection').count
44 end
44 end
45
45
46 def test_truth
46 def test_truth
47 assert_kind_of User, @jsmith
47 assert_kind_of User, @jsmith
48 end
48 end
49
49
50 def test_mail_should_be_stripped
50 def test_mail_should_be_stripped
51 u = User.new
51 u = User.new
52 u.mail = " foo@bar.com "
52 u.mail = " foo@bar.com "
53 assert_equal "foo@bar.com", u.mail
53 assert_equal "foo@bar.com", u.mail
54 end
54 end
55
55
56 def test_mail_validation
56 def test_mail_validation
57 u = User.new
57 u = User.new
58 u.mail = ''
58 u.mail = ''
59 assert !u.valid?
59 assert !u.valid?
60 assert_include I18n.translate('activerecord.errors.messages.blank'), u.errors[:mail]
60 assert_include I18n.translate('activerecord.errors.messages.blank'), u.errors[:mail]
61 end
61 end
62
62
63 def test_login_length_validation
63 def test_login_length_validation
64 user = User.new(:firstname => "new", :lastname => "user", :mail => "newuser@somenet.foo")
64 user = User.new(:firstname => "new", :lastname => "user", :mail => "newuser@somenet.foo")
65 user.login = "x" * (User::LOGIN_LENGTH_LIMIT+1)
65 user.login = "x" * (User::LOGIN_LENGTH_LIMIT+1)
66 assert !user.valid?
66 assert !user.valid?
67
67
68 user.login = "x" * (User::LOGIN_LENGTH_LIMIT)
68 user.login = "x" * (User::LOGIN_LENGTH_LIMIT)
69 assert user.valid?
69 assert user.valid?
70 assert user.save
70 assert user.save
71 end
71 end
72
72
73 def test_generate_password_should_respect_minimum_password_length
73 def test_generate_password_should_respect_minimum_password_length
74 with_settings :password_min_length => 15 do
74 with_settings :password_min_length => 15 do
75 user = User.generate!(:generate_password => true)
75 user = User.generate!(:generate_password => true)
76 assert user.password.length >= 15
76 assert user.password.length >= 15
77 end
77 end
78 end
78 end
79
79
80 def test_generate_password_should_not_generate_password_with_less_than_10_characters
80 def test_generate_password_should_not_generate_password_with_less_than_10_characters
81 with_settings :password_min_length => 4 do
81 with_settings :password_min_length => 4 do
82 user = User.generate!(:generate_password => true)
82 user = User.generate!(:generate_password => true)
83 assert user.password.length >= 10
83 assert user.password.length >= 10
84 end
84 end
85 end
85 end
86
86
87 def test_generate_password_on_create_should_set_password
87 def test_generate_password_on_create_should_set_password
88 user = User.new(:firstname => "new", :lastname => "user", :mail => "newuser@somenet.foo")
88 user = User.new(:firstname => "new", :lastname => "user", :mail => "newuser@somenet.foo")
89 user.login = "newuser"
89 user.login = "newuser"
90 user.generate_password = true
90 user.generate_password = true
91 assert user.save
91 assert user.save
92
92
93 password = user.password
93 password = user.password
94 assert user.check_password?(password)
94 assert user.check_password?(password)
95 end
95 end
96
96
97 def test_generate_password_on_update_should_update_password
97 def test_generate_password_on_update_should_update_password
98 user = User.find(2)
98 user = User.find(2)
99 hash = user.hashed_password
99 hash = user.hashed_password
100 user.generate_password = true
100 user.generate_password = true
101 assert user.save
101 assert user.save
102
102
103 password = user.password
103 password = user.password
104 assert user.check_password?(password)
104 assert user.check_password?(password)
105 assert_not_equal hash, user.reload.hashed_password
105 assert_not_equal hash, user.reload.hashed_password
106 end
106 end
107
107
108 def test_create
108 def test_create
109 user = User.new(:firstname => "new", :lastname => "user", :mail => "newuser@somenet.foo")
109 user = User.new(:firstname => "new", :lastname => "user", :mail => "newuser@somenet.foo")
110
110
111 user.login = "jsmith"
111 user.login = "jsmith"
112 user.password, user.password_confirmation = "password", "password"
112 user.password, user.password_confirmation = "password", "password"
113 # login uniqueness
113 # login uniqueness
114 assert !user.save
114 assert !user.save
115 assert_equal 1, user.errors.count
115 assert_equal 1, user.errors.count
116
116
117 user.login = "newuser"
117 user.login = "newuser"
118 user.password, user.password_confirmation = "password", "pass"
118 user.password, user.password_confirmation = "password", "pass"
119 # password confirmation
119 # password confirmation
120 assert !user.save
120 assert !user.save
121 assert_equal 1, user.errors.count
121 assert_equal 1, user.errors.count
122
122
123 user.password, user.password_confirmation = "password", "password"
123 user.password, user.password_confirmation = "password", "password"
124 assert user.save
124 assert user.save
125 end
125 end
126
126
127 def test_user_before_create_should_set_the_mail_notification_to_the_default_setting
127 def test_user_before_create_should_set_the_mail_notification_to_the_default_setting
128 @user1 = User.generate!
128 @user1 = User.generate!
129 assert_equal 'only_my_events', @user1.mail_notification
129 assert_equal 'only_my_events', @user1.mail_notification
130 with_settings :default_notification_option => 'all' do
130 with_settings :default_notification_option => 'all' do
131 @user2 = User.generate!
131 @user2 = User.generate!
132 assert_equal 'all', @user2.mail_notification
132 assert_equal 'all', @user2.mail_notification
133 end
133 end
134 end
134 end
135
135
136 def test_user_login_should_be_case_insensitive
136 def test_user_login_should_be_case_insensitive
137 u = User.new(:firstname => "new", :lastname => "user", :mail => "newuser@somenet.foo")
137 u = User.new(:firstname => "new", :lastname => "user", :mail => "newuser@somenet.foo")
138 u.login = 'newuser'
138 u.login = 'newuser'
139 u.password, u.password_confirmation = "password", "password"
139 u.password, u.password_confirmation = "password", "password"
140 assert u.save
140 assert u.save
141 u = User.new(:firstname => "Similar", :lastname => "User", :mail => "similaruser@somenet.foo")
141 u = User.new(:firstname => "Similar", :lastname => "User", :mail => "similaruser@somenet.foo")
142 u.login = 'NewUser'
142 u.login = 'NewUser'
143 u.password, u.password_confirmation = "password", "password"
143 u.password, u.password_confirmation = "password", "password"
144 assert !u.save
144 assert !u.save
145 assert_include I18n.translate('activerecord.errors.messages.taken'), u.errors[:login]
145 assert_include I18n.translate('activerecord.errors.messages.taken'), u.errors[:login]
146 end
146 end
147
147
148 def test_mail_uniqueness_should_not_be_case_sensitive
148 def test_mail_uniqueness_should_not_be_case_sensitive
149 u = User.new(:firstname => "new", :lastname => "user", :mail => "newuser@somenet.foo")
149 u = User.new(:firstname => "new", :lastname => "user", :mail => "newuser@somenet.foo")
150 u.login = 'newuser1'
150 u.login = 'newuser1'
151 u.password, u.password_confirmation = "password", "password"
151 u.password, u.password_confirmation = "password", "password"
152 assert u.save
152 assert u.save
153
153
154 u = User.new(:firstname => "new", :lastname => "user", :mail => "newUser@Somenet.foo")
154 u = User.new(:firstname => "new", :lastname => "user", :mail => "newUser@Somenet.foo")
155 u.login = 'newuser2'
155 u.login = 'newuser2'
156 u.password, u.password_confirmation = "password", "password"
156 u.password, u.password_confirmation = "password", "password"
157 assert !u.save
157 assert !u.save
158 assert_include I18n.translate('activerecord.errors.messages.taken'), u.errors[:mail]
158 assert_include I18n.translate('activerecord.errors.messages.taken'), u.errors[:mail]
159 end
159 end
160
160
161 def test_update
161 def test_update
162 assert_equal "admin", @admin.login
162 assert_equal "admin", @admin.login
163 @admin.login = "john"
163 @admin.login = "john"
164 assert @admin.save, @admin.errors.full_messages.join("; ")
164 assert @admin.save, @admin.errors.full_messages.join("; ")
165 @admin.reload
165 @admin.reload
166 assert_equal "john", @admin.login
166 assert_equal "john", @admin.login
167 end
167 end
168
168
169 def test_update_should_not_fail_for_legacy_user_with_different_case_logins
169 def test_update_should_not_fail_for_legacy_user_with_different_case_logins
170 u1 = User.new(:firstname => "new", :lastname => "user", :mail => "newuser1@somenet.foo")
170 u1 = User.new(:firstname => "new", :lastname => "user", :mail => "newuser1@somenet.foo")
171 u1.login = 'newuser1'
171 u1.login = 'newuser1'
172 assert u1.save
172 assert u1.save
173
173
174 u2 = User.new(:firstname => "new", :lastname => "user", :mail => "newuser2@somenet.foo")
174 u2 = User.new(:firstname => "new", :lastname => "user", :mail => "newuser2@somenet.foo")
175 u2.login = 'newuser1'
175 u2.login = 'newuser1'
176 assert u2.save(:validate => false)
176 assert u2.save(:validate => false)
177
177
178 user = User.find(u2.id)
178 user = User.find(u2.id)
179 user.firstname = "firstname"
179 user.firstname = "firstname"
180 assert user.save, "Save failed"
180 assert user.save, "Save failed"
181 end
181 end
182
182
183 def test_destroy_should_delete_members_and_roles
183 def test_destroy_should_delete_members_and_roles
184 members = Member.find_all_by_user_id(2)
184 members = Member.find_all_by_user_id(2)
185 ms = members.size
185 ms = members.size
186 rs = members.collect(&:roles).flatten.size
186 rs = members.collect(&:roles).flatten.size
187
187
188 assert_difference 'Member.count', - ms do
188 assert_difference 'Member.count', - ms do
189 assert_difference 'MemberRole.count', - rs do
189 assert_difference 'MemberRole.count', - rs do
190 User.find(2).destroy
190 User.find(2).destroy
191 end
191 end
192 end
192 end
193
193
194 assert_nil User.find_by_id(2)
194 assert_nil User.find_by_id(2)
195 assert Member.find_all_by_user_id(2).empty?
195 assert Member.find_all_by_user_id(2).empty?
196 end
196 end
197
197
198 def test_destroy_should_update_attachments
198 def test_destroy_should_update_attachments
199 attachment = Attachment.create!(:container => Project.find(1),
199 attachment = Attachment.create!(:container => Project.find(1),
200 :file => uploaded_test_file("testfile.txt", "text/plain"),
200 :file => uploaded_test_file("testfile.txt", "text/plain"),
201 :author_id => 2)
201 :author_id => 2)
202
202
203 User.find(2).destroy
203 User.find(2).destroy
204 assert_nil User.find_by_id(2)
204 assert_nil User.find_by_id(2)
205 assert_equal User.anonymous, attachment.reload.author
205 assert_equal User.anonymous, attachment.reload.author
206 end
206 end
207
207
208 def test_destroy_should_update_comments
208 def test_destroy_should_update_comments
209 comment = Comment.create!(
209 comment = Comment.create!(
210 :commented => News.create!(:project_id => 1, :author_id => 1, :title => 'foo', :description => 'foo'),
210 :commented => News.create!(:project_id => 1, :author_id => 1, :title => 'foo', :description => 'foo'),
211 :author => User.find(2),
211 :author => User.find(2),
212 :comments => 'foo'
212 :comments => 'foo'
213 )
213 )
214
214
215 User.find(2).destroy
215 User.find(2).destroy
216 assert_nil User.find_by_id(2)
216 assert_nil User.find_by_id(2)
217 assert_equal User.anonymous, comment.reload.author
217 assert_equal User.anonymous, comment.reload.author
218 end
218 end
219
219
220 def test_destroy_should_update_issues
220 def test_destroy_should_update_issues
221 issue = Issue.create!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'foo')
221 issue = Issue.create!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'foo')
222
222
223 User.find(2).destroy
223 User.find(2).destroy
224 assert_nil User.find_by_id(2)
224 assert_nil User.find_by_id(2)
225 assert_equal User.anonymous, issue.reload.author
225 assert_equal User.anonymous, issue.reload.author
226 end
226 end
227
227
228 def test_destroy_should_unassign_issues
228 def test_destroy_should_unassign_issues
229 issue = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'foo', :assigned_to_id => 2)
229 issue = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'foo', :assigned_to_id => 2)
230
230
231 User.find(2).destroy
231 User.find(2).destroy
232 assert_nil User.find_by_id(2)
232 assert_nil User.find_by_id(2)
233 assert_nil issue.reload.assigned_to
233 assert_nil issue.reload.assigned_to
234 end
234 end
235
235
236 def test_destroy_should_update_journals
236 def test_destroy_should_update_journals
237 issue = Issue.create!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'foo')
237 issue = Issue.create!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'foo')
238 issue.init_journal(User.find(2), "update")
238 issue.init_journal(User.find(2), "update")
239 issue.save!
239 issue.save!
240
240
241 User.find(2).destroy
241 User.find(2).destroy
242 assert_nil User.find_by_id(2)
242 assert_nil User.find_by_id(2)
243 assert_equal User.anonymous, issue.journals.first.reload.user
243 assert_equal User.anonymous, issue.journals.first.reload.user
244 end
244 end
245
245
246 def test_destroy_should_update_journal_details_old_value
246 def test_destroy_should_update_journal_details_old_value
247 issue = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'foo', :assigned_to_id => 2)
247 issue = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'foo', :assigned_to_id => 2)
248 issue.init_journal(User.find(1), "update")
248 issue.init_journal(User.find(1), "update")
249 issue.assigned_to_id = nil
249 issue.assigned_to_id = nil
250 assert_difference 'JournalDetail.count' do
250 assert_difference 'JournalDetail.count' do
251 issue.save!
251 issue.save!
252 end
252 end
253 journal_detail = JournalDetail.first(:order => 'id DESC')
253 journal_detail = JournalDetail.first(:order => 'id DESC')
254 assert_equal '2', journal_detail.old_value
254 assert_equal '2', journal_detail.old_value
255
255
256 User.find(2).destroy
256 User.find(2).destroy
257 assert_nil User.find_by_id(2)
257 assert_nil User.find_by_id(2)
258 assert_equal User.anonymous.id.to_s, journal_detail.reload.old_value
258 assert_equal User.anonymous.id.to_s, journal_detail.reload.old_value
259 end
259 end
260
260
261 def test_destroy_should_update_journal_details_value
261 def test_destroy_should_update_journal_details_value
262 issue = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'foo')
262 issue = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'foo')
263 issue.init_journal(User.find(1), "update")
263 issue.init_journal(User.find(1), "update")
264 issue.assigned_to_id = 2
264 issue.assigned_to_id = 2
265 assert_difference 'JournalDetail.count' do
265 assert_difference 'JournalDetail.count' do
266 issue.save!
266 issue.save!
267 end
267 end
268 journal_detail = JournalDetail.first(:order => 'id DESC')
268 journal_detail = JournalDetail.first(:order => 'id DESC')
269 assert_equal '2', journal_detail.value
269 assert_equal '2', journal_detail.value
270
270
271 User.find(2).destroy
271 User.find(2).destroy
272 assert_nil User.find_by_id(2)
272 assert_nil User.find_by_id(2)
273 assert_equal User.anonymous.id.to_s, journal_detail.reload.value
273 assert_equal User.anonymous.id.to_s, journal_detail.reload.value
274 end
274 end
275
275
276 def test_destroy_should_update_messages
276 def test_destroy_should_update_messages
277 board = Board.create!(:project_id => 1, :name => 'Board', :description => 'Board')
277 board = Board.create!(:project_id => 1, :name => 'Board', :description => 'Board')
278 message = Message.create!(:board_id => board.id, :author_id => 2, :subject => 'foo', :content => 'foo')
278 message = Message.create!(:board_id => board.id, :author_id => 2, :subject => 'foo', :content => 'foo')
279
279
280 User.find(2).destroy
280 User.find(2).destroy
281 assert_nil User.find_by_id(2)
281 assert_nil User.find_by_id(2)
282 assert_equal User.anonymous, message.reload.author
282 assert_equal User.anonymous, message.reload.author
283 end
283 end
284
284
285 def test_destroy_should_update_news
285 def test_destroy_should_update_news
286 news = News.create!(:project_id => 1, :author_id => 2, :title => 'foo', :description => 'foo')
286 news = News.create!(:project_id => 1, :author_id => 2, :title => 'foo', :description => 'foo')
287
287
288 User.find(2).destroy
288 User.find(2).destroy
289 assert_nil User.find_by_id(2)
289 assert_nil User.find_by_id(2)
290 assert_equal User.anonymous, news.reload.author
290 assert_equal User.anonymous, news.reload.author
291 end
291 end
292
292
293 def test_destroy_should_delete_private_queries
293 def test_destroy_should_delete_private_queries
294 query = Query.new(:name => 'foo', :visibility => Query::VISIBILITY_PRIVATE)
294 query = Query.new(:name => 'foo', :visibility => Query::VISIBILITY_PRIVATE)
295 query.project_id = 1
295 query.project_id = 1
296 query.user_id = 2
296 query.user_id = 2
297 query.save!
297 query.save!
298
298
299 User.find(2).destroy
299 User.find(2).destroy
300 assert_nil User.find_by_id(2)
300 assert_nil User.find_by_id(2)
301 assert_nil Query.find_by_id(query.id)
301 assert_nil Query.find_by_id(query.id)
302 end
302 end
303
303
304 def test_destroy_should_update_public_queries
304 def test_destroy_should_update_public_queries
305 query = Query.new(:name => 'foo', :visibility => Query::VISIBILITY_PUBLIC)
305 query = Query.new(:name => 'foo', :visibility => Query::VISIBILITY_PUBLIC)
306 query.project_id = 1
306 query.project_id = 1
307 query.user_id = 2
307 query.user_id = 2
308 query.save!
308 query.save!
309
309
310 User.find(2).destroy
310 User.find(2).destroy
311 assert_nil User.find_by_id(2)
311 assert_nil User.find_by_id(2)
312 assert_equal User.anonymous, query.reload.user
312 assert_equal User.anonymous, query.reload.user
313 end
313 end
314
314
315 def test_destroy_should_update_time_entries
315 def test_destroy_should_update_time_entries
316 entry = TimeEntry.new(:hours => '2', :spent_on => Date.today, :activity => TimeEntryActivity.create!(:name => 'foo'))
316 entry = TimeEntry.new(:hours => '2', :spent_on => Date.today, :activity => TimeEntryActivity.create!(:name => 'foo'))
317 entry.project_id = 1
317 entry.project_id = 1
318 entry.user_id = 2
318 entry.user_id = 2
319 entry.save!
319 entry.save!
320
320
321 User.find(2).destroy
321 User.find(2).destroy
322 assert_nil User.find_by_id(2)
322 assert_nil User.find_by_id(2)
323 assert_equal User.anonymous, entry.reload.user
323 assert_equal User.anonymous, entry.reload.user
324 end
324 end
325
325
326 def test_destroy_should_delete_tokens
326 def test_destroy_should_delete_tokens
327 token = Token.create!(:user_id => 2, :value => 'foo')
327 token = Token.create!(:user_id => 2, :value => 'foo')
328
328
329 User.find(2).destroy
329 User.find(2).destroy
330 assert_nil User.find_by_id(2)
330 assert_nil User.find_by_id(2)
331 assert_nil Token.find_by_id(token.id)
331 assert_nil Token.find_by_id(token.id)
332 end
332 end
333
333
334 def test_destroy_should_delete_watchers
334 def test_destroy_should_delete_watchers
335 issue = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'foo')
335 issue = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'foo')
336 watcher = Watcher.create!(:user_id => 2, :watchable => issue)
336 watcher = Watcher.create!(:user_id => 2, :watchable => issue)
337
337
338 User.find(2).destroy
338 User.find(2).destroy
339 assert_nil User.find_by_id(2)
339 assert_nil User.find_by_id(2)
340 assert_nil Watcher.find_by_id(watcher.id)
340 assert_nil Watcher.find_by_id(watcher.id)
341 end
341 end
342
342
343 def test_destroy_should_update_wiki_contents
343 def test_destroy_should_update_wiki_contents
344 wiki_content = WikiContent.create!(
344 wiki_content = WikiContent.create!(
345 :text => 'foo',
345 :text => 'foo',
346 :author_id => 2,
346 :author_id => 2,
347 :page => WikiPage.create!(:title => 'Foo', :wiki => Wiki.create!(:project_id => 1, :start_page => 'Start'))
347 :page => WikiPage.create!(:title => 'Foo', :wiki => Wiki.create!(:project_id => 1, :start_page => 'Start'))
348 )
348 )
349 wiki_content.text = 'bar'
349 wiki_content.text = 'bar'
350 assert_difference 'WikiContent::Version.count' do
350 assert_difference 'WikiContent::Version.count' do
351 wiki_content.save!
351 wiki_content.save!
352 end
352 end
353
353
354 User.find(2).destroy
354 User.find(2).destroy
355 assert_nil User.find_by_id(2)
355 assert_nil User.find_by_id(2)
356 assert_equal User.anonymous, wiki_content.reload.author
356 assert_equal User.anonymous, wiki_content.reload.author
357 wiki_content.versions.each do |version|
357 wiki_content.versions.each do |version|
358 assert_equal User.anonymous, version.reload.author
358 assert_equal User.anonymous, version.reload.author
359 end
359 end
360 end
360 end
361
361
362 def test_destroy_should_nullify_issue_categories
362 def test_destroy_should_nullify_issue_categories
363 category = IssueCategory.create!(:project_id => 1, :assigned_to_id => 2, :name => 'foo')
363 category = IssueCategory.create!(:project_id => 1, :assigned_to_id => 2, :name => 'foo')
364
364
365 User.find(2).destroy
365 User.find(2).destroy
366 assert_nil User.find_by_id(2)
366 assert_nil User.find_by_id(2)
367 assert_nil category.reload.assigned_to_id
367 assert_nil category.reload.assigned_to_id
368 end
368 end
369
369
370 def test_destroy_should_nullify_changesets
370 def test_destroy_should_nullify_changesets
371 changeset = Changeset.create!(
371 changeset = Changeset.create!(
372 :repository => Repository::Subversion.create!(
372 :repository => Repository::Subversion.create!(
373 :project_id => 1,
373 :project_id => 1,
374 :url => 'file:///tmp',
374 :url => 'file:///tmp',
375 :identifier => 'tmp'
375 :identifier => 'tmp'
376 ),
376 ),
377 :revision => '12',
377 :revision => '12',
378 :committed_on => Time.now,
378 :committed_on => Time.now,
379 :committer => 'jsmith'
379 :committer => 'jsmith'
380 )
380 )
381 assert_equal 2, changeset.user_id
381 assert_equal 2, changeset.user_id
382
382
383 User.find(2).destroy
383 User.find(2).destroy
384 assert_nil User.find_by_id(2)
384 assert_nil User.find_by_id(2)
385 assert_nil changeset.reload.user_id
385 assert_nil changeset.reload.user_id
386 end
386 end
387
387
388 def test_anonymous_user_should_not_be_destroyable
388 def test_anonymous_user_should_not_be_destroyable
389 assert_no_difference 'User.count' do
389 assert_no_difference 'User.count' do
390 assert_equal false, User.anonymous.destroy
390 assert_equal false, User.anonymous.destroy
391 end
391 end
392 end
392 end
393
393
394 def test_validate_login_presence
394 def test_validate_login_presence
395 @admin.login = ""
395 @admin.login = ""
396 assert !@admin.save
396 assert !@admin.save
397 assert_equal 1, @admin.errors.count
397 assert_equal 1, @admin.errors.count
398 end
398 end
399
399
400 def test_validate_mail_notification_inclusion
400 def test_validate_mail_notification_inclusion
401 u = User.new
401 u = User.new
402 u.mail_notification = 'foo'
402 u.mail_notification = 'foo'
403 u.save
403 u.save
404 assert_not_nil u.errors[:mail_notification]
404 assert_not_equal [], u.errors[:mail_notification]
405 end
405 end
406
406
407 def test_password
407 def test_password
408 user = User.try_to_login("admin", "admin")
408 user = User.try_to_login("admin", "admin")
409 assert_kind_of User, user
409 assert_kind_of User, user
410 assert_equal "admin", user.login
410 assert_equal "admin", user.login
411 user.password = "hello123"
411 user.password = "hello123"
412 assert user.save
412 assert user.save
413
413
414 user = User.try_to_login("admin", "hello123")
414 user = User.try_to_login("admin", "hello123")
415 assert_kind_of User, user
415 assert_kind_of User, user
416 assert_equal "admin", user.login
416 assert_equal "admin", user.login
417 end
417 end
418
418
419 def test_validate_password_length
419 def test_validate_password_length
420 with_settings :password_min_length => '100' do
420 with_settings :password_min_length => '100' do
421 user = User.new(:firstname => "new100", :lastname => "user100", :mail => "newuser100@somenet.foo")
421 user = User.new(:firstname => "new100", :lastname => "user100", :mail => "newuser100@somenet.foo")
422 user.login = "newuser100"
422 user.login = "newuser100"
423 user.password, user.password_confirmation = "password100", "password100"
423 user.password, user.password_confirmation = "password100", "password100"
424 assert !user.save
424 assert !user.save
425 assert_equal 1, user.errors.count
425 assert_equal 1, user.errors.count
426 end
426 end
427 end
427 end
428
428
429 def test_name_format
429 def test_name_format
430 assert_equal 'John S.', @jsmith.name(:firstname_lastinitial)
430 assert_equal 'John S.', @jsmith.name(:firstname_lastinitial)
431 assert_equal 'Smith, John', @jsmith.name(:lastname_coma_firstname)
431 assert_equal 'Smith, John', @jsmith.name(:lastname_coma_firstname)
432 with_settings :user_format => :firstname_lastname do
432 with_settings :user_format => :firstname_lastname do
433 assert_equal 'John Smith', @jsmith.reload.name
433 assert_equal 'John Smith', @jsmith.reload.name
434 end
434 end
435 with_settings :user_format => :username do
435 with_settings :user_format => :username do
436 assert_equal 'jsmith', @jsmith.reload.name
436 assert_equal 'jsmith', @jsmith.reload.name
437 end
437 end
438 with_settings :user_format => :lastname do
438 with_settings :user_format => :lastname do
439 assert_equal 'Smith', @jsmith.reload.name
439 assert_equal 'Smith', @jsmith.reload.name
440 end
440 end
441 end
441 end
442
442
443 def test_today_should_return_the_day_according_to_user_time_zone
443 def test_today_should_return_the_day_according_to_user_time_zone
444 preference = User.find(1).pref
444 preference = User.find(1).pref
445 date = Date.new(2012, 05, 15)
445 date = Date.new(2012, 05, 15)
446 time = Time.gm(2012, 05, 15, 23, 30).utc # 2012-05-15 23:30 UTC
446 time = Time.gm(2012, 05, 15, 23, 30).utc # 2012-05-15 23:30 UTC
447 Date.stubs(:today).returns(date)
447 Date.stubs(:today).returns(date)
448 Time.stubs(:now).returns(time)
448 Time.stubs(:now).returns(time)
449
449
450 preference.update_attribute :time_zone, 'Baku' # UTC+4
450 preference.update_attribute :time_zone, 'Baku' # UTC+4
451 assert_equal '2012-05-16', User.find(1).today.to_s
451 assert_equal '2012-05-16', User.find(1).today.to_s
452
452
453 preference.update_attribute :time_zone, 'La Paz' # UTC-4
453 preference.update_attribute :time_zone, 'La Paz' # UTC-4
454 assert_equal '2012-05-15', User.find(1).today.to_s
454 assert_equal '2012-05-15', User.find(1).today.to_s
455
455
456 preference.update_attribute :time_zone, ''
456 preference.update_attribute :time_zone, ''
457 assert_equal '2012-05-15', User.find(1).today.to_s
457 assert_equal '2012-05-15', User.find(1).today.to_s
458 end
458 end
459
459
460 def test_time_to_date_should_return_the_date_according_to_user_time_zone
460 def test_time_to_date_should_return_the_date_according_to_user_time_zone
461 preference = User.find(1).pref
461 preference = User.find(1).pref
462 time = Time.gm(2012, 05, 15, 23, 30).utc # 2012-05-15 23:30 UTC
462 time = Time.gm(2012, 05, 15, 23, 30).utc # 2012-05-15 23:30 UTC
463
463
464 preference.update_attribute :time_zone, 'Baku' # UTC+4
464 preference.update_attribute :time_zone, 'Baku' # UTC+4
465 assert_equal '2012-05-16', User.find(1).time_to_date(time).to_s
465 assert_equal '2012-05-16', User.find(1).time_to_date(time).to_s
466
466
467 preference.update_attribute :time_zone, 'La Paz' # UTC-4
467 preference.update_attribute :time_zone, 'La Paz' # UTC-4
468 assert_equal '2012-05-15', User.find(1).time_to_date(time).to_s
468 assert_equal '2012-05-15', User.find(1).time_to_date(time).to_s
469
469
470 preference.update_attribute :time_zone, ''
470 preference.update_attribute :time_zone, ''
471 assert_equal '2012-05-15', User.find(1).time_to_date(time).to_s
471 assert_equal '2012-05-15', User.find(1).time_to_date(time).to_s
472 end
472 end
473
473
474 def test_fields_for_order_statement_should_return_fields_according_user_format_setting
474 def test_fields_for_order_statement_should_return_fields_according_user_format_setting
475 with_settings :user_format => 'lastname_coma_firstname' do
475 with_settings :user_format => 'lastname_coma_firstname' do
476 assert_equal ['users.lastname', 'users.firstname', 'users.id'], User.fields_for_order_statement
476 assert_equal ['users.lastname', 'users.firstname', 'users.id'], User.fields_for_order_statement
477 end
477 end
478 end
478 end
479
479
480 def test_fields_for_order_statement_width_table_name_should_prepend_table_name
480 def test_fields_for_order_statement_width_table_name_should_prepend_table_name
481 with_settings :user_format => 'lastname_firstname' do
481 with_settings :user_format => 'lastname_firstname' do
482 assert_equal ['authors.lastname', 'authors.firstname', 'authors.id'], User.fields_for_order_statement('authors')
482 assert_equal ['authors.lastname', 'authors.firstname', 'authors.id'], User.fields_for_order_statement('authors')
483 end
483 end
484 end
484 end
485
485
486 def test_fields_for_order_statement_with_blank_format_should_return_default
486 def test_fields_for_order_statement_with_blank_format_should_return_default
487 with_settings :user_format => '' do
487 with_settings :user_format => '' do
488 assert_equal ['users.firstname', 'users.lastname', 'users.id'], User.fields_for_order_statement
488 assert_equal ['users.firstname', 'users.lastname', 'users.id'], User.fields_for_order_statement
489 end
489 end
490 end
490 end
491
491
492 def test_fields_for_order_statement_with_invalid_format_should_return_default
492 def test_fields_for_order_statement_with_invalid_format_should_return_default
493 with_settings :user_format => 'foo' do
493 with_settings :user_format => 'foo' do
494 assert_equal ['users.firstname', 'users.lastname', 'users.id'], User.fields_for_order_statement
494 assert_equal ['users.firstname', 'users.lastname', 'users.id'], User.fields_for_order_statement
495 end
495 end
496 end
496 end
497
497
498 test ".try_to_login with good credentials should return the user" do
498 test ".try_to_login with good credentials should return the user" do
499 user = User.try_to_login("admin", "admin")
499 user = User.try_to_login("admin", "admin")
500 assert_kind_of User, user
500 assert_kind_of User, user
501 assert_equal "admin", user.login
501 assert_equal "admin", user.login
502 end
502 end
503
503
504 test ".try_to_login with wrong credentials should return nil" do
504 test ".try_to_login with wrong credentials should return nil" do
505 assert_nil User.try_to_login("admin", "foo")
505 assert_nil User.try_to_login("admin", "foo")
506 end
506 end
507
507
508 def test_try_to_login_with_locked_user_should_return_nil
508 def test_try_to_login_with_locked_user_should_return_nil
509 @jsmith.status = User::STATUS_LOCKED
509 @jsmith.status = User::STATUS_LOCKED
510 @jsmith.save!
510 @jsmith.save!
511
511
512 user = User.try_to_login("jsmith", "jsmith")
512 user = User.try_to_login("jsmith", "jsmith")
513 assert_equal nil, user
513 assert_equal nil, user
514 end
514 end
515
515
516 def test_try_to_login_with_locked_user_and_not_active_only_should_return_user
516 def test_try_to_login_with_locked_user_and_not_active_only_should_return_user
517 @jsmith.status = User::STATUS_LOCKED
517 @jsmith.status = User::STATUS_LOCKED
518 @jsmith.save!
518 @jsmith.save!
519
519
520 user = User.try_to_login("jsmith", "jsmith", false)
520 user = User.try_to_login("jsmith", "jsmith", false)
521 assert_equal @jsmith, user
521 assert_equal @jsmith, user
522 end
522 end
523
523
524 test ".try_to_login should fall-back to case-insensitive if user login is not found as-typed" do
524 test ".try_to_login should fall-back to case-insensitive if user login is not found as-typed" do
525 user = User.try_to_login("AdMin", "admin")
525 user = User.try_to_login("AdMin", "admin")
526 assert_kind_of User, user
526 assert_kind_of User, user
527 assert_equal "admin", user.login
527 assert_equal "admin", user.login
528 end
528 end
529
529
530 test ".try_to_login should select the exact matching user first" do
530 test ".try_to_login should select the exact matching user first" do
531 case_sensitive_user = User.generate! do |user|
531 case_sensitive_user = User.generate! do |user|
532 user.password = "admin123"
532 user.password = "admin123"
533 end
533 end
534 # bypass validations to make it appear like existing data
534 # bypass validations to make it appear like existing data
535 case_sensitive_user.update_attribute(:login, 'ADMIN')
535 case_sensitive_user.update_attribute(:login, 'ADMIN')
536
536
537 user = User.try_to_login("ADMIN", "admin123")
537 user = User.try_to_login("ADMIN", "admin123")
538 assert_kind_of User, user
538 assert_kind_of User, user
539 assert_equal "ADMIN", user.login
539 assert_equal "ADMIN", user.login
540 end
540 end
541
541
542 if ldap_configured?
542 if ldap_configured?
543 context "#try_to_login using LDAP" do
543 context "#try_to_login using LDAP" do
544 context "with failed connection to the LDAP server" do
544 context "with failed connection to the LDAP server" do
545 should "return nil" do
545 should "return nil" do
546 @auth_source = AuthSourceLdap.find(1)
546 @auth_source = AuthSourceLdap.find(1)
547 AuthSource.any_instance.stubs(:initialize_ldap_con).raises(Net::LDAP::LdapError, 'Cannot connect')
547 AuthSource.any_instance.stubs(:initialize_ldap_con).raises(Net::LDAP::LdapError, 'Cannot connect')
548
548
549 assert_equal nil, User.try_to_login('edavis', 'wrong')
549 assert_equal nil, User.try_to_login('edavis', 'wrong')
550 end
550 end
551 end
551 end
552
552
553 context "with an unsuccessful authentication" do
553 context "with an unsuccessful authentication" do
554 should "return nil" do
554 should "return nil" do
555 assert_equal nil, User.try_to_login('edavis', 'wrong')
555 assert_equal nil, User.try_to_login('edavis', 'wrong')
556 end
556 end
557 end
557 end
558
558
559 context "binding with user's account" do
559 context "binding with user's account" do
560 setup do
560 setup do
561 @auth_source = AuthSourceLdap.find(1)
561 @auth_source = AuthSourceLdap.find(1)
562 @auth_source.account = "uid=$login,ou=Person,dc=redmine,dc=org"
562 @auth_source.account = "uid=$login,ou=Person,dc=redmine,dc=org"
563 @auth_source.account_password = ''
563 @auth_source.account_password = ''
564 @auth_source.save!
564 @auth_source.save!
565
565
566 @ldap_user = User.new(:mail => 'example1@redmine.org', :firstname => 'LDAP', :lastname => 'user', :auth_source_id => 1)
566 @ldap_user = User.new(:mail => 'example1@redmine.org', :firstname => 'LDAP', :lastname => 'user', :auth_source_id => 1)
567 @ldap_user.login = 'example1'
567 @ldap_user.login = 'example1'
568 @ldap_user.save!
568 @ldap_user.save!
569 end
569 end
570
570
571 context "with a successful authentication" do
571 context "with a successful authentication" do
572 should "return the user" do
572 should "return the user" do
573 assert_equal @ldap_user, User.try_to_login('example1', '123456')
573 assert_equal @ldap_user, User.try_to_login('example1', '123456')
574 end
574 end
575 end
575 end
576
576
577 context "with an unsuccessful authentication" do
577 context "with an unsuccessful authentication" do
578 should "return nil" do
578 should "return nil" do
579 assert_nil User.try_to_login('example1', '11111')
579 assert_nil User.try_to_login('example1', '11111')
580 end
580 end
581 end
581 end
582 end
582 end
583
583
584 context "on the fly registration" do
584 context "on the fly registration" do
585 setup do
585 setup do
586 @auth_source = AuthSourceLdap.find(1)
586 @auth_source = AuthSourceLdap.find(1)
587 @auth_source.update_attribute :onthefly_register, true
587 @auth_source.update_attribute :onthefly_register, true
588 end
588 end
589
589
590 context "with a successful authentication" do
590 context "with a successful authentication" do
591 should "create a new user account if it doesn't exist" do
591 should "create a new user account if it doesn't exist" do
592 assert_difference('User.count') do
592 assert_difference('User.count') do
593 user = User.try_to_login('edavis', '123456')
593 user = User.try_to_login('edavis', '123456')
594 assert !user.admin?
594 assert !user.admin?
595 end
595 end
596 end
596 end
597
597
598 should "retrieve existing user" do
598 should "retrieve existing user" do
599 user = User.try_to_login('edavis', '123456')
599 user = User.try_to_login('edavis', '123456')
600 user.admin = true
600 user.admin = true
601 user.save!
601 user.save!
602
602
603 assert_no_difference('User.count') do
603 assert_no_difference('User.count') do
604 user = User.try_to_login('edavis', '123456')
604 user = User.try_to_login('edavis', '123456')
605 assert user.admin?
605 assert user.admin?
606 end
606 end
607 end
607 end
608 end
608 end
609
609
610 context "binding with user's account" do
610 context "binding with user's account" do
611 setup do
611 setup do
612 @auth_source = AuthSourceLdap.find(1)
612 @auth_source = AuthSourceLdap.find(1)
613 @auth_source.account = "uid=$login,ou=Person,dc=redmine,dc=org"
613 @auth_source.account = "uid=$login,ou=Person,dc=redmine,dc=org"
614 @auth_source.account_password = ''
614 @auth_source.account_password = ''
615 @auth_source.save!
615 @auth_source.save!
616 end
616 end
617
617
618 context "with a successful authentication" do
618 context "with a successful authentication" do
619 should "create a new user account if it doesn't exist" do
619 should "create a new user account if it doesn't exist" do
620 assert_difference('User.count') do
620 assert_difference('User.count') do
621 user = User.try_to_login('example1', '123456')
621 user = User.try_to_login('example1', '123456')
622 assert_kind_of User, user
622 assert_kind_of User, user
623 end
623 end
624 end
624 end
625 end
625 end
626
626
627 context "with an unsuccessful authentication" do
627 context "with an unsuccessful authentication" do
628 should "return nil" do
628 should "return nil" do
629 assert_nil User.try_to_login('example1', '11111')
629 assert_nil User.try_to_login('example1', '11111')
630 end
630 end
631 end
631 end
632 end
632 end
633 end
633 end
634 end
634 end
635
635
636 else
636 else
637 puts "Skipping LDAP tests."
637 puts "Skipping LDAP tests."
638 end
638 end
639
639
640 def test_create_anonymous
640 def test_create_anonymous
641 AnonymousUser.delete_all
641 AnonymousUser.delete_all
642 anon = User.anonymous
642 anon = User.anonymous
643 assert !anon.new_record?
643 assert !anon.new_record?
644 assert_kind_of AnonymousUser, anon
644 assert_kind_of AnonymousUser, anon
645 end
645 end
646
646
647 def test_ensure_single_anonymous_user
647 def test_ensure_single_anonymous_user
648 AnonymousUser.delete_all
648 AnonymousUser.delete_all
649 anon1 = User.anonymous
649 anon1 = User.anonymous
650 assert !anon1.new_record?
650 assert !anon1.new_record?
651 assert_kind_of AnonymousUser, anon1
651 assert_kind_of AnonymousUser, anon1
652 anon2 = AnonymousUser.create(
652 anon2 = AnonymousUser.create(
653 :lastname => 'Anonymous', :firstname => '',
653 :lastname => 'Anonymous', :firstname => '',
654 :mail => '', :login => '', :status => 0)
654 :mail => '', :login => '', :status => 0)
655 assert_equal 1, anon2.errors.count
655 assert_equal 1, anon2.errors.count
656 end
656 end
657
657
658 def test_rss_key
658 def test_rss_key
659 assert_nil @jsmith.rss_token
659 assert_nil @jsmith.rss_token
660 key = @jsmith.rss_key
660 key = @jsmith.rss_key
661 assert_equal 40, key.length
661 assert_equal 40, key.length
662
662
663 @jsmith.reload
663 @jsmith.reload
664 assert_equal key, @jsmith.rss_key
664 assert_equal key, @jsmith.rss_key
665 end
665 end
666
666
667 def test_rss_key_should_not_be_generated_twice
667 def test_rss_key_should_not_be_generated_twice
668 assert_difference 'Token.count', 1 do
668 assert_difference 'Token.count', 1 do
669 key1 = @jsmith.rss_key
669 key1 = @jsmith.rss_key
670 key2 = @jsmith.rss_key
670 key2 = @jsmith.rss_key
671 assert_equal key1, key2
671 assert_equal key1, key2
672 end
672 end
673 end
673 end
674
674
675 def test_api_key_should_not_be_generated_twice
675 def test_api_key_should_not_be_generated_twice
676 assert_difference 'Token.count', 1 do
676 assert_difference 'Token.count', 1 do
677 key1 = @jsmith.api_key
677 key1 = @jsmith.api_key
678 key2 = @jsmith.api_key
678 key2 = @jsmith.api_key
679 assert_equal key1, key2
679 assert_equal key1, key2
680 end
680 end
681 end
681 end
682
682
683 test "#api_key should generate a new one if the user doesn't have one" do
683 test "#api_key should generate a new one if the user doesn't have one" do
684 user = User.generate!(:api_token => nil)
684 user = User.generate!(:api_token => nil)
685 assert_nil user.api_token
685 assert_nil user.api_token
686
686
687 key = user.api_key
687 key = user.api_key
688 assert_equal 40, key.length
688 assert_equal 40, key.length
689 user.reload
689 user.reload
690 assert_equal key, user.api_key
690 assert_equal key, user.api_key
691 end
691 end
692
692
693 test "#api_key should return the existing api token value" do
693 test "#api_key should return the existing api token value" do
694 user = User.generate!
694 user = User.generate!
695 token = Token.create!(:action => 'api')
695 token = Token.create!(:action => 'api')
696 user.api_token = token
696 user.api_token = token
697 assert user.save
697 assert user.save
698
698
699 assert_equal token.value, user.api_key
699 assert_equal token.value, user.api_key
700 end
700 end
701
701
702 test "#find_by_api_key should return nil if no matching key is found" do
702 test "#find_by_api_key should return nil if no matching key is found" do
703 assert_nil User.find_by_api_key('zzzzzzzzz')
703 assert_nil User.find_by_api_key('zzzzzzzzz')
704 end
704 end
705
705
706 test "#find_by_api_key should return nil if the key is found for an inactive user" do
706 test "#find_by_api_key should return nil if the key is found for an inactive user" do
707 user = User.generate!
707 user = User.generate!
708 user.status = User::STATUS_LOCKED
708 user.status = User::STATUS_LOCKED
709 token = Token.create!(:action => 'api')
709 token = Token.create!(:action => 'api')
710 user.api_token = token
710 user.api_token = token
711 user.save
711 user.save
712
712
713 assert_nil User.find_by_api_key(token.value)
713 assert_nil User.find_by_api_key(token.value)
714 end
714 end
715
715
716 test "#find_by_api_key should return the user if the key is found for an active user" do
716 test "#find_by_api_key should return the user if the key is found for an active user" do
717 user = User.generate!
717 user = User.generate!
718 token = Token.create!(:action => 'api')
718 token = Token.create!(:action => 'api')
719 user.api_token = token
719 user.api_token = token
720 user.save
720 user.save
721
721
722 assert_equal user, User.find_by_api_key(token.value)
722 assert_equal user, User.find_by_api_key(token.value)
723 end
723 end
724
724
725 def test_default_admin_account_changed_should_return_false_if_account_was_not_changed
725 def test_default_admin_account_changed_should_return_false_if_account_was_not_changed
726 user = User.find_by_login("admin")
726 user = User.find_by_login("admin")
727 user.password = "admin"
727 user.password = "admin"
728 assert user.save(:validate => false)
728 assert user.save(:validate => false)
729
729
730 assert_equal false, User.default_admin_account_changed?
730 assert_equal false, User.default_admin_account_changed?
731 end
731 end
732
732
733 def test_default_admin_account_changed_should_return_true_if_password_was_changed
733 def test_default_admin_account_changed_should_return_true_if_password_was_changed
734 user = User.find_by_login("admin")
734 user = User.find_by_login("admin")
735 user.password = "newpassword"
735 user.password = "newpassword"
736 user.save!
736 user.save!
737
737
738 assert_equal true, User.default_admin_account_changed?
738 assert_equal true, User.default_admin_account_changed?
739 end
739 end
740
740
741 def test_default_admin_account_changed_should_return_true_if_account_is_disabled
741 def test_default_admin_account_changed_should_return_true_if_account_is_disabled
742 user = User.find_by_login("admin")
742 user = User.find_by_login("admin")
743 user.password = "admin"
743 user.password = "admin"
744 user.status = User::STATUS_LOCKED
744 user.status = User::STATUS_LOCKED
745 assert user.save(:validate => false)
745 assert user.save(:validate => false)
746
746
747 assert_equal true, User.default_admin_account_changed?
747 assert_equal true, User.default_admin_account_changed?
748 end
748 end
749
749
750 def test_default_admin_account_changed_should_return_true_if_account_does_not_exist
750 def test_default_admin_account_changed_should_return_true_if_account_does_not_exist
751 user = User.find_by_login("admin")
751 user = User.find_by_login("admin")
752 user.destroy
752 user.destroy
753
753
754 assert_equal true, User.default_admin_account_changed?
754 assert_equal true, User.default_admin_account_changed?
755 end
755 end
756
756
757 def test_membership_with_project_should_return_membership
757 def test_membership_with_project_should_return_membership
758 project = Project.find(1)
758 project = Project.find(1)
759
759
760 membership = @jsmith.membership(project)
760 membership = @jsmith.membership(project)
761 assert_kind_of Member, membership
761 assert_kind_of Member, membership
762 assert_equal @jsmith, membership.user
762 assert_equal @jsmith, membership.user
763 assert_equal project, membership.project
763 assert_equal project, membership.project
764 end
764 end
765
765
766 def test_membership_with_project_id_should_return_membership
766 def test_membership_with_project_id_should_return_membership
767 project = Project.find(1)
767 project = Project.find(1)
768
768
769 membership = @jsmith.membership(1)
769 membership = @jsmith.membership(1)
770 assert_kind_of Member, membership
770 assert_kind_of Member, membership
771 assert_equal @jsmith, membership.user
771 assert_equal @jsmith, membership.user
772 assert_equal project, membership.project
772 assert_equal project, membership.project
773 end
773 end
774
774
775 def test_membership_for_non_member_should_return_nil
775 def test_membership_for_non_member_should_return_nil
776 project = Project.find(1)
776 project = Project.find(1)
777
777
778 user = User.generate!
778 user = User.generate!
779 membership = user.membership(1)
779 membership = user.membership(1)
780 assert_nil membership
780 assert_nil membership
781 end
781 end
782
782
783 def test_roles_for_project
783 def test_roles_for_project
784 # user with a role
784 # user with a role
785 roles = @jsmith.roles_for_project(Project.find(1))
785 roles = @jsmith.roles_for_project(Project.find(1))
786 assert_kind_of Role, roles.first
786 assert_kind_of Role, roles.first
787 assert_equal "Manager", roles.first.name
787 assert_equal "Manager", roles.first.name
788
788
789 # user with no role
789 # user with no role
790 assert_nil @dlopper.roles_for_project(Project.find(2)).detect {|role| role.member?}
790 assert_nil @dlopper.roles_for_project(Project.find(2)).detect {|role| role.member?}
791 end
791 end
792
792
793 def test_projects_by_role_for_user_with_role
793 def test_projects_by_role_for_user_with_role
794 user = User.find(2)
794 user = User.find(2)
795 assert_kind_of Hash, user.projects_by_role
795 assert_kind_of Hash, user.projects_by_role
796 assert_equal 2, user.projects_by_role.size
796 assert_equal 2, user.projects_by_role.size
797 assert_equal [1,5], user.projects_by_role[Role.find(1)].collect(&:id).sort
797 assert_equal [1,5], user.projects_by_role[Role.find(1)].collect(&:id).sort
798 assert_equal [2], user.projects_by_role[Role.find(2)].collect(&:id).sort
798 assert_equal [2], user.projects_by_role[Role.find(2)].collect(&:id).sort
799 end
799 end
800
800
801 def test_accessing_projects_by_role_with_no_projects_should_return_an_empty_array
801 def test_accessing_projects_by_role_with_no_projects_should_return_an_empty_array
802 user = User.find(2)
802 user = User.find(2)
803 assert_equal [], user.projects_by_role[Role.find(3)]
803 assert_equal [], user.projects_by_role[Role.find(3)]
804 # should not update the hash
804 # should not update the hash
805 assert_nil user.projects_by_role.values.detect(&:blank?)
805 assert_nil user.projects_by_role.values.detect(&:blank?)
806 end
806 end
807
807
808 def test_projects_by_role_for_user_with_no_role
808 def test_projects_by_role_for_user_with_no_role
809 user = User.generate!
809 user = User.generate!
810 assert_equal({}, user.projects_by_role)
810 assert_equal({}, user.projects_by_role)
811 end
811 end
812
812
813 def test_projects_by_role_for_anonymous
813 def test_projects_by_role_for_anonymous
814 assert_equal({}, User.anonymous.projects_by_role)
814 assert_equal({}, User.anonymous.projects_by_role)
815 end
815 end
816
816
817 def test_valid_notification_options
817 def test_valid_notification_options
818 # without memberships
818 # without memberships
819 assert_equal 5, User.find(7).valid_notification_options.size
819 assert_equal 5, User.find(7).valid_notification_options.size
820 # with memberships
820 # with memberships
821 assert_equal 6, User.find(2).valid_notification_options.size
821 assert_equal 6, User.find(2).valid_notification_options.size
822 end
822 end
823
823
824 def test_valid_notification_options_class_method
824 def test_valid_notification_options_class_method
825 assert_equal 5, User.valid_notification_options.size
825 assert_equal 5, User.valid_notification_options.size
826 assert_equal 5, User.valid_notification_options(User.find(7)).size
826 assert_equal 5, User.valid_notification_options(User.find(7)).size
827 assert_equal 6, User.valid_notification_options(User.find(2)).size
827 assert_equal 6, User.valid_notification_options(User.find(2)).size
828 end
828 end
829
829
830 def test_mail_notification_all
830 def test_mail_notification_all
831 @jsmith.mail_notification = 'all'
831 @jsmith.mail_notification = 'all'
832 @jsmith.notified_project_ids = []
832 @jsmith.notified_project_ids = []
833 @jsmith.save
833 @jsmith.save
834 @jsmith.reload
834 @jsmith.reload
835 assert @jsmith.projects.first.recipients.include?(@jsmith.mail)
835 assert @jsmith.projects.first.recipients.include?(@jsmith.mail)
836 end
836 end
837
837
838 def test_mail_notification_selected
838 def test_mail_notification_selected
839 @jsmith.mail_notification = 'selected'
839 @jsmith.mail_notification = 'selected'
840 @jsmith.notified_project_ids = [1]
840 @jsmith.notified_project_ids = [1]
841 @jsmith.save
841 @jsmith.save
842 @jsmith.reload
842 @jsmith.reload
843 assert Project.find(1).recipients.include?(@jsmith.mail)
843 assert Project.find(1).recipients.include?(@jsmith.mail)
844 end
844 end
845
845
846 def test_mail_notification_only_my_events
846 def test_mail_notification_only_my_events
847 @jsmith.mail_notification = 'only_my_events'
847 @jsmith.mail_notification = 'only_my_events'
848 @jsmith.notified_project_ids = []
848 @jsmith.notified_project_ids = []
849 @jsmith.save
849 @jsmith.save
850 @jsmith.reload
850 @jsmith.reload
851 assert !@jsmith.projects.first.recipients.include?(@jsmith.mail)
851 assert !@jsmith.projects.first.recipients.include?(@jsmith.mail)
852 end
852 end
853
853
854 def test_comments_sorting_preference
854 def test_comments_sorting_preference
855 assert !@jsmith.wants_comments_in_reverse_order?
855 assert !@jsmith.wants_comments_in_reverse_order?
856 @jsmith.pref.comments_sorting = 'asc'
856 @jsmith.pref.comments_sorting = 'asc'
857 assert !@jsmith.wants_comments_in_reverse_order?
857 assert !@jsmith.wants_comments_in_reverse_order?
858 @jsmith.pref.comments_sorting = 'desc'
858 @jsmith.pref.comments_sorting = 'desc'
859 assert @jsmith.wants_comments_in_reverse_order?
859 assert @jsmith.wants_comments_in_reverse_order?
860 end
860 end
861
861
862 def test_find_by_mail_should_be_case_insensitive
862 def test_find_by_mail_should_be_case_insensitive
863 u = User.find_by_mail('JSmith@somenet.foo')
863 u = User.find_by_mail('JSmith@somenet.foo')
864 assert_not_nil u
864 assert_not_nil u
865 assert_equal 'jsmith@somenet.foo', u.mail
865 assert_equal 'jsmith@somenet.foo', u.mail
866 end
866 end
867
867
868 def test_random_password
868 def test_random_password
869 u = User.new
869 u = User.new
870 u.random_password
870 u.random_password
871 assert !u.password.blank?
871 assert !u.password.blank?
872 assert !u.password_confirmation.blank?
872 assert !u.password_confirmation.blank?
873 end
873 end
874
874
875 test "#change_password_allowed? should be allowed if no auth source is set" do
875 test "#change_password_allowed? should be allowed if no auth source is set" do
876 user = User.generate!
876 user = User.generate!
877 assert user.change_password_allowed?
877 assert user.change_password_allowed?
878 end
878 end
879
879
880 test "#change_password_allowed? should delegate to the auth source" do
880 test "#change_password_allowed? should delegate to the auth source" do
881 user = User.generate!
881 user = User.generate!
882
882
883 allowed_auth_source = AuthSource.generate!
883 allowed_auth_source = AuthSource.generate!
884 def allowed_auth_source.allow_password_changes?; true; end
884 def allowed_auth_source.allow_password_changes?; true; end
885
885
886 denied_auth_source = AuthSource.generate!
886 denied_auth_source = AuthSource.generate!
887 def denied_auth_source.allow_password_changes?; false; end
887 def denied_auth_source.allow_password_changes?; false; end
888
888
889 assert user.change_password_allowed?
889 assert user.change_password_allowed?
890
890
891 user.auth_source = allowed_auth_source
891 user.auth_source = allowed_auth_source
892 assert user.change_password_allowed?, "User not allowed to change password, though auth source does"
892 assert user.change_password_allowed?, "User not allowed to change password, though auth source does"
893
893
894 user.auth_source = denied_auth_source
894 user.auth_source = denied_auth_source
895 assert !user.change_password_allowed?, "User allowed to change password, though auth source does not"
895 assert !user.change_password_allowed?, "User allowed to change password, though auth source does not"
896 end
896 end
897
897
898 def test_own_account_deletable_should_be_true_with_unsubscrive_enabled
898 def test_own_account_deletable_should_be_true_with_unsubscrive_enabled
899 with_settings :unsubscribe => '1' do
899 with_settings :unsubscribe => '1' do
900 assert_equal true, User.find(2).own_account_deletable?
900 assert_equal true, User.find(2).own_account_deletable?
901 end
901 end
902 end
902 end
903
903
904 def test_own_account_deletable_should_be_false_with_unsubscrive_disabled
904 def test_own_account_deletable_should_be_false_with_unsubscrive_disabled
905 with_settings :unsubscribe => '0' do
905 with_settings :unsubscribe => '0' do
906 assert_equal false, User.find(2).own_account_deletable?
906 assert_equal false, User.find(2).own_account_deletable?
907 end
907 end
908 end
908 end
909
909
910 def test_own_account_deletable_should_be_false_for_a_single_admin
910 def test_own_account_deletable_should_be_false_for_a_single_admin
911 User.delete_all(["admin = ? AND id <> ?", true, 1])
911 User.delete_all(["admin = ? AND id <> ?", true, 1])
912
912
913 with_settings :unsubscribe => '1' do
913 with_settings :unsubscribe => '1' do
914 assert_equal false, User.find(1).own_account_deletable?
914 assert_equal false, User.find(1).own_account_deletable?
915 end
915 end
916 end
916 end
917
917
918 def test_own_account_deletable_should_be_true_for_an_admin_if_other_admin_exists
918 def test_own_account_deletable_should_be_true_for_an_admin_if_other_admin_exists
919 User.generate! do |user|
919 User.generate! do |user|
920 user.admin = true
920 user.admin = true
921 end
921 end
922
922
923 with_settings :unsubscribe => '1' do
923 with_settings :unsubscribe => '1' do
924 assert_equal true, User.find(1).own_account_deletable?
924 assert_equal true, User.find(1).own_account_deletable?
925 end
925 end
926 end
926 end
927
927
928 context "#allowed_to?" do
928 context "#allowed_to?" do
929 context "with a unique project" do
929 context "with a unique project" do
930 should "return false if project is archived" do
930 should "return false if project is archived" do
931 project = Project.find(1)
931 project = Project.find(1)
932 Project.any_instance.stubs(:status).returns(Project::STATUS_ARCHIVED)
932 Project.any_instance.stubs(:status).returns(Project::STATUS_ARCHIVED)
933 assert_equal false, @admin.allowed_to?(:view_issues, Project.find(1))
933 assert_equal false, @admin.allowed_to?(:view_issues, Project.find(1))
934 end
934 end
935
935
936 should "return false for write action if project is closed" do
936 should "return false for write action if project is closed" do
937 project = Project.find(1)
937 project = Project.find(1)
938 Project.any_instance.stubs(:status).returns(Project::STATUS_CLOSED)
938 Project.any_instance.stubs(:status).returns(Project::STATUS_CLOSED)
939 assert_equal false, @admin.allowed_to?(:edit_project, Project.find(1))
939 assert_equal false, @admin.allowed_to?(:edit_project, Project.find(1))
940 end
940 end
941
941
942 should "return true for read action if project is closed" do
942 should "return true for read action if project is closed" do
943 project = Project.find(1)
943 project = Project.find(1)
944 Project.any_instance.stubs(:status).returns(Project::STATUS_CLOSED)
944 Project.any_instance.stubs(:status).returns(Project::STATUS_CLOSED)
945 assert_equal true, @admin.allowed_to?(:view_project, Project.find(1))
945 assert_equal true, @admin.allowed_to?(:view_project, Project.find(1))
946 end
946 end
947
947
948 should "return false if related module is disabled" do
948 should "return false if related module is disabled" do
949 project = Project.find(1)
949 project = Project.find(1)
950 project.enabled_module_names = ["issue_tracking"]
950 project.enabled_module_names = ["issue_tracking"]
951 assert_equal true, @admin.allowed_to?(:add_issues, project)
951 assert_equal true, @admin.allowed_to?(:add_issues, project)
952 assert_equal false, @admin.allowed_to?(:view_wiki_pages, project)
952 assert_equal false, @admin.allowed_to?(:view_wiki_pages, project)
953 end
953 end
954
954
955 should "authorize nearly everything for admin users" do
955 should "authorize nearly everything for admin users" do
956 project = Project.find(1)
956 project = Project.find(1)
957 assert ! @admin.member_of?(project)
957 assert ! @admin.member_of?(project)
958 %w(edit_issues delete_issues manage_news add_documents manage_wiki).each do |p|
958 %w(edit_issues delete_issues manage_news add_documents manage_wiki).each do |p|
959 assert_equal true, @admin.allowed_to?(p.to_sym, project)
959 assert_equal true, @admin.allowed_to?(p.to_sym, project)
960 end
960 end
961 end
961 end
962
962
963 should "authorize normal users depending on their roles" do
963 should "authorize normal users depending on their roles" do
964 project = Project.find(1)
964 project = Project.find(1)
965 assert_equal true, @jsmith.allowed_to?(:delete_messages, project) #Manager
965 assert_equal true, @jsmith.allowed_to?(:delete_messages, project) #Manager
966 assert_equal false, @dlopper.allowed_to?(:delete_messages, project) #Developper
966 assert_equal false, @dlopper.allowed_to?(:delete_messages, project) #Developper
967 end
967 end
968 end
968 end
969
969
970 context "with multiple projects" do
970 context "with multiple projects" do
971 should "return false if array is empty" do
971 should "return false if array is empty" do
972 assert_equal false, @admin.allowed_to?(:view_project, [])
972 assert_equal false, @admin.allowed_to?(:view_project, [])
973 end
973 end
974
974
975 should "return true only if user has permission on all these projects" do
975 should "return true only if user has permission on all these projects" do
976 assert_equal true, @admin.allowed_to?(:view_project, Project.all)
976 assert_equal true, @admin.allowed_to?(:view_project, Project.all)
977 assert_equal false, @dlopper.allowed_to?(:view_project, Project.all) #cannot see Project(2)
977 assert_equal false, @dlopper.allowed_to?(:view_project, Project.all) #cannot see Project(2)
978 assert_equal true, @jsmith.allowed_to?(:edit_issues, @jsmith.projects) #Manager or Developer everywhere
978 assert_equal true, @jsmith.allowed_to?(:edit_issues, @jsmith.projects) #Manager or Developer everywhere
979 assert_equal false, @jsmith.allowed_to?(:delete_issue_watchers, @jsmith.projects) #Dev cannot delete_issue_watchers
979 assert_equal false, @jsmith.allowed_to?(:delete_issue_watchers, @jsmith.projects) #Dev cannot delete_issue_watchers
980 end
980 end
981
981
982 should "behave correctly with arrays of 1 project" do
982 should "behave correctly with arrays of 1 project" do
983 assert_equal false, User.anonymous.allowed_to?(:delete_issues, [Project.first])
983 assert_equal false, User.anonymous.allowed_to?(:delete_issues, [Project.first])
984 end
984 end
985 end
985 end
986
986
987 context "with options[:global]" do
987 context "with options[:global]" do
988 should "authorize if user has at least one role that has this permission" do
988 should "authorize if user has at least one role that has this permission" do
989 @dlopper2 = User.find(5) #only Developper on a project, not Manager anywhere
989 @dlopper2 = User.find(5) #only Developper on a project, not Manager anywhere
990 @anonymous = User.find(6)
990 @anonymous = User.find(6)
991 assert_equal true, @jsmith.allowed_to?(:delete_issue_watchers, nil, :global => true)
991 assert_equal true, @jsmith.allowed_to?(:delete_issue_watchers, nil, :global => true)
992 assert_equal false, @dlopper2.allowed_to?(:delete_issue_watchers, nil, :global => true)
992 assert_equal false, @dlopper2.allowed_to?(:delete_issue_watchers, nil, :global => true)
993 assert_equal true, @dlopper2.allowed_to?(:add_issues, nil, :global => true)
993 assert_equal true, @dlopper2.allowed_to?(:add_issues, nil, :global => true)
994 assert_equal false, @anonymous.allowed_to?(:add_issues, nil, :global => true)
994 assert_equal false, @anonymous.allowed_to?(:add_issues, nil, :global => true)
995 assert_equal true, @anonymous.allowed_to?(:view_issues, nil, :global => true)
995 assert_equal true, @anonymous.allowed_to?(:view_issues, nil, :global => true)
996 end
996 end
997 end
997 end
998 end
998 end
999
999
1000 context "User#notify_about?" do
1000 context "User#notify_about?" do
1001 context "Issues" do
1001 context "Issues" do
1002 setup do
1002 setup do
1003 @project = Project.find(1)
1003 @project = Project.find(1)
1004 @author = User.generate!
1004 @author = User.generate!
1005 @assignee = User.generate!
1005 @assignee = User.generate!
1006 @issue = Issue.generate!(:project => @project, :assigned_to => @assignee, :author => @author)
1006 @issue = Issue.generate!(:project => @project, :assigned_to => @assignee, :author => @author)
1007 end
1007 end
1008
1008
1009 should "be true for a user with :all" do
1009 should "be true for a user with :all" do
1010 @author.update_attribute(:mail_notification, 'all')
1010 @author.update_attribute(:mail_notification, 'all')
1011 assert @author.notify_about?(@issue)
1011 assert @author.notify_about?(@issue)
1012 end
1012 end
1013
1013
1014 should "be false for a user with :none" do
1014 should "be false for a user with :none" do
1015 @author.update_attribute(:mail_notification, 'none')
1015 @author.update_attribute(:mail_notification, 'none')
1016 assert ! @author.notify_about?(@issue)
1016 assert ! @author.notify_about?(@issue)
1017 end
1017 end
1018
1018
1019 should "be false for a user with :only_my_events and isn't an author, creator, or assignee" do
1019 should "be false for a user with :only_my_events and isn't an author, creator, or assignee" do
1020 @user = User.generate!(:mail_notification => 'only_my_events')
1020 @user = User.generate!(:mail_notification => 'only_my_events')
1021 Member.create!(:user => @user, :project => @project, :role_ids => [1])
1021 Member.create!(:user => @user, :project => @project, :role_ids => [1])
1022 assert ! @user.notify_about?(@issue)
1022 assert ! @user.notify_about?(@issue)
1023 end
1023 end
1024
1024
1025 should "be true for a user with :only_my_events and is the author" do
1025 should "be true for a user with :only_my_events and is the author" do
1026 @author.update_attribute(:mail_notification, 'only_my_events')
1026 @author.update_attribute(:mail_notification, 'only_my_events')
1027 assert @author.notify_about?(@issue)
1027 assert @author.notify_about?(@issue)
1028 end
1028 end
1029
1029
1030 should "be true for a user with :only_my_events and is the assignee" do
1030 should "be true for a user with :only_my_events and is the assignee" do
1031 @assignee.update_attribute(:mail_notification, 'only_my_events')
1031 @assignee.update_attribute(:mail_notification, 'only_my_events')
1032 assert @assignee.notify_about?(@issue)
1032 assert @assignee.notify_about?(@issue)
1033 end
1033 end
1034
1034
1035 should "be true for a user with :only_assigned and is the assignee" do
1035 should "be true for a user with :only_assigned and is the assignee" do
1036 @assignee.update_attribute(:mail_notification, 'only_assigned')
1036 @assignee.update_attribute(:mail_notification, 'only_assigned')
1037 assert @assignee.notify_about?(@issue)
1037 assert @assignee.notify_about?(@issue)
1038 end
1038 end
1039
1039
1040 should "be false for a user with :only_assigned and is not the assignee" do
1040 should "be false for a user with :only_assigned and is not the assignee" do
1041 @author.update_attribute(:mail_notification, 'only_assigned')
1041 @author.update_attribute(:mail_notification, 'only_assigned')
1042 assert ! @author.notify_about?(@issue)
1042 assert ! @author.notify_about?(@issue)
1043 end
1043 end
1044
1044
1045 should "be true for a user with :only_owner and is the author" do
1045 should "be true for a user with :only_owner and is the author" do
1046 @author.update_attribute(:mail_notification, 'only_owner')
1046 @author.update_attribute(:mail_notification, 'only_owner')
1047 assert @author.notify_about?(@issue)
1047 assert @author.notify_about?(@issue)
1048 end
1048 end
1049
1049
1050 should "be false for a user with :only_owner and is not the author" do
1050 should "be false for a user with :only_owner and is not the author" do
1051 @assignee.update_attribute(:mail_notification, 'only_owner')
1051 @assignee.update_attribute(:mail_notification, 'only_owner')
1052 assert ! @assignee.notify_about?(@issue)
1052 assert ! @assignee.notify_about?(@issue)
1053 end
1053 end
1054
1054
1055 should "be true for a user with :selected and is the author" do
1055 should "be true for a user with :selected and is the author" do
1056 @author.update_attribute(:mail_notification, 'selected')
1056 @author.update_attribute(:mail_notification, 'selected')
1057 assert @author.notify_about?(@issue)
1057 assert @author.notify_about?(@issue)
1058 end
1058 end
1059
1059
1060 should "be true for a user with :selected and is the assignee" do
1060 should "be true for a user with :selected and is the assignee" do
1061 @assignee.update_attribute(:mail_notification, 'selected')
1061 @assignee.update_attribute(:mail_notification, 'selected')
1062 assert @assignee.notify_about?(@issue)
1062 assert @assignee.notify_about?(@issue)
1063 end
1063 end
1064
1064
1065 should "be false for a user with :selected and is not the author or assignee" do
1065 should "be false for a user with :selected and is not the author or assignee" do
1066 @user = User.generate!(:mail_notification => 'selected')
1066 @user = User.generate!(:mail_notification => 'selected')
1067 Member.create!(:user => @user, :project => @project, :role_ids => [1])
1067 Member.create!(:user => @user, :project => @project, :role_ids => [1])
1068 assert ! @user.notify_about?(@issue)
1068 assert ! @user.notify_about?(@issue)
1069 end
1069 end
1070 end
1070 end
1071 end
1071 end
1072
1072
1073 def test_notify_about_news
1073 def test_notify_about_news
1074 user = User.generate!
1074 user = User.generate!
1075 news = News.new
1075 news = News.new
1076
1076
1077 User::MAIL_NOTIFICATION_OPTIONS.map(&:first).each do |option|
1077 User::MAIL_NOTIFICATION_OPTIONS.map(&:first).each do |option|
1078 user.mail_notification = option
1078 user.mail_notification = option
1079 assert_equal (option != 'none'), user.notify_about?(news)
1079 assert_equal (option != 'none'), user.notify_about?(news)
1080 end
1080 end
1081 end
1081 end
1082
1082
1083 def test_salt_unsalted_passwords
1083 def test_salt_unsalted_passwords
1084 # Restore a user with an unsalted password
1084 # Restore a user with an unsalted password
1085 user = User.find(1)
1085 user = User.find(1)
1086 user.salt = nil
1086 user.salt = nil
1087 user.hashed_password = User.hash_password("unsalted")
1087 user.hashed_password = User.hash_password("unsalted")
1088 user.save!
1088 user.save!
1089
1089
1090 User.salt_unsalted_passwords!
1090 User.salt_unsalted_passwords!
1091
1091
1092 user.reload
1092 user.reload
1093 # Salt added
1093 # Salt added
1094 assert !user.salt.blank?
1094 assert !user.salt.blank?
1095 # Password still valid
1095 # Password still valid
1096 assert user.check_password?("unsalted")
1096 assert user.check_password?("unsalted")
1097 assert_equal user, User.try_to_login(user.login, "unsalted")
1097 assert_equal user, User.try_to_login(user.login, "unsalted")
1098 end
1098 end
1099
1099
1100 if Object.const_defined?(:OpenID)
1100 if Object.const_defined?(:OpenID)
1101
1101
1102 def test_setting_identity_url
1102 def test_setting_identity_url
1103 normalized_open_id_url = 'http://example.com/'
1103 normalized_open_id_url = 'http://example.com/'
1104 u = User.new( :identity_url => 'http://example.com/' )
1104 u = User.new( :identity_url => 'http://example.com/' )
1105 assert_equal normalized_open_id_url, u.identity_url
1105 assert_equal normalized_open_id_url, u.identity_url
1106 end
1106 end
1107
1107
1108 def test_setting_identity_url_without_trailing_slash
1108 def test_setting_identity_url_without_trailing_slash
1109 normalized_open_id_url = 'http://example.com/'
1109 normalized_open_id_url = 'http://example.com/'
1110 u = User.new( :identity_url => 'http://example.com' )
1110 u = User.new( :identity_url => 'http://example.com' )
1111 assert_equal normalized_open_id_url, u.identity_url
1111 assert_equal normalized_open_id_url, u.identity_url
1112 end
1112 end
1113
1113
1114 def test_setting_identity_url_without_protocol
1114 def test_setting_identity_url_without_protocol
1115 normalized_open_id_url = 'http://example.com/'
1115 normalized_open_id_url = 'http://example.com/'
1116 u = User.new( :identity_url => 'example.com' )
1116 u = User.new( :identity_url => 'example.com' )
1117 assert_equal normalized_open_id_url, u.identity_url
1117 assert_equal normalized_open_id_url, u.identity_url
1118 end
1118 end
1119
1119
1120 def test_setting_blank_identity_url
1120 def test_setting_blank_identity_url
1121 u = User.new( :identity_url => 'example.com' )
1121 u = User.new( :identity_url => 'example.com' )
1122 u.identity_url = ''
1122 u.identity_url = ''
1123 assert u.identity_url.blank?
1123 assert u.identity_url.blank?
1124 end
1124 end
1125
1125
1126 def test_setting_invalid_identity_url
1126 def test_setting_invalid_identity_url
1127 u = User.new( :identity_url => 'this is not an openid url' )
1127 u = User.new( :identity_url => 'this is not an openid url' )
1128 assert u.identity_url.blank?
1128 assert u.identity_url.blank?
1129 end
1129 end
1130
1130
1131 else
1131 else
1132 puts "Skipping openid tests."
1132 puts "Skipping openid tests."
1133 end
1133 end
1134
1134
1135 end
1135 end
General Comments 0
You need to be logged in to leave comments. Login now