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