@@ -1,285 +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_nil 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 |
|
|
201 | test "Attachmnet.attach_files should attach the file" do | |
202 | should "attach the file" do |
|
|||
203 |
|
|
202 | issue = Issue.first | |
204 |
|
|
203 | assert_difference 'Attachment.count' do | |
205 |
|
|
204 | Attachment.attach_files(issue, | |
206 |
|
|
205 | '1' => { | |
207 |
|
|
206 | 'file' => uploaded_test_file('testfile.txt', 'text/plain'), | |
208 |
|
|
207 | 'description' => 'test' | |
209 |
|
|
208 | }) | |
210 |
|
|
209 | end | |
211 |
|
210 | |||
212 |
|
|
211 | attachment = Attachment.first(:order => 'id DESC') | |
213 |
|
|
212 | assert_equal issue, attachment.container | |
214 |
|
|
213 | assert_equal 'testfile.txt', attachment.filename | |
215 |
|
|
214 | assert_equal 59, attachment.filesize | |
216 |
|
|
215 | assert_equal 'test', attachment.description | |
217 |
|
|
216 | assert_equal 'text/plain', attachment.content_type | |
218 |
|
|
217 | assert File.exists?(attachment.diskfile) | |
219 |
|
|
218 | assert_equal 59, File.size(attachment.diskfile) | |
220 |
|
|
219 | end | |
221 |
|
220 | |||
222 |
|
|
221 | test "Attachmnet.attach_files should add unsaved files to the object as unsaved attachments" do | |
223 |
|
|
222 | # Max size of 0 to force Attachment creation failures | |
224 |
|
|
223 | with_settings(:attachment_max_size => 0) do | |
225 |
|
|
224 | @project = Project.find(1) | |
226 |
|
|
225 | response = Attachment.attach_files(@project, { | |
227 |
|
|
226 | '1' => {'file' => mock_file, 'description' => 'test'}, | |
228 |
|
|
227 | '2' => {'file' => mock_file, 'description' => 'test'} | |
229 |
|
|
228 | }) | |
230 |
|
229 | |||
231 |
|
|
230 | assert response[:unsaved].present? | |
232 |
|
|
231 | assert_equal 2, response[:unsaved].length | |
233 |
|
|
232 | assert response[:unsaved].first.new_record? | |
234 |
|
|
233 | assert response[:unsaved].second.new_record? | |
235 |
|
|
234 | assert_equal response[:unsaved], @project.unsaved_attachments | |
236 |
|
|
235 | end | |
237 |
|
|
236 | end | |
238 | end |
|
|||
239 |
|
237 | |||
240 | def test_latest_attach |
|
238 | def test_latest_attach | |
241 | set_fixtures_attachments_directory |
|
239 | set_fixtures_attachments_directory | |
242 | a1 = Attachment.find(16) |
|
240 | a1 = Attachment.find(16) | |
243 | assert_equal "testfile.png", a1.filename |
|
241 | assert_equal "testfile.png", a1.filename | |
244 | assert a1.readable? |
|
242 | assert a1.readable? | |
245 | assert (! a1.visible?(User.anonymous)) |
|
243 | assert (! a1.visible?(User.anonymous)) | |
246 | assert a1.visible?(User.find(2)) |
|
244 | assert a1.visible?(User.find(2)) | |
247 | a2 = Attachment.find(17) |
|
245 | a2 = Attachment.find(17) | |
248 | assert_equal "testfile.PNG", a2.filename |
|
246 | assert_equal "testfile.PNG", a2.filename | |
249 | assert a2.readable? |
|
247 | assert a2.readable? | |
250 | assert (! a2.visible?(User.anonymous)) |
|
248 | assert (! a2.visible?(User.anonymous)) | |
251 | assert a2.visible?(User.find(2)) |
|
249 | assert a2.visible?(User.find(2)) | |
252 | assert a1.created_on < a2.created_on |
|
250 | assert a1.created_on < a2.created_on | |
253 |
|
251 | |||
254 | la1 = Attachment.latest_attach([a1, a2], "testfile.png") |
|
252 | la1 = Attachment.latest_attach([a1, a2], "testfile.png") | |
255 | assert_equal 17, la1.id |
|
253 | assert_equal 17, la1.id | |
256 | la2 = Attachment.latest_attach([a1, a2], "Testfile.PNG") |
|
254 | la2 = Attachment.latest_attach([a1, a2], "Testfile.PNG") | |
257 | assert_equal 17, la2.id |
|
255 | assert_equal 17, la2.id | |
258 |
|
256 | |||
259 | set_tmp_attachments_directory |
|
257 | set_tmp_attachments_directory | |
260 | end |
|
258 | end | |
261 |
|
259 | |||
262 | def test_thumbnailable_should_be_true_for_images |
|
260 | def test_thumbnailable_should_be_true_for_images | |
263 | assert_equal true, Attachment.new(:filename => 'test.jpg').thumbnailable? |
|
261 | assert_equal true, Attachment.new(:filename => 'test.jpg').thumbnailable? | |
264 | end |
|
262 | end | |
265 |
|
263 | |||
266 | def test_thumbnailable_should_be_true_for_non_images |
|
264 | def test_thumbnailable_should_be_true_for_non_images | |
267 | assert_equal false, Attachment.new(:filename => 'test.txt').thumbnailable? |
|
265 | assert_equal false, Attachment.new(:filename => 'test.txt').thumbnailable? | |
268 | end |
|
266 | end | |
269 |
|
267 | |||
270 | if convert_installed? |
|
268 | if convert_installed? | |
271 | def test_thumbnail_should_generate_the_thumbnail |
|
269 | def test_thumbnail_should_generate_the_thumbnail | |
272 | set_fixtures_attachments_directory |
|
270 | set_fixtures_attachments_directory | |
273 | attachment = Attachment.find(16) |
|
271 | attachment = Attachment.find(16) | |
274 | Attachment.clear_thumbnails |
|
272 | Attachment.clear_thumbnails | |
275 |
|
273 | |||
276 | 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 | |
277 | thumbnail = attachment.thumbnail |
|
275 | thumbnail = attachment.thumbnail | |
278 | assert_equal "16_8e0294de2441577c529f170b6fb8f638_100.thumb", File.basename(thumbnail) |
|
276 | assert_equal "16_8e0294de2441577c529f170b6fb8f638_100.thumb", File.basename(thumbnail) | |
279 | assert File.exists?(thumbnail) |
|
277 | assert File.exists?(thumbnail) | |
280 | end |
|
278 | end | |
281 | end |
|
279 | end | |
282 | else |
|
280 | else | |
283 | puts '(ImageMagick convert not available)' |
|
281 | puts '(ImageMagick convert not available)' | |
284 | end |
|
282 | end | |
285 | end |
|
283 | end |
@@ -1,154 +1,141 | |||||
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 AuthSourceLdapTest < ActiveSupport::TestCase |
|
20 | class AuthSourceLdapTest < ActiveSupport::TestCase | |
21 | include Redmine::I18n |
|
21 | include Redmine::I18n | |
22 | fixtures :auth_sources |
|
22 | fixtures :auth_sources | |
23 |
|
23 | |||
24 | def setup |
|
24 | def setup | |
25 | end |
|
25 | end | |
26 |
|
26 | |||
27 | def test_create |
|
27 | def test_create | |
28 | a = AuthSourceLdap.new(:name => 'My LDAP', :host => 'ldap.example.net', :port => 389, :base_dn => 'dc=example,dc=net', :attr_login => 'sAMAccountName') |
|
28 | a = AuthSourceLdap.new(:name => 'My LDAP', :host => 'ldap.example.net', :port => 389, :base_dn => 'dc=example,dc=net', :attr_login => 'sAMAccountName') | |
29 | assert a.save |
|
29 | assert a.save | |
30 | end |
|
30 | end | |
31 |
|
31 | |||
32 | def test_should_strip_ldap_attributes |
|
32 | def test_should_strip_ldap_attributes | |
33 | a = AuthSourceLdap.new(:name => 'My LDAP', :host => 'ldap.example.net', :port => 389, :base_dn => 'dc=example,dc=net', :attr_login => 'sAMAccountName', |
|
33 | a = AuthSourceLdap.new(:name => 'My LDAP', :host => 'ldap.example.net', :port => 389, :base_dn => 'dc=example,dc=net', :attr_login => 'sAMAccountName', | |
34 | :attr_firstname => 'givenName ') |
|
34 | :attr_firstname => 'givenName ') | |
35 | assert a.save |
|
35 | assert a.save | |
36 | assert_equal 'givenName', a.reload.attr_firstname |
|
36 | assert_equal 'givenName', a.reload.attr_firstname | |
37 | end |
|
37 | end | |
38 |
|
38 | |||
39 | def test_replace_port_zero_to_389 |
|
39 | def test_replace_port_zero_to_389 | |
40 | a = AuthSourceLdap.new( |
|
40 | a = AuthSourceLdap.new( | |
41 | :name => 'My LDAP', :host => 'ldap.example.net', :port => 0, |
|
41 | :name => 'My LDAP', :host => 'ldap.example.net', :port => 0, | |
42 | :base_dn => 'dc=example,dc=net', :attr_login => 'sAMAccountName', |
|
42 | :base_dn => 'dc=example,dc=net', :attr_login => 'sAMAccountName', | |
43 | :attr_firstname => 'givenName ') |
|
43 | :attr_firstname => 'givenName ') | |
44 | assert a.save |
|
44 | assert a.save | |
45 | assert_equal 389, a.port |
|
45 | assert_equal 389, a.port | |
46 | end |
|
46 | end | |
47 |
|
47 | |||
48 | def test_filter_should_be_validated |
|
48 | def test_filter_should_be_validated | |
49 | set_language_if_valid 'en' |
|
49 | set_language_if_valid 'en' | |
50 |
|
50 | |||
51 | a = AuthSourceLdap.new(:name => 'My LDAP', :host => 'ldap.example.net', :port => 389, :attr_login => 'sn') |
|
51 | a = AuthSourceLdap.new(:name => 'My LDAP', :host => 'ldap.example.net', :port => 389, :attr_login => 'sn') | |
52 | a.filter = "(mail=*@redmine.org" |
|
52 | a.filter = "(mail=*@redmine.org" | |
53 | assert !a.valid? |
|
53 | assert !a.valid? | |
54 | assert_include "LDAP filter is invalid", a.errors.full_messages |
|
54 | assert_include "LDAP filter is invalid", a.errors.full_messages | |
55 |
|
55 | |||
56 | a.filter = "(mail=*@redmine.org)" |
|
56 | a.filter = "(mail=*@redmine.org)" | |
57 | assert a.valid? |
|
57 | assert a.valid? | |
58 | end |
|
58 | end | |
59 |
|
59 | |||
60 | if ldap_configured? |
|
60 | if ldap_configured? | |
61 | context '#authenticate' do |
|
61 | test '#authenticate with a valid LDAP user should return the user attributes' do | |
62 | setup do |
|
62 | auth = AuthSourceLdap.find(1) | |
63 | @auth = AuthSourceLdap.find(1) |
|
63 | auth.update_attribute :onthefly_register, true | |
64 | @auth.update_attribute :onthefly_register, true |
|
|||
65 | end |
|
|||
66 |
|
64 | |||
67 | context 'with a valid LDAP user' do |
|
65 | attributes = auth.authenticate('example1','123456') | |
68 | should 'return the user attributes' do |
|
|||
69 | attributes = @auth.authenticate('example1','123456') |
|
|||
70 |
|
|
66 | assert attributes.is_a?(Hash), "An hash was not returned" | |
71 |
|
|
67 | assert_equal 'Example', attributes[:firstname] | |
72 |
|
|
68 | assert_equal 'One', attributes[:lastname] | |
73 |
|
|
69 | assert_equal 'example1@redmine.org', attributes[:mail] | |
74 |
|
|
70 | assert_equal auth.id, attributes[:auth_source_id] | |
75 |
|
|
71 | attributes.keys.each do |attribute| | |
76 |
|
|
72 | assert User.new.respond_to?("#{attribute}="), "Unexpected :#{attribute} attribute returned" | |
77 |
|
|
73 | end | |
78 |
|
|
74 | end | |
79 | end |
|
|||
80 |
|
75 | |||
81 |
|
|
76 | test '#authenticate with an invalid LDAP user should return nil' do | |
82 | should 'return nil' do |
|
77 | auth = AuthSourceLdap.find(1) | |
83 |
|
|
78 | assert_equal nil, auth.authenticate('nouser','123456') | |
84 | end |
|
|||
85 |
|
|
79 | end | |
86 |
|
80 | |||
87 | context 'without a login' do |
|
81 | test '#authenticate without a login should return nil' do | |
88 | should 'return nil' do |
|
82 | auth = AuthSourceLdap.find(1) | |
89 |
|
|
83 | assert_equal nil, auth.authenticate('','123456') | |
90 | end |
|
|||
91 |
|
|
84 | end | |
92 |
|
85 | |||
93 |
|
|
86 | test '#authenticate without a password should return nil' do | |
94 | should 'return nil' do |
|
87 | auth = AuthSourceLdap.find(1) | |
95 |
|
|
88 | assert_equal nil, auth.authenticate('edavis','') | |
96 | end |
|
|||
97 |
|
|
89 | end | |
98 |
|
90 | |||
99 | context 'without filter' do |
|
91 | test '#authenticate without filter should return any user' do | |
100 | should 'return any user' do |
|
92 | auth = AuthSourceLdap.find(1) | |
101 |
|
|
93 | assert auth.authenticate('example1','123456') | |
102 |
|
|
94 | assert auth.authenticate('edavis', '123456') | |
103 | end |
|
|||
104 |
|
|
95 | end | |
105 |
|
96 | |||
106 | context 'with filter' do |
|
97 | test '#authenticate with filter should return user who matches the filter only' do | |
107 | setup do |
|
98 | auth = AuthSourceLdap.find(1) | |
108 |
|
|
99 | auth.filter = "(mail=*@redmine.org)" | |
109 | end |
|
|||
110 |
|
100 | |||
111 | should 'return user who matches the filter only' do |
|
101 | assert auth.authenticate('example1','123456') | |
112 |
|
|
102 | assert_nil auth.authenticate('edavis', '123456') | |
113 | assert_nil @auth.authenticate('edavis', '123456') |
|
|||
114 | end |
|
|||
115 | end |
|
|||
116 | end |
|
103 | end | |
117 |
|
104 | |||
118 | def test_authenticate_should_timeout |
|
105 | def test_authenticate_should_timeout | |
119 | auth_source = AuthSourceLdap.find(1) |
|
106 | auth_source = AuthSourceLdap.find(1) | |
120 | auth_source.timeout = 1 |
|
107 | auth_source.timeout = 1 | |
121 | def auth_source.initialize_ldap_con(*args); sleep(5); end |
|
108 | def auth_source.initialize_ldap_con(*args); sleep(5); end | |
122 |
|
109 | |||
123 | assert_raise AuthSourceTimeoutException do |
|
110 | assert_raise AuthSourceTimeoutException do | |
124 | auth_source.authenticate 'example1', '123456' |
|
111 | auth_source.authenticate 'example1', '123456' | |
125 | end |
|
112 | end | |
126 | end |
|
113 | end | |
127 |
|
114 | |||
128 | def test_search_should_return_matching_entries |
|
115 | def test_search_should_return_matching_entries | |
129 | results = AuthSource.search("exa") |
|
116 | results = AuthSource.search("exa") | |
130 | assert_equal 1, results.size |
|
117 | assert_equal 1, results.size | |
131 | result = results.first |
|
118 | result = results.first | |
132 | assert_kind_of Hash, result |
|
119 | assert_kind_of Hash, result | |
133 | assert_equal "example1", result[:login] |
|
120 | assert_equal "example1", result[:login] | |
134 | assert_equal "Example", result[:firstname] |
|
121 | assert_equal "Example", result[:firstname] | |
135 | assert_equal "One", result[:lastname] |
|
122 | assert_equal "One", result[:lastname] | |
136 | assert_equal "example1@redmine.org", result[:mail] |
|
123 | assert_equal "example1@redmine.org", result[:mail] | |
137 | assert_equal 1, result[:auth_source_id] |
|
124 | assert_equal 1, result[:auth_source_id] | |
138 | end |
|
125 | end | |
139 |
|
126 | |||
140 | def test_search_with_no_match_should_return_an_empty_array |
|
127 | def test_search_with_no_match_should_return_an_empty_array | |
141 | results = AuthSource.search("wro") |
|
128 | results = AuthSource.search("wro") | |
142 | assert_equal [], results |
|
129 | assert_equal [], results | |
143 | end |
|
130 | end | |
144 |
|
131 | |||
145 | def test_search_with_exception_should_return_an_empty_array |
|
132 | def test_search_with_exception_should_return_an_empty_array | |
146 | Net::LDAP.stubs(:new).raises(Net::LDAP::LdapError, 'Cannot connect') |
|
133 | Net::LDAP.stubs(:new).raises(Net::LDAP::LdapError, 'Cannot connect') | |
147 |
|
134 | |||
148 | results = AuthSource.search("exa") |
|
135 | results = AuthSource.search("exa") | |
149 | assert_equal [], results |
|
136 | assert_equal [], results | |
150 | end |
|
137 | end | |
151 | else |
|
138 | else | |
152 | puts '(Test LDAP server not configured)' |
|
139 | puts '(Test LDAP server not configured)' | |
153 | end |
|
140 | end | |
154 | end |
|
141 | end |
@@ -1,1957 +1,1905 | |||||
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_create |
|
38 | def test_create | |
39 | issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3, |
|
39 | issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3, | |
40 | :status_id => 1, :priority => IssuePriority.all.first, |
|
40 | :status_id => 1, :priority => IssuePriority.all.first, | |
41 | :subject => 'test_create', |
|
41 | :subject => 'test_create', | |
42 | :description => 'IssueTest#test_create', :estimated_hours => '1:30') |
|
42 | :description => 'IssueTest#test_create', :estimated_hours => '1:30') | |
43 | assert issue.save |
|
43 | assert issue.save | |
44 | issue.reload |
|
44 | issue.reload | |
45 | assert_equal 1.5, issue.estimated_hours |
|
45 | assert_equal 1.5, issue.estimated_hours | |
46 | end |
|
46 | end | |
47 |
|
47 | |||
48 | def test_create_minimal |
|
48 | def test_create_minimal | |
49 | issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3, |
|
49 | issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3, | |
50 | :status_id => 1, :priority => IssuePriority.all.first, |
|
50 | :status_id => 1, :priority => IssuePriority.all.first, | |
51 | :subject => 'test_create') |
|
51 | :subject => 'test_create') | |
52 | assert issue.save |
|
52 | assert issue.save | |
53 | assert issue.description.nil? |
|
53 | assert issue.description.nil? | |
54 | assert_nil issue.estimated_hours |
|
54 | assert_nil issue.estimated_hours | |
55 | end |
|
55 | end | |
56 |
|
56 | |||
57 | def test_start_date_format_should_be_validated |
|
57 | def test_start_date_format_should_be_validated | |
58 | set_language_if_valid 'en' |
|
58 | set_language_if_valid 'en' | |
59 | ['2012', 'ABC', '2012-15-20'].each do |invalid_date| |
|
59 | ['2012', 'ABC', '2012-15-20'].each do |invalid_date| | |
60 | issue = Issue.new(:start_date => invalid_date) |
|
60 | issue = Issue.new(:start_date => invalid_date) | |
61 | assert !issue.valid? |
|
61 | assert !issue.valid? | |
62 | assert_include 'Start date is not a valid date', issue.errors.full_messages, "No error found for invalid date #{invalid_date}" |
|
62 | assert_include 'Start date is not a valid date', issue.errors.full_messages, "No error found for invalid date #{invalid_date}" | |
63 | end |
|
63 | end | |
64 | end |
|
64 | end | |
65 |
|
65 | |||
66 | def test_due_date_format_should_be_validated |
|
66 | def test_due_date_format_should_be_validated | |
67 | set_language_if_valid 'en' |
|
67 | set_language_if_valid 'en' | |
68 | ['2012', 'ABC', '2012-15-20'].each do |invalid_date| |
|
68 | ['2012', 'ABC', '2012-15-20'].each do |invalid_date| | |
69 | issue = Issue.new(:due_date => invalid_date) |
|
69 | issue = Issue.new(:due_date => invalid_date) | |
70 | assert !issue.valid? |
|
70 | assert !issue.valid? | |
71 | assert_include 'Due date is not a valid date', issue.errors.full_messages, "No error found for invalid date #{invalid_date}" |
|
71 | assert_include 'Due date is not a valid date', issue.errors.full_messages, "No error found for invalid date #{invalid_date}" | |
72 | end |
|
72 | end | |
73 | end |
|
73 | end | |
74 |
|
74 | |||
75 | def test_due_date_lesser_than_start_date_should_not_validate |
|
75 | def test_due_date_lesser_than_start_date_should_not_validate | |
76 | set_language_if_valid 'en' |
|
76 | set_language_if_valid 'en' | |
77 | issue = Issue.new(:start_date => '2012-10-06', :due_date => '2012-10-02') |
|
77 | issue = Issue.new(:start_date => '2012-10-06', :due_date => '2012-10-02') | |
78 | assert !issue.valid? |
|
78 | assert !issue.valid? | |
79 | assert_include 'Due date must be greater than start date', issue.errors.full_messages |
|
79 | assert_include 'Due date must be greater than start date', issue.errors.full_messages | |
80 | end |
|
80 | end | |
81 |
|
81 | |||
82 | def test_estimated_hours_should_be_validated |
|
82 | def test_estimated_hours_should_be_validated | |
83 | set_language_if_valid 'en' |
|
83 | set_language_if_valid 'en' | |
84 | ['-2'].each do |invalid| |
|
84 | ['-2'].each do |invalid| | |
85 | issue = Issue.new(:estimated_hours => invalid) |
|
85 | issue = Issue.new(:estimated_hours => invalid) | |
86 | assert !issue.valid? |
|
86 | assert !issue.valid? | |
87 | assert_include 'Estimated time is invalid', issue.errors.full_messages |
|
87 | assert_include 'Estimated time is invalid', issue.errors.full_messages | |
88 | end |
|
88 | end | |
89 | end |
|
89 | end | |
90 |
|
90 | |||
91 | def test_create_with_required_custom_field |
|
91 | def test_create_with_required_custom_field | |
92 | set_language_if_valid 'en' |
|
92 | set_language_if_valid 'en' | |
93 | field = IssueCustomField.find_by_name('Database') |
|
93 | field = IssueCustomField.find_by_name('Database') | |
94 | field.update_attribute(:is_required, true) |
|
94 | field.update_attribute(:is_required, true) | |
95 |
|
95 | |||
96 | issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, |
|
96 | issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, | |
97 | :status_id => 1, :subject => 'test_create', |
|
97 | :status_id => 1, :subject => 'test_create', | |
98 | :description => 'IssueTest#test_create_with_required_custom_field') |
|
98 | :description => 'IssueTest#test_create_with_required_custom_field') | |
99 | assert issue.available_custom_fields.include?(field) |
|
99 | assert issue.available_custom_fields.include?(field) | |
100 | # No value for the custom field |
|
100 | # No value for the custom field | |
101 | assert !issue.save |
|
101 | assert !issue.save | |
102 | assert_equal ["Database can't be blank"], issue.errors.full_messages |
|
102 | assert_equal ["Database can't be blank"], issue.errors.full_messages | |
103 | # Blank value |
|
103 | # Blank value | |
104 | issue.custom_field_values = { field.id => '' } |
|
104 | issue.custom_field_values = { field.id => '' } | |
105 | assert !issue.save |
|
105 | assert !issue.save | |
106 | assert_equal ["Database can't be blank"], issue.errors.full_messages |
|
106 | assert_equal ["Database can't be blank"], issue.errors.full_messages | |
107 | # Invalid value |
|
107 | # Invalid value | |
108 | issue.custom_field_values = { field.id => 'SQLServer' } |
|
108 | issue.custom_field_values = { field.id => 'SQLServer' } | |
109 | assert !issue.save |
|
109 | assert !issue.save | |
110 | assert_equal ["Database is not included in the list"], issue.errors.full_messages |
|
110 | assert_equal ["Database is not included in the list"], issue.errors.full_messages | |
111 | # Valid value |
|
111 | # Valid value | |
112 | issue.custom_field_values = { field.id => 'PostgreSQL' } |
|
112 | issue.custom_field_values = { field.id => 'PostgreSQL' } | |
113 | assert issue.save |
|
113 | assert issue.save | |
114 | issue.reload |
|
114 | issue.reload | |
115 | assert_equal 'PostgreSQL', issue.custom_value_for(field).value |
|
115 | assert_equal 'PostgreSQL', issue.custom_value_for(field).value | |
116 | end |
|
116 | end | |
117 |
|
117 | |||
118 | def test_create_with_group_assignment |
|
118 | def test_create_with_group_assignment | |
119 | with_settings :issue_group_assignment => '1' do |
|
119 | with_settings :issue_group_assignment => '1' do | |
120 | assert Issue.new(:project_id => 2, :tracker_id => 1, :author_id => 1, |
|
120 | assert Issue.new(:project_id => 2, :tracker_id => 1, :author_id => 1, | |
121 | :subject => 'Group assignment', |
|
121 | :subject => 'Group assignment', | |
122 | :assigned_to_id => 11).save |
|
122 | :assigned_to_id => 11).save | |
123 | issue = Issue.first(:order => 'id DESC') |
|
123 | issue = Issue.first(:order => 'id DESC') | |
124 | assert_kind_of Group, issue.assigned_to |
|
124 | assert_kind_of Group, issue.assigned_to | |
125 | assert_equal Group.find(11), issue.assigned_to |
|
125 | assert_equal Group.find(11), issue.assigned_to | |
126 | end |
|
126 | end | |
127 | end |
|
127 | end | |
128 |
|
128 | |||
129 | def test_create_with_parent_issue_id |
|
129 | def test_create_with_parent_issue_id | |
130 | issue = Issue.new(:project_id => 1, :tracker_id => 1, |
|
130 | issue = Issue.new(:project_id => 1, :tracker_id => 1, | |
131 | :author_id => 1, :subject => 'Group assignment', |
|
131 | :author_id => 1, :subject => 'Group assignment', | |
132 | :parent_issue_id => 1) |
|
132 | :parent_issue_id => 1) | |
133 | assert_save issue |
|
133 | assert_save issue | |
134 | assert_equal 1, issue.parent_issue_id |
|
134 | assert_equal 1, issue.parent_issue_id | |
135 | assert_equal Issue.find(1), issue.parent |
|
135 | assert_equal Issue.find(1), issue.parent | |
136 | end |
|
136 | end | |
137 |
|
137 | |||
138 | def test_create_with_sharp_parent_issue_id |
|
138 | def test_create_with_sharp_parent_issue_id | |
139 | issue = Issue.new(:project_id => 1, :tracker_id => 1, |
|
139 | issue = Issue.new(:project_id => 1, :tracker_id => 1, | |
140 | :author_id => 1, :subject => 'Group assignment', |
|
140 | :author_id => 1, :subject => 'Group assignment', | |
141 | :parent_issue_id => "#1") |
|
141 | :parent_issue_id => "#1") | |
142 | assert_save issue |
|
142 | assert_save issue | |
143 | assert_equal 1, issue.parent_issue_id |
|
143 | assert_equal 1, issue.parent_issue_id | |
144 | assert_equal Issue.find(1), issue.parent |
|
144 | assert_equal Issue.find(1), issue.parent | |
145 | end |
|
145 | end | |
146 |
|
146 | |||
147 | def test_create_with_invalid_parent_issue_id |
|
147 | def test_create_with_invalid_parent_issue_id | |
148 | set_language_if_valid 'en' |
|
148 | set_language_if_valid 'en' | |
149 | issue = Issue.new(:project_id => 1, :tracker_id => 1, |
|
149 | issue = Issue.new(:project_id => 1, :tracker_id => 1, | |
150 | :author_id => 1, :subject => 'Group assignment', |
|
150 | :author_id => 1, :subject => 'Group assignment', | |
151 | :parent_issue_id => '01ABC') |
|
151 | :parent_issue_id => '01ABC') | |
152 | assert !issue.save |
|
152 | assert !issue.save | |
153 | assert_equal '01ABC', issue.parent_issue_id |
|
153 | assert_equal '01ABC', issue.parent_issue_id | |
154 | assert_include 'Parent task is invalid', issue.errors.full_messages |
|
154 | assert_include 'Parent task is invalid', issue.errors.full_messages | |
155 | end |
|
155 | end | |
156 |
|
156 | |||
157 | def test_create_with_invalid_sharp_parent_issue_id |
|
157 | def test_create_with_invalid_sharp_parent_issue_id | |
158 | set_language_if_valid 'en' |
|
158 | set_language_if_valid 'en' | |
159 | issue = Issue.new(:project_id => 1, :tracker_id => 1, |
|
159 | issue = Issue.new(:project_id => 1, :tracker_id => 1, | |
160 | :author_id => 1, :subject => 'Group assignment', |
|
160 | :author_id => 1, :subject => 'Group assignment', | |
161 | :parent_issue_id => '#01ABC') |
|
161 | :parent_issue_id => '#01ABC') | |
162 | assert !issue.save |
|
162 | assert !issue.save | |
163 | assert_equal '#01ABC', issue.parent_issue_id |
|
163 | assert_equal '#01ABC', issue.parent_issue_id | |
164 | assert_include 'Parent task is invalid', issue.errors.full_messages |
|
164 | assert_include 'Parent task is invalid', issue.errors.full_messages | |
165 | end |
|
165 | end | |
166 |
|
166 | |||
167 | def assert_visibility_match(user, issues) |
|
167 | def assert_visibility_match(user, issues) | |
168 | assert_equal issues.collect(&:id).sort, Issue.all.select {|issue| issue.visible?(user)}.collect(&:id).sort |
|
168 | assert_equal issues.collect(&:id).sort, Issue.all.select {|issue| issue.visible?(user)}.collect(&:id).sort | |
169 | end |
|
169 | end | |
170 |
|
170 | |||
171 | def test_visible_scope_for_anonymous |
|
171 | def test_visible_scope_for_anonymous | |
172 | # Anonymous user should see issues of public projects only |
|
172 | # Anonymous user should see issues of public projects only | |
173 | issues = Issue.visible(User.anonymous).all |
|
173 | issues = Issue.visible(User.anonymous).all | |
174 | assert issues.any? |
|
174 | assert issues.any? | |
175 | assert_nil issues.detect {|issue| !issue.project.is_public?} |
|
175 | assert_nil issues.detect {|issue| !issue.project.is_public?} | |
176 | assert_nil issues.detect {|issue| issue.is_private?} |
|
176 | assert_nil issues.detect {|issue| issue.is_private?} | |
177 | assert_visibility_match User.anonymous, issues |
|
177 | assert_visibility_match User.anonymous, issues | |
178 | end |
|
178 | end | |
179 |
|
179 | |||
180 | def test_visible_scope_for_anonymous_without_view_issues_permissions |
|
180 | def test_visible_scope_for_anonymous_without_view_issues_permissions | |
181 | # Anonymous user should not see issues without permission |
|
181 | # Anonymous user should not see issues without permission | |
182 | Role.anonymous.remove_permission!(:view_issues) |
|
182 | Role.anonymous.remove_permission!(:view_issues) | |
183 | issues = Issue.visible(User.anonymous).all |
|
183 | issues = Issue.visible(User.anonymous).all | |
184 | assert issues.empty? |
|
184 | assert issues.empty? | |
185 | assert_visibility_match User.anonymous, issues |
|
185 | assert_visibility_match User.anonymous, issues | |
186 | end |
|
186 | end | |
187 |
|
187 | |||
188 | def test_anonymous_should_not_see_private_issues_with_issues_visibility_set_to_default |
|
188 | def test_anonymous_should_not_see_private_issues_with_issues_visibility_set_to_default | |
189 | assert Role.anonymous.update_attribute(:issues_visibility, 'default') |
|
189 | assert Role.anonymous.update_attribute(:issues_visibility, 'default') | |
190 | issue = Issue.generate!(:author => User.anonymous, :assigned_to => User.anonymous, :is_private => true) |
|
190 | issue = Issue.generate!(:author => User.anonymous, :assigned_to => User.anonymous, :is_private => true) | |
191 | assert_nil Issue.where(:id => issue.id).visible(User.anonymous).first |
|
191 | assert_nil Issue.where(:id => issue.id).visible(User.anonymous).first | |
192 | assert !issue.visible?(User.anonymous) |
|
192 | assert !issue.visible?(User.anonymous) | |
193 | end |
|
193 | end | |
194 |
|
194 | |||
195 | def test_anonymous_should_not_see_private_issues_with_issues_visibility_set_to_own |
|
195 | def test_anonymous_should_not_see_private_issues_with_issues_visibility_set_to_own | |
196 | assert Role.anonymous.update_attribute(:issues_visibility, 'own') |
|
196 | assert Role.anonymous.update_attribute(:issues_visibility, 'own') | |
197 | issue = Issue.generate!(:author => User.anonymous, :assigned_to => User.anonymous, :is_private => true) |
|
197 | issue = Issue.generate!(:author => User.anonymous, :assigned_to => User.anonymous, :is_private => true) | |
198 | assert_nil Issue.where(:id => issue.id).visible(User.anonymous).first |
|
198 | assert_nil Issue.where(:id => issue.id).visible(User.anonymous).first | |
199 | assert !issue.visible?(User.anonymous) |
|
199 | assert !issue.visible?(User.anonymous) | |
200 | end |
|
200 | end | |
201 |
|
201 | |||
202 | def test_visible_scope_for_non_member |
|
202 | def test_visible_scope_for_non_member | |
203 | user = User.find(9) |
|
203 | user = User.find(9) | |
204 | assert user.projects.empty? |
|
204 | assert user.projects.empty? | |
205 | # Non member user should see issues of public projects only |
|
205 | # Non member user should see issues of public projects only | |
206 | issues = Issue.visible(user).all |
|
206 | issues = Issue.visible(user).all | |
207 | assert issues.any? |
|
207 | assert issues.any? | |
208 | assert_nil issues.detect {|issue| !issue.project.is_public?} |
|
208 | assert_nil issues.detect {|issue| !issue.project.is_public?} | |
209 | assert_nil issues.detect {|issue| issue.is_private?} |
|
209 | assert_nil issues.detect {|issue| issue.is_private?} | |
210 | assert_visibility_match user, issues |
|
210 | assert_visibility_match user, issues | |
211 | end |
|
211 | end | |
212 |
|
212 | |||
213 | def test_visible_scope_for_non_member_with_own_issues_visibility |
|
213 | def test_visible_scope_for_non_member_with_own_issues_visibility | |
214 | Role.non_member.update_attribute :issues_visibility, 'own' |
|
214 | Role.non_member.update_attribute :issues_visibility, 'own' | |
215 | Issue.create!(:project_id => 1, :tracker_id => 1, :author_id => 9, :subject => 'Issue by non member') |
|
215 | Issue.create!(:project_id => 1, :tracker_id => 1, :author_id => 9, :subject => 'Issue by non member') | |
216 | user = User.find(9) |
|
216 | user = User.find(9) | |
217 |
|
217 | |||
218 | issues = Issue.visible(user).all |
|
218 | issues = Issue.visible(user).all | |
219 | assert issues.any? |
|
219 | assert issues.any? | |
220 | assert_nil issues.detect {|issue| issue.author != user} |
|
220 | assert_nil issues.detect {|issue| issue.author != user} | |
221 | assert_visibility_match user, issues |
|
221 | assert_visibility_match user, issues | |
222 | end |
|
222 | end | |
223 |
|
223 | |||
224 | def test_visible_scope_for_non_member_without_view_issues_permissions |
|
224 | def test_visible_scope_for_non_member_without_view_issues_permissions | |
225 | # Non member user should not see issues without permission |
|
225 | # Non member user should not see issues without permission | |
226 | Role.non_member.remove_permission!(:view_issues) |
|
226 | Role.non_member.remove_permission!(:view_issues) | |
227 | user = User.find(9) |
|
227 | user = User.find(9) | |
228 | assert user.projects.empty? |
|
228 | assert user.projects.empty? | |
229 | issues = Issue.visible(user).all |
|
229 | issues = Issue.visible(user).all | |
230 | assert issues.empty? |
|
230 | assert issues.empty? | |
231 | assert_visibility_match user, issues |
|
231 | assert_visibility_match user, issues | |
232 | end |
|
232 | end | |
233 |
|
233 | |||
234 | def test_visible_scope_for_member |
|
234 | def test_visible_scope_for_member | |
235 | user = User.find(9) |
|
235 | user = User.find(9) | |
236 | # User should see issues of projects for which he has view_issues permissions only |
|
236 | # User should see issues of projects for which he has view_issues permissions only | |
237 | Role.non_member.remove_permission!(:view_issues) |
|
237 | Role.non_member.remove_permission!(:view_issues) | |
238 | Member.create!(:principal => user, :project_id => 3, :role_ids => [2]) |
|
238 | Member.create!(:principal => user, :project_id => 3, :role_ids => [2]) | |
239 | issues = Issue.visible(user).all |
|
239 | issues = Issue.visible(user).all | |
240 | assert issues.any? |
|
240 | assert issues.any? | |
241 | assert_nil issues.detect {|issue| issue.project_id != 3} |
|
241 | assert_nil issues.detect {|issue| issue.project_id != 3} | |
242 | assert_nil issues.detect {|issue| issue.is_private?} |
|
242 | assert_nil issues.detect {|issue| issue.is_private?} | |
243 | assert_visibility_match user, issues |
|
243 | assert_visibility_match user, issues | |
244 | end |
|
244 | end | |
245 |
|
245 | |||
246 | def test_visible_scope_for_member_with_groups_should_return_assigned_issues |
|
246 | def test_visible_scope_for_member_with_groups_should_return_assigned_issues | |
247 | user = User.find(8) |
|
247 | user = User.find(8) | |
248 | assert user.groups.any? |
|
248 | assert user.groups.any? | |
249 | Member.create!(:principal => user.groups.first, :project_id => 1, :role_ids => [2]) |
|
249 | Member.create!(:principal => user.groups.first, :project_id => 1, :role_ids => [2]) | |
250 | Role.non_member.remove_permission!(:view_issues) |
|
250 | Role.non_member.remove_permission!(:view_issues) | |
251 |
|
251 | |||
252 | issue = Issue.create(:project_id => 1, :tracker_id => 1, :author_id => 3, |
|
252 | issue = Issue.create(:project_id => 1, :tracker_id => 1, :author_id => 3, | |
253 | :status_id => 1, :priority => IssuePriority.all.first, |
|
253 | :status_id => 1, :priority => IssuePriority.all.first, | |
254 | :subject => 'Assignment test', |
|
254 | :subject => 'Assignment test', | |
255 | :assigned_to => user.groups.first, |
|
255 | :assigned_to => user.groups.first, | |
256 | :is_private => true) |
|
256 | :is_private => true) | |
257 |
|
257 | |||
258 | Role.find(2).update_attribute :issues_visibility, 'default' |
|
258 | Role.find(2).update_attribute :issues_visibility, 'default' | |
259 | issues = Issue.visible(User.find(8)).all |
|
259 | issues = Issue.visible(User.find(8)).all | |
260 | assert issues.any? |
|
260 | assert issues.any? | |
261 | assert issues.include?(issue) |
|
261 | assert issues.include?(issue) | |
262 |
|
262 | |||
263 | Role.find(2).update_attribute :issues_visibility, 'own' |
|
263 | Role.find(2).update_attribute :issues_visibility, 'own' | |
264 | issues = Issue.visible(User.find(8)).all |
|
264 | issues = Issue.visible(User.find(8)).all | |
265 | assert issues.any? |
|
265 | assert issues.any? | |
266 | assert issues.include?(issue) |
|
266 | assert issues.include?(issue) | |
267 | end |
|
267 | end | |
268 |
|
268 | |||
269 | def test_visible_scope_for_admin |
|
269 | def test_visible_scope_for_admin | |
270 | user = User.find(1) |
|
270 | user = User.find(1) | |
271 | user.members.each(&:destroy) |
|
271 | user.members.each(&:destroy) | |
272 | assert user.projects.empty? |
|
272 | assert user.projects.empty? | |
273 | issues = Issue.visible(user).all |
|
273 | issues = Issue.visible(user).all | |
274 | assert issues.any? |
|
274 | assert issues.any? | |
275 | # Admin should see issues on private projects that he does not belong to |
|
275 | # Admin should see issues on private projects that he does not belong to | |
276 | assert issues.detect {|issue| !issue.project.is_public?} |
|
276 | assert issues.detect {|issue| !issue.project.is_public?} | |
277 | # Admin should see private issues of other users |
|
277 | # Admin should see private issues of other users | |
278 | assert issues.detect {|issue| issue.is_private? && issue.author != user} |
|
278 | assert issues.detect {|issue| issue.is_private? && issue.author != user} | |
279 | assert_visibility_match user, issues |
|
279 | assert_visibility_match user, issues | |
280 | end |
|
280 | end | |
281 |
|
281 | |||
282 | def test_visible_scope_with_project |
|
282 | def test_visible_scope_with_project | |
283 | project = Project.find(1) |
|
283 | project = Project.find(1) | |
284 | issues = Issue.visible(User.find(2), :project => project).all |
|
284 | issues = Issue.visible(User.find(2), :project => project).all | |
285 | projects = issues.collect(&:project).uniq |
|
285 | projects = issues.collect(&:project).uniq | |
286 | assert_equal 1, projects.size |
|
286 | assert_equal 1, projects.size | |
287 | assert_equal project, projects.first |
|
287 | assert_equal project, projects.first | |
288 | end |
|
288 | end | |
289 |
|
289 | |||
290 | def test_visible_scope_with_project_and_subprojects |
|
290 | def test_visible_scope_with_project_and_subprojects | |
291 | project = Project.find(1) |
|
291 | project = Project.find(1) | |
292 | issues = Issue.visible(User.find(2), :project => project, :with_subprojects => true).all |
|
292 | issues = Issue.visible(User.find(2), :project => project, :with_subprojects => true).all | |
293 | projects = issues.collect(&:project).uniq |
|
293 | projects = issues.collect(&:project).uniq | |
294 | assert projects.size > 1 |
|
294 | assert projects.size > 1 | |
295 | assert_equal [], projects.select {|p| !p.is_or_is_descendant_of?(project)} |
|
295 | assert_equal [], projects.select {|p| !p.is_or_is_descendant_of?(project)} | |
296 | end |
|
296 | end | |
297 |
|
297 | |||
298 | def test_visible_and_nested_set_scopes |
|
298 | def test_visible_and_nested_set_scopes | |
299 | assert_equal 0, Issue.find(1).descendants.visible.all.size |
|
299 | assert_equal 0, Issue.find(1).descendants.visible.all.size | |
300 | end |
|
300 | end | |
301 |
|
301 | |||
302 | def test_open_scope |
|
302 | def test_open_scope | |
303 | issues = Issue.open.all |
|
303 | issues = Issue.open.all | |
304 | assert_nil issues.detect(&:closed?) |
|
304 | assert_nil issues.detect(&:closed?) | |
305 | end |
|
305 | end | |
306 |
|
306 | |||
307 | def test_open_scope_with_arg |
|
307 | def test_open_scope_with_arg | |
308 | issues = Issue.open(false).all |
|
308 | issues = Issue.open(false).all | |
309 | assert_equal issues, issues.select(&:closed?) |
|
309 | assert_equal issues, issues.select(&:closed?) | |
310 | end |
|
310 | end | |
311 |
|
311 | |||
312 | def test_fixed_version_scope_with_a_version_should_return_its_fixed_issues |
|
312 | def test_fixed_version_scope_with_a_version_should_return_its_fixed_issues | |
313 | version = Version.find(2) |
|
313 | version = Version.find(2) | |
314 | assert version.fixed_issues.any? |
|
314 | assert version.fixed_issues.any? | |
315 | assert_equal version.fixed_issues.to_a.sort, Issue.fixed_version(version).to_a.sort |
|
315 | assert_equal version.fixed_issues.to_a.sort, Issue.fixed_version(version).to_a.sort | |
316 | end |
|
316 | end | |
317 |
|
317 | |||
318 | def test_fixed_version_scope_with_empty_array_should_return_no_result |
|
318 | def test_fixed_version_scope_with_empty_array_should_return_no_result | |
319 | assert_equal 0, Issue.fixed_version([]).count |
|
319 | assert_equal 0, Issue.fixed_version([]).count | |
320 | end |
|
320 | end | |
321 |
|
321 | |||
322 | def test_errors_full_messages_should_include_custom_fields_errors |
|
322 | def test_errors_full_messages_should_include_custom_fields_errors | |
323 | field = IssueCustomField.find_by_name('Database') |
|
323 | field = IssueCustomField.find_by_name('Database') | |
324 |
|
324 | |||
325 | issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, |
|
325 | issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, | |
326 | :status_id => 1, :subject => 'test_create', |
|
326 | :status_id => 1, :subject => 'test_create', | |
327 | :description => 'IssueTest#test_create_with_required_custom_field') |
|
327 | :description => 'IssueTest#test_create_with_required_custom_field') | |
328 | assert issue.available_custom_fields.include?(field) |
|
328 | assert issue.available_custom_fields.include?(field) | |
329 | # Invalid value |
|
329 | # Invalid value | |
330 | issue.custom_field_values = { field.id => 'SQLServer' } |
|
330 | issue.custom_field_values = { field.id => 'SQLServer' } | |
331 |
|
331 | |||
332 | assert !issue.valid? |
|
332 | assert !issue.valid? | |
333 | assert_equal 1, issue.errors.full_messages.size |
|
333 | assert_equal 1, issue.errors.full_messages.size | |
334 | assert_equal "Database #{I18n.translate('activerecord.errors.messages.inclusion')}", |
|
334 | assert_equal "Database #{I18n.translate('activerecord.errors.messages.inclusion')}", | |
335 | issue.errors.full_messages.first |
|
335 | issue.errors.full_messages.first | |
336 | end |
|
336 | end | |
337 |
|
337 | |||
338 | def test_update_issue_with_required_custom_field |
|
338 | def test_update_issue_with_required_custom_field | |
339 | field = IssueCustomField.find_by_name('Database') |
|
339 | field = IssueCustomField.find_by_name('Database') | |
340 | field.update_attribute(:is_required, true) |
|
340 | field.update_attribute(:is_required, true) | |
341 |
|
341 | |||
342 | issue = Issue.find(1) |
|
342 | issue = Issue.find(1) | |
343 | assert_nil issue.custom_value_for(field) |
|
343 | assert_nil issue.custom_value_for(field) | |
344 | assert issue.available_custom_fields.include?(field) |
|
344 | assert issue.available_custom_fields.include?(field) | |
345 | # No change to custom values, issue can be saved |
|
345 | # No change to custom values, issue can be saved | |
346 | assert issue.save |
|
346 | assert issue.save | |
347 | # Blank value |
|
347 | # Blank value | |
348 | issue.custom_field_values = { field.id => '' } |
|
348 | issue.custom_field_values = { field.id => '' } | |
349 | assert !issue.save |
|
349 | assert !issue.save | |
350 | # Valid value |
|
350 | # Valid value | |
351 | issue.custom_field_values = { field.id => 'PostgreSQL' } |
|
351 | issue.custom_field_values = { field.id => 'PostgreSQL' } | |
352 | assert issue.save |
|
352 | assert issue.save | |
353 | issue.reload |
|
353 | issue.reload | |
354 | assert_equal 'PostgreSQL', issue.custom_value_for(field).value |
|
354 | assert_equal 'PostgreSQL', issue.custom_value_for(field).value | |
355 | end |
|
355 | end | |
356 |
|
356 | |||
357 | def test_should_not_update_attributes_if_custom_fields_validation_fails |
|
357 | def test_should_not_update_attributes_if_custom_fields_validation_fails | |
358 | issue = Issue.find(1) |
|
358 | issue = Issue.find(1) | |
359 | field = IssueCustomField.find_by_name('Database') |
|
359 | field = IssueCustomField.find_by_name('Database') | |
360 | assert issue.available_custom_fields.include?(field) |
|
360 | assert issue.available_custom_fields.include?(field) | |
361 |
|
361 | |||
362 | issue.custom_field_values = { field.id => 'Invalid' } |
|
362 | issue.custom_field_values = { field.id => 'Invalid' } | |
363 | issue.subject = 'Should be not be saved' |
|
363 | issue.subject = 'Should be not be saved' | |
364 | assert !issue.save |
|
364 | assert !issue.save | |
365 |
|
365 | |||
366 | issue.reload |
|
366 | issue.reload | |
367 | assert_equal "Can't print recipes", issue.subject |
|
367 | assert_equal "Can't print recipes", issue.subject | |
368 | end |
|
368 | end | |
369 |
|
369 | |||
370 | def test_should_not_recreate_custom_values_objects_on_update |
|
370 | def test_should_not_recreate_custom_values_objects_on_update | |
371 | field = IssueCustomField.find_by_name('Database') |
|
371 | field = IssueCustomField.find_by_name('Database') | |
372 |
|
372 | |||
373 | issue = Issue.find(1) |
|
373 | issue = Issue.find(1) | |
374 | issue.custom_field_values = { field.id => 'PostgreSQL' } |
|
374 | issue.custom_field_values = { field.id => 'PostgreSQL' } | |
375 | assert issue.save |
|
375 | assert issue.save | |
376 | custom_value = issue.custom_value_for(field) |
|
376 | custom_value = issue.custom_value_for(field) | |
377 | issue.reload |
|
377 | issue.reload | |
378 | issue.custom_field_values = { field.id => 'MySQL' } |
|
378 | issue.custom_field_values = { field.id => 'MySQL' } | |
379 | assert issue.save |
|
379 | assert issue.save | |
380 | issue.reload |
|
380 | issue.reload | |
381 | assert_equal custom_value.id, issue.custom_value_for(field).id |
|
381 | assert_equal custom_value.id, issue.custom_value_for(field).id | |
382 | end |
|
382 | end | |
383 |
|
383 | |||
384 | def test_should_not_update_custom_fields_on_changing_tracker_with_different_custom_fields |
|
384 | def test_should_not_update_custom_fields_on_changing_tracker_with_different_custom_fields | |
385 | issue = Issue.create!(:project_id => 1, :tracker_id => 1, :author_id => 1, |
|
385 | issue = Issue.create!(:project_id => 1, :tracker_id => 1, :author_id => 1, | |
386 | :status_id => 1, :subject => 'Test', |
|
386 | :status_id => 1, :subject => 'Test', | |
387 | :custom_field_values => {'2' => 'Test'}) |
|
387 | :custom_field_values => {'2' => 'Test'}) | |
388 | assert !Tracker.find(2).custom_field_ids.include?(2) |
|
388 | assert !Tracker.find(2).custom_field_ids.include?(2) | |
389 |
|
389 | |||
390 | issue = Issue.find(issue.id) |
|
390 | issue = Issue.find(issue.id) | |
391 | issue.attributes = {:tracker_id => 2, :custom_field_values => {'1' => ''}} |
|
391 | issue.attributes = {:tracker_id => 2, :custom_field_values => {'1' => ''}} | |
392 |
|
392 | |||
393 | issue = Issue.find(issue.id) |
|
393 | issue = Issue.find(issue.id) | |
394 | custom_value = issue.custom_value_for(2) |
|
394 | custom_value = issue.custom_value_for(2) | |
395 | assert_not_nil custom_value |
|
395 | assert_not_nil custom_value | |
396 | assert_equal 'Test', custom_value.value |
|
396 | assert_equal 'Test', custom_value.value | |
397 | end |
|
397 | end | |
398 |
|
398 | |||
399 | def test_assigning_tracker_id_should_reload_custom_fields_values |
|
399 | def test_assigning_tracker_id_should_reload_custom_fields_values | |
400 | issue = Issue.new(:project => Project.find(1)) |
|
400 | issue = Issue.new(:project => Project.find(1)) | |
401 | assert issue.custom_field_values.empty? |
|
401 | assert issue.custom_field_values.empty? | |
402 | issue.tracker_id = 1 |
|
402 | issue.tracker_id = 1 | |
403 | assert issue.custom_field_values.any? |
|
403 | assert issue.custom_field_values.any? | |
404 | end |
|
404 | end | |
405 |
|
405 | |||
406 | def test_assigning_attributes_should_assign_project_and_tracker_first |
|
406 | def test_assigning_attributes_should_assign_project_and_tracker_first | |
407 | seq = sequence('seq') |
|
407 | seq = sequence('seq') | |
408 | issue = Issue.new |
|
408 | issue = Issue.new | |
409 | issue.expects(:project_id=).in_sequence(seq) |
|
409 | issue.expects(:project_id=).in_sequence(seq) | |
410 | issue.expects(:tracker_id=).in_sequence(seq) |
|
410 | issue.expects(:tracker_id=).in_sequence(seq) | |
411 | issue.expects(:subject=).in_sequence(seq) |
|
411 | issue.expects(:subject=).in_sequence(seq) | |
412 | issue.attributes = {:tracker_id => 2, :project_id => 1, :subject => 'Test'} |
|
412 | issue.attributes = {:tracker_id => 2, :project_id => 1, :subject => 'Test'} | |
413 | end |
|
413 | end | |
414 |
|
414 | |||
415 | def test_assigning_tracker_and_custom_fields_should_assign_custom_fields |
|
415 | def test_assigning_tracker_and_custom_fields_should_assign_custom_fields | |
416 | attributes = ActiveSupport::OrderedHash.new |
|
416 | attributes = ActiveSupport::OrderedHash.new | |
417 | attributes['custom_field_values'] = { '1' => 'MySQL' } |
|
417 | attributes['custom_field_values'] = { '1' => 'MySQL' } | |
418 | attributes['tracker_id'] = '1' |
|
418 | attributes['tracker_id'] = '1' | |
419 | issue = Issue.new(:project => Project.find(1)) |
|
419 | issue = Issue.new(:project => Project.find(1)) | |
420 | issue.attributes = attributes |
|
420 | issue.attributes = attributes | |
421 | assert_equal 'MySQL', issue.custom_field_value(1) |
|
421 | assert_equal 'MySQL', issue.custom_field_value(1) | |
422 | end |
|
422 | end | |
423 |
|
423 | |||
424 | def test_should_update_issue_with_disabled_tracker |
|
424 | def test_should_update_issue_with_disabled_tracker | |
425 | p = Project.find(1) |
|
425 | p = Project.find(1) | |
426 | issue = Issue.find(1) |
|
426 | issue = Issue.find(1) | |
427 |
|
427 | |||
428 | p.trackers.delete(issue.tracker) |
|
428 | p.trackers.delete(issue.tracker) | |
429 | assert !p.trackers.include?(issue.tracker) |
|
429 | assert !p.trackers.include?(issue.tracker) | |
430 |
|
430 | |||
431 | issue.reload |
|
431 | issue.reload | |
432 | issue.subject = 'New subject' |
|
432 | issue.subject = 'New subject' | |
433 | assert issue.save |
|
433 | assert issue.save | |
434 | end |
|
434 | end | |
435 |
|
435 | |||
436 | def test_should_not_set_a_disabled_tracker |
|
436 | def test_should_not_set_a_disabled_tracker | |
437 | p = Project.find(1) |
|
437 | p = Project.find(1) | |
438 | p.trackers.delete(Tracker.find(2)) |
|
438 | p.trackers.delete(Tracker.find(2)) | |
439 |
|
439 | |||
440 | issue = Issue.find(1) |
|
440 | issue = Issue.find(1) | |
441 | issue.tracker_id = 2 |
|
441 | issue.tracker_id = 2 | |
442 | issue.subject = 'New subject' |
|
442 | issue.subject = 'New subject' | |
443 | assert !issue.save |
|
443 | assert !issue.save | |
444 | assert_not_nil issue.errors[:tracker_id] |
|
444 | assert_not_nil issue.errors[:tracker_id] | |
445 | end |
|
445 | end | |
446 |
|
446 | |||
447 | def test_category_based_assignment |
|
447 | def test_category_based_assignment | |
448 | issue = Issue.create(:project_id => 1, :tracker_id => 1, :author_id => 3, |
|
448 | issue = Issue.create(:project_id => 1, :tracker_id => 1, :author_id => 3, | |
449 | :status_id => 1, :priority => IssuePriority.all.first, |
|
449 | :status_id => 1, :priority => IssuePriority.all.first, | |
450 | :subject => 'Assignment test', |
|
450 | :subject => 'Assignment test', | |
451 | :description => 'Assignment test', :category_id => 1) |
|
451 | :description => 'Assignment test', :category_id => 1) | |
452 | assert_equal IssueCategory.find(1).assigned_to, issue.assigned_to |
|
452 | assert_equal IssueCategory.find(1).assigned_to, issue.assigned_to | |
453 | end |
|
453 | end | |
454 |
|
454 | |||
455 | def test_new_statuses_allowed_to |
|
455 | def test_new_statuses_allowed_to | |
456 | WorkflowTransition.delete_all |
|
456 | WorkflowTransition.delete_all | |
457 | WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, |
|
457 | WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, | |
458 | :old_status_id => 1, :new_status_id => 2, |
|
458 | :old_status_id => 1, :new_status_id => 2, | |
459 | :author => false, :assignee => false) |
|
459 | :author => false, :assignee => false) | |
460 | WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, |
|
460 | WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, | |
461 | :old_status_id => 1, :new_status_id => 3, |
|
461 | :old_status_id => 1, :new_status_id => 3, | |
462 | :author => true, :assignee => false) |
|
462 | :author => true, :assignee => false) | |
463 | WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, |
|
463 | WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, | |
464 | :new_status_id => 4, :author => false, |
|
464 | :new_status_id => 4, :author => false, | |
465 | :assignee => true) |
|
465 | :assignee => true) | |
466 | WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, |
|
466 | WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, | |
467 | :old_status_id => 1, :new_status_id => 5, |
|
467 | :old_status_id => 1, :new_status_id => 5, | |
468 | :author => true, :assignee => true) |
|
468 | :author => true, :assignee => true) | |
469 | status = IssueStatus.find(1) |
|
469 | status = IssueStatus.find(1) | |
470 | role = Role.find(1) |
|
470 | role = Role.find(1) | |
471 | tracker = Tracker.find(1) |
|
471 | tracker = Tracker.find(1) | |
472 | user = User.find(2) |
|
472 | user = User.find(2) | |
473 |
|
473 | |||
474 | issue = Issue.generate!(:tracker => tracker, :status => status, |
|
474 | issue = Issue.generate!(:tracker => tracker, :status => status, | |
475 | :project_id => 1, :author_id => 1) |
|
475 | :project_id => 1, :author_id => 1) | |
476 | assert_equal [1, 2], issue.new_statuses_allowed_to(user).map(&:id) |
|
476 | assert_equal [1, 2], issue.new_statuses_allowed_to(user).map(&:id) | |
477 |
|
477 | |||
478 | issue = Issue.generate!(:tracker => tracker, :status => status, |
|
478 | issue = Issue.generate!(:tracker => tracker, :status => status, | |
479 | :project_id => 1, :author => user) |
|
479 | :project_id => 1, :author => user) | |
480 | assert_equal [1, 2, 3, 5], issue.new_statuses_allowed_to(user).map(&:id) |
|
480 | assert_equal [1, 2, 3, 5], issue.new_statuses_allowed_to(user).map(&:id) | |
481 |
|
481 | |||
482 | issue = Issue.generate!(:tracker => tracker, :status => status, |
|
482 | issue = Issue.generate!(:tracker => tracker, :status => status, | |
483 | :project_id => 1, :author_id => 1, |
|
483 | :project_id => 1, :author_id => 1, | |
484 | :assigned_to => user) |
|
484 | :assigned_to => user) | |
485 | assert_equal [1, 2, 4, 5], issue.new_statuses_allowed_to(user).map(&:id) |
|
485 | assert_equal [1, 2, 4, 5], issue.new_statuses_allowed_to(user).map(&:id) | |
486 |
|
486 | |||
487 | issue = Issue.generate!(:tracker => tracker, :status => status, |
|
487 | issue = Issue.generate!(:tracker => tracker, :status => status, | |
488 | :project_id => 1, :author => user, |
|
488 | :project_id => 1, :author => user, | |
489 | :assigned_to => user) |
|
489 | :assigned_to => user) | |
490 | assert_equal [1, 2, 3, 4, 5], issue.new_statuses_allowed_to(user).map(&:id) |
|
490 | assert_equal [1, 2, 3, 4, 5], issue.new_statuses_allowed_to(user).map(&:id) | |
491 | end |
|
491 | end | |
492 |
|
492 | |||
493 | def test_new_statuses_allowed_to_should_return_all_transitions_for_admin |
|
493 | def test_new_statuses_allowed_to_should_return_all_transitions_for_admin | |
494 | admin = User.find(1) |
|
494 | admin = User.find(1) | |
495 | issue = Issue.find(1) |
|
495 | issue = Issue.find(1) | |
496 | assert !admin.member_of?(issue.project) |
|
496 | assert !admin.member_of?(issue.project) | |
497 | expected_statuses = [issue.status] + |
|
497 | expected_statuses = [issue.status] + | |
498 | WorkflowTransition.find_all_by_old_status_id( |
|
498 | WorkflowTransition.find_all_by_old_status_id( | |
499 | issue.status_id).map(&:new_status).uniq.sort |
|
499 | issue.status_id).map(&:new_status).uniq.sort | |
500 | assert_equal expected_statuses, issue.new_statuses_allowed_to(admin) |
|
500 | assert_equal expected_statuses, issue.new_statuses_allowed_to(admin) | |
501 | end |
|
501 | end | |
502 |
|
502 | |||
503 | def test_new_statuses_allowed_to_should_return_default_and_current_status_when_copying |
|
503 | def test_new_statuses_allowed_to_should_return_default_and_current_status_when_copying | |
504 | issue = Issue.find(1).copy |
|
504 | issue = Issue.find(1).copy | |
505 | assert_equal [1], issue.new_statuses_allowed_to(User.find(2)).map(&:id) |
|
505 | assert_equal [1], issue.new_statuses_allowed_to(User.find(2)).map(&:id) | |
506 |
|
506 | |||
507 | issue = Issue.find(2).copy |
|
507 | issue = Issue.find(2).copy | |
508 | assert_equal [1, 2], issue.new_statuses_allowed_to(User.find(2)).map(&:id) |
|
508 | assert_equal [1, 2], issue.new_statuses_allowed_to(User.find(2)).map(&:id) | |
509 | end |
|
509 | end | |
510 |
|
510 | |||
511 | def test_safe_attributes_names_should_not_include_disabled_field |
|
511 | def test_safe_attributes_names_should_not_include_disabled_field | |
512 | tracker = Tracker.new(:core_fields => %w(assigned_to_id fixed_version_id)) |
|
512 | tracker = Tracker.new(:core_fields => %w(assigned_to_id fixed_version_id)) | |
513 |
|
513 | |||
514 | issue = Issue.new(:tracker => tracker) |
|
514 | issue = Issue.new(:tracker => tracker) | |
515 | assert_include 'tracker_id', issue.safe_attribute_names |
|
515 | assert_include 'tracker_id', issue.safe_attribute_names | |
516 | assert_include 'status_id', issue.safe_attribute_names |
|
516 | assert_include 'status_id', issue.safe_attribute_names | |
517 | assert_include 'subject', issue.safe_attribute_names |
|
517 | assert_include 'subject', issue.safe_attribute_names | |
518 | assert_include 'description', issue.safe_attribute_names |
|
518 | assert_include 'description', issue.safe_attribute_names | |
519 | assert_include 'custom_field_values', issue.safe_attribute_names |
|
519 | assert_include 'custom_field_values', issue.safe_attribute_names | |
520 | assert_include 'custom_fields', issue.safe_attribute_names |
|
520 | assert_include 'custom_fields', issue.safe_attribute_names | |
521 | assert_include 'lock_version', issue.safe_attribute_names |
|
521 | assert_include 'lock_version', issue.safe_attribute_names | |
522 |
|
522 | |||
523 | tracker.core_fields.each do |field| |
|
523 | tracker.core_fields.each do |field| | |
524 | assert_include field, issue.safe_attribute_names |
|
524 | assert_include field, issue.safe_attribute_names | |
525 | end |
|
525 | end | |
526 |
|
526 | |||
527 | tracker.disabled_core_fields.each do |field| |
|
527 | tracker.disabled_core_fields.each do |field| | |
528 | assert_not_include field, issue.safe_attribute_names |
|
528 | assert_not_include field, issue.safe_attribute_names | |
529 | end |
|
529 | end | |
530 | end |
|
530 | end | |
531 |
|
531 | |||
532 | def test_safe_attributes_should_ignore_disabled_fields |
|
532 | def test_safe_attributes_should_ignore_disabled_fields | |
533 | tracker = Tracker.find(1) |
|
533 | tracker = Tracker.find(1) | |
534 | tracker.core_fields = %w(assigned_to_id due_date) |
|
534 | tracker.core_fields = %w(assigned_to_id due_date) | |
535 | tracker.save! |
|
535 | tracker.save! | |
536 |
|
536 | |||
537 | issue = Issue.new(:tracker => tracker) |
|
537 | issue = Issue.new(:tracker => tracker) | |
538 | issue.safe_attributes = {'start_date' => '2012-07-14', 'due_date' => '2012-07-14'} |
|
538 | issue.safe_attributes = {'start_date' => '2012-07-14', 'due_date' => '2012-07-14'} | |
539 | assert_nil issue.start_date |
|
539 | assert_nil issue.start_date | |
540 | assert_equal Date.parse('2012-07-14'), issue.due_date |
|
540 | assert_equal Date.parse('2012-07-14'), issue.due_date | |
541 | end |
|
541 | end | |
542 |
|
542 | |||
543 | def test_safe_attributes_should_accept_target_tracker_enabled_fields |
|
543 | def test_safe_attributes_should_accept_target_tracker_enabled_fields | |
544 | source = Tracker.find(1) |
|
544 | source = Tracker.find(1) | |
545 | source.core_fields = [] |
|
545 | source.core_fields = [] | |
546 | source.save! |
|
546 | source.save! | |
547 | target = Tracker.find(2) |
|
547 | target = Tracker.find(2) | |
548 | target.core_fields = %w(assigned_to_id due_date) |
|
548 | target.core_fields = %w(assigned_to_id due_date) | |
549 | target.save! |
|
549 | target.save! | |
550 |
|
550 | |||
551 | issue = Issue.new(:tracker => source) |
|
551 | issue = Issue.new(:tracker => source) | |
552 | issue.safe_attributes = {'tracker_id' => 2, 'due_date' => '2012-07-14'} |
|
552 | issue.safe_attributes = {'tracker_id' => 2, 'due_date' => '2012-07-14'} | |
553 | assert_equal target, issue.tracker |
|
553 | assert_equal target, issue.tracker | |
554 | assert_equal Date.parse('2012-07-14'), issue.due_date |
|
554 | assert_equal Date.parse('2012-07-14'), issue.due_date | |
555 | end |
|
555 | end | |
556 |
|
556 | |||
557 | def test_safe_attributes_should_not_include_readonly_fields |
|
557 | def test_safe_attributes_should_not_include_readonly_fields | |
558 | WorkflowPermission.delete_all |
|
558 | WorkflowPermission.delete_all | |
559 | WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, |
|
559 | WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, | |
560 | :role_id => 1, :field_name => 'due_date', |
|
560 | :role_id => 1, :field_name => 'due_date', | |
561 | :rule => 'readonly') |
|
561 | :rule => 'readonly') | |
562 | user = User.find(2) |
|
562 | user = User.find(2) | |
563 |
|
563 | |||
564 | issue = Issue.new(:project_id => 1, :tracker_id => 1) |
|
564 | issue = Issue.new(:project_id => 1, :tracker_id => 1) | |
565 | assert_equal %w(due_date), issue.read_only_attribute_names(user) |
|
565 | assert_equal %w(due_date), issue.read_only_attribute_names(user) | |
566 | assert_not_include 'due_date', issue.safe_attribute_names(user) |
|
566 | assert_not_include 'due_date', issue.safe_attribute_names(user) | |
567 |
|
567 | |||
568 | issue.send :safe_attributes=, {'start_date' => '2012-07-14', 'due_date' => '2012-07-14'}, user |
|
568 | issue.send :safe_attributes=, {'start_date' => '2012-07-14', 'due_date' => '2012-07-14'}, user | |
569 | assert_equal Date.parse('2012-07-14'), issue.start_date |
|
569 | assert_equal Date.parse('2012-07-14'), issue.start_date | |
570 | assert_nil issue.due_date |
|
570 | assert_nil issue.due_date | |
571 | end |
|
571 | end | |
572 |
|
572 | |||
573 | def test_safe_attributes_should_not_include_readonly_custom_fields |
|
573 | def test_safe_attributes_should_not_include_readonly_custom_fields | |
574 | cf1 = IssueCustomField.create!(:name => 'Writable field', |
|
574 | cf1 = IssueCustomField.create!(:name => 'Writable field', | |
575 | :field_format => 'string', |
|
575 | :field_format => 'string', | |
576 | :is_for_all => true, :tracker_ids => [1]) |
|
576 | :is_for_all => true, :tracker_ids => [1]) | |
577 | cf2 = IssueCustomField.create!(:name => 'Readonly field', |
|
577 | cf2 = IssueCustomField.create!(:name => 'Readonly field', | |
578 | :field_format => 'string', |
|
578 | :field_format => 'string', | |
579 | :is_for_all => true, :tracker_ids => [1]) |
|
579 | :is_for_all => true, :tracker_ids => [1]) | |
580 | WorkflowPermission.delete_all |
|
580 | WorkflowPermission.delete_all | |
581 | WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, |
|
581 | WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, | |
582 | :role_id => 1, :field_name => cf2.id.to_s, |
|
582 | :role_id => 1, :field_name => cf2.id.to_s, | |
583 | :rule => 'readonly') |
|
583 | :rule => 'readonly') | |
584 | user = User.find(2) |
|
584 | user = User.find(2) | |
585 | issue = Issue.new(:project_id => 1, :tracker_id => 1) |
|
585 | issue = Issue.new(:project_id => 1, :tracker_id => 1) | |
586 | assert_equal [cf2.id.to_s], issue.read_only_attribute_names(user) |
|
586 | assert_equal [cf2.id.to_s], issue.read_only_attribute_names(user) | |
587 | assert_not_include cf2.id.to_s, issue.safe_attribute_names(user) |
|
587 | assert_not_include cf2.id.to_s, issue.safe_attribute_names(user) | |
588 |
|
588 | |||
589 | issue.send :safe_attributes=, {'custom_field_values' => { |
|
589 | issue.send :safe_attributes=, {'custom_field_values' => { | |
590 | cf1.id.to_s => 'value1', cf2.id.to_s => 'value2' |
|
590 | cf1.id.to_s => 'value1', cf2.id.to_s => 'value2' | |
591 | }}, user |
|
591 | }}, user | |
592 | assert_equal 'value1', issue.custom_field_value(cf1) |
|
592 | assert_equal 'value1', issue.custom_field_value(cf1) | |
593 | assert_nil issue.custom_field_value(cf2) |
|
593 | assert_nil issue.custom_field_value(cf2) | |
594 |
|
594 | |||
595 | issue.send :safe_attributes=, {'custom_fields' => [ |
|
595 | issue.send :safe_attributes=, {'custom_fields' => [ | |
596 | {'id' => cf1.id.to_s, 'value' => 'valuea'}, |
|
596 | {'id' => cf1.id.to_s, 'value' => 'valuea'}, | |
597 | {'id' => cf2.id.to_s, 'value' => 'valueb'} |
|
597 | {'id' => cf2.id.to_s, 'value' => 'valueb'} | |
598 | ]}, user |
|
598 | ]}, user | |
599 | assert_equal 'valuea', issue.custom_field_value(cf1) |
|
599 | assert_equal 'valuea', issue.custom_field_value(cf1) | |
600 | assert_nil issue.custom_field_value(cf2) |
|
600 | assert_nil issue.custom_field_value(cf2) | |
601 | end |
|
601 | end | |
602 |
|
602 | |||
603 | def test_editable_custom_field_values_should_return_non_readonly_custom_values |
|
603 | def test_editable_custom_field_values_should_return_non_readonly_custom_values | |
604 | cf1 = IssueCustomField.create!(:name => 'Writable field', :field_format => 'string', |
|
604 | cf1 = IssueCustomField.create!(:name => 'Writable field', :field_format => 'string', | |
605 | :is_for_all => true, :tracker_ids => [1, 2]) |
|
605 | :is_for_all => true, :tracker_ids => [1, 2]) | |
606 | cf2 = IssueCustomField.create!(:name => 'Readonly field', :field_format => 'string', |
|
606 | cf2 = IssueCustomField.create!(:name => 'Readonly field', :field_format => 'string', | |
607 | :is_for_all => true, :tracker_ids => [1, 2]) |
|
607 | :is_for_all => true, :tracker_ids => [1, 2]) | |
608 | WorkflowPermission.delete_all |
|
608 | WorkflowPermission.delete_all | |
609 | WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, :role_id => 1, |
|
609 | WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, :role_id => 1, | |
610 | :field_name => cf2.id.to_s, :rule => 'readonly') |
|
610 | :field_name => cf2.id.to_s, :rule => 'readonly') | |
611 | user = User.find(2) |
|
611 | user = User.find(2) | |
612 |
|
612 | |||
613 | issue = Issue.new(:project_id => 1, :tracker_id => 1) |
|
613 | issue = Issue.new(:project_id => 1, :tracker_id => 1) | |
614 | values = issue.editable_custom_field_values(user) |
|
614 | values = issue.editable_custom_field_values(user) | |
615 | assert values.detect {|value| value.custom_field == cf1} |
|
615 | assert values.detect {|value| value.custom_field == cf1} | |
616 | assert_nil values.detect {|value| value.custom_field == cf2} |
|
616 | assert_nil values.detect {|value| value.custom_field == cf2} | |
617 |
|
617 | |||
618 | issue.tracker_id = 2 |
|
618 | issue.tracker_id = 2 | |
619 | values = issue.editable_custom_field_values(user) |
|
619 | values = issue.editable_custom_field_values(user) | |
620 | assert values.detect {|value| value.custom_field == cf1} |
|
620 | assert values.detect {|value| value.custom_field == cf1} | |
621 | assert values.detect {|value| value.custom_field == cf2} |
|
621 | assert values.detect {|value| value.custom_field == cf2} | |
622 | end |
|
622 | end | |
623 |
|
623 | |||
624 | def test_safe_attributes_should_accept_target_tracker_writable_fields |
|
624 | def test_safe_attributes_should_accept_target_tracker_writable_fields | |
625 | WorkflowPermission.delete_all |
|
625 | WorkflowPermission.delete_all | |
626 | WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, |
|
626 | WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, | |
627 | :role_id => 1, :field_name => 'due_date', |
|
627 | :role_id => 1, :field_name => 'due_date', | |
628 | :rule => 'readonly') |
|
628 | :rule => 'readonly') | |
629 | WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2, |
|
629 | WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2, | |
630 | :role_id => 1, :field_name => 'start_date', |
|
630 | :role_id => 1, :field_name => 'start_date', | |
631 | :rule => 'readonly') |
|
631 | :rule => 'readonly') | |
632 | user = User.find(2) |
|
632 | user = User.find(2) | |
633 |
|
633 | |||
634 | issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1) |
|
634 | issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1) | |
635 |
|
635 | |||
636 | issue.send :safe_attributes=, {'start_date' => '2012-07-12', |
|
636 | issue.send :safe_attributes=, {'start_date' => '2012-07-12', | |
637 | 'due_date' => '2012-07-14'}, user |
|
637 | 'due_date' => '2012-07-14'}, user | |
638 | assert_equal Date.parse('2012-07-12'), issue.start_date |
|
638 | assert_equal Date.parse('2012-07-12'), issue.start_date | |
639 | assert_nil issue.due_date |
|
639 | assert_nil issue.due_date | |
640 |
|
640 | |||
641 | issue.send :safe_attributes=, {'start_date' => '2012-07-15', |
|
641 | issue.send :safe_attributes=, {'start_date' => '2012-07-15', | |
642 | 'due_date' => '2012-07-16', |
|
642 | 'due_date' => '2012-07-16', | |
643 | 'tracker_id' => 2}, user |
|
643 | 'tracker_id' => 2}, user | |
644 | assert_equal Date.parse('2012-07-12'), issue.start_date |
|
644 | assert_equal Date.parse('2012-07-12'), issue.start_date | |
645 | assert_equal Date.parse('2012-07-16'), issue.due_date |
|
645 | assert_equal Date.parse('2012-07-16'), issue.due_date | |
646 | end |
|
646 | end | |
647 |
|
647 | |||
648 | def test_safe_attributes_should_accept_target_status_writable_fields |
|
648 | def test_safe_attributes_should_accept_target_status_writable_fields | |
649 | WorkflowPermission.delete_all |
|
649 | WorkflowPermission.delete_all | |
650 | WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, |
|
650 | WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, | |
651 | :role_id => 1, :field_name => 'due_date', |
|
651 | :role_id => 1, :field_name => 'due_date', | |
652 | :rule => 'readonly') |
|
652 | :rule => 'readonly') | |
653 | WorkflowPermission.create!(:old_status_id => 2, :tracker_id => 1, |
|
653 | WorkflowPermission.create!(:old_status_id => 2, :tracker_id => 1, | |
654 | :role_id => 1, :field_name => 'start_date', |
|
654 | :role_id => 1, :field_name => 'start_date', | |
655 | :rule => 'readonly') |
|
655 | :rule => 'readonly') | |
656 | user = User.find(2) |
|
656 | user = User.find(2) | |
657 |
|
657 | |||
658 | issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1) |
|
658 | issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1) | |
659 |
|
659 | |||
660 | issue.send :safe_attributes=, {'start_date' => '2012-07-12', |
|
660 | issue.send :safe_attributes=, {'start_date' => '2012-07-12', | |
661 | 'due_date' => '2012-07-14'}, |
|
661 | 'due_date' => '2012-07-14'}, | |
662 | user |
|
662 | user | |
663 | assert_equal Date.parse('2012-07-12'), issue.start_date |
|
663 | assert_equal Date.parse('2012-07-12'), issue.start_date | |
664 | assert_nil issue.due_date |
|
664 | assert_nil issue.due_date | |
665 |
|
665 | |||
666 | issue.send :safe_attributes=, {'start_date' => '2012-07-15', |
|
666 | issue.send :safe_attributes=, {'start_date' => '2012-07-15', | |
667 | 'due_date' => '2012-07-16', |
|
667 | 'due_date' => '2012-07-16', | |
668 | 'status_id' => 2}, |
|
668 | 'status_id' => 2}, | |
669 | user |
|
669 | user | |
670 | assert_equal Date.parse('2012-07-12'), issue.start_date |
|
670 | assert_equal Date.parse('2012-07-12'), issue.start_date | |
671 | assert_equal Date.parse('2012-07-16'), issue.due_date |
|
671 | assert_equal Date.parse('2012-07-16'), issue.due_date | |
672 | end |
|
672 | end | |
673 |
|
673 | |||
674 | def test_required_attributes_should_be_validated |
|
674 | def test_required_attributes_should_be_validated | |
675 | cf = IssueCustomField.create!(:name => 'Foo', :field_format => 'string', |
|
675 | cf = IssueCustomField.create!(:name => 'Foo', :field_format => 'string', | |
676 | :is_for_all => true, :tracker_ids => [1, 2]) |
|
676 | :is_for_all => true, :tracker_ids => [1, 2]) | |
677 |
|
677 | |||
678 | WorkflowPermission.delete_all |
|
678 | WorkflowPermission.delete_all | |
679 | WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, |
|
679 | WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, | |
680 | :role_id => 1, :field_name => 'due_date', |
|
680 | :role_id => 1, :field_name => 'due_date', | |
681 | :rule => 'required') |
|
681 | :rule => 'required') | |
682 | WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, |
|
682 | WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, | |
683 | :role_id => 1, :field_name => 'category_id', |
|
683 | :role_id => 1, :field_name => 'category_id', | |
684 | :rule => 'required') |
|
684 | :rule => 'required') | |
685 | WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, |
|
685 | WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, | |
686 | :role_id => 1, :field_name => cf.id.to_s, |
|
686 | :role_id => 1, :field_name => cf.id.to_s, | |
687 | :rule => 'required') |
|
687 | :rule => 'required') | |
688 |
|
688 | |||
689 | WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2, |
|
689 | WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2, | |
690 | :role_id => 1, :field_name => 'start_date', |
|
690 | :role_id => 1, :field_name => 'start_date', | |
691 | :rule => 'required') |
|
691 | :rule => 'required') | |
692 | WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2, |
|
692 | WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2, | |
693 | :role_id => 1, :field_name => cf.id.to_s, |
|
693 | :role_id => 1, :field_name => cf.id.to_s, | |
694 | :rule => 'required') |
|
694 | :rule => 'required') | |
695 | user = User.find(2) |
|
695 | user = User.find(2) | |
696 |
|
696 | |||
697 | issue = Issue.new(:project_id => 1, :tracker_id => 1, |
|
697 | issue = Issue.new(:project_id => 1, :tracker_id => 1, | |
698 | :status_id => 1, :subject => 'Required fields', |
|
698 | :status_id => 1, :subject => 'Required fields', | |
699 | :author => user) |
|
699 | :author => user) | |
700 | assert_equal [cf.id.to_s, "category_id", "due_date"], |
|
700 | assert_equal [cf.id.to_s, "category_id", "due_date"], | |
701 | issue.required_attribute_names(user).sort |
|
701 | issue.required_attribute_names(user).sort | |
702 | assert !issue.save, "Issue was saved" |
|
702 | assert !issue.save, "Issue was saved" | |
703 | assert_equal ["Category can't be blank", "Due date can't be blank", "Foo can't be blank"], |
|
703 | assert_equal ["Category can't be blank", "Due date can't be blank", "Foo can't be blank"], | |
704 | issue.errors.full_messages.sort |
|
704 | issue.errors.full_messages.sort | |
705 |
|
705 | |||
706 | issue.tracker_id = 2 |
|
706 | issue.tracker_id = 2 | |
707 | assert_equal [cf.id.to_s, "start_date"], issue.required_attribute_names(user).sort |
|
707 | assert_equal [cf.id.to_s, "start_date"], issue.required_attribute_names(user).sort | |
708 | assert !issue.save, "Issue was saved" |
|
708 | assert !issue.save, "Issue was saved" | |
709 | assert_equal ["Foo can't be blank", "Start date can't be blank"], |
|
709 | assert_equal ["Foo can't be blank", "Start date can't be blank"], | |
710 | issue.errors.full_messages.sort |
|
710 | issue.errors.full_messages.sort | |
711 |
|
711 | |||
712 | issue.start_date = Date.today |
|
712 | issue.start_date = Date.today | |
713 | issue.custom_field_values = {cf.id.to_s => 'bar'} |
|
713 | issue.custom_field_values = {cf.id.to_s => 'bar'} | |
714 | assert issue.save |
|
714 | assert issue.save | |
715 | end |
|
715 | end | |
716 |
|
716 | |||
717 | def test_required_attribute_names_for_multiple_roles_should_intersect_rules |
|
717 | def test_required_attribute_names_for_multiple_roles_should_intersect_rules | |
718 | WorkflowPermission.delete_all |
|
718 | WorkflowPermission.delete_all | |
719 | WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, |
|
719 | WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, | |
720 | :role_id => 1, :field_name => 'due_date', |
|
720 | :role_id => 1, :field_name => 'due_date', | |
721 | :rule => 'required') |
|
721 | :rule => 'required') | |
722 | WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, |
|
722 | WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, | |
723 | :role_id => 1, :field_name => 'start_date', |
|
723 | :role_id => 1, :field_name => 'start_date', | |
724 | :rule => 'required') |
|
724 | :rule => 'required') | |
725 | user = User.find(2) |
|
725 | user = User.find(2) | |
726 | member = Member.find(1) |
|
726 | member = Member.find(1) | |
727 | issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1) |
|
727 | issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1) | |
728 |
|
728 | |||
729 | assert_equal %w(due_date start_date), issue.required_attribute_names(user).sort |
|
729 | assert_equal %w(due_date start_date), issue.required_attribute_names(user).sort | |
730 |
|
730 | |||
731 | member.role_ids = [1, 2] |
|
731 | member.role_ids = [1, 2] | |
732 | member.save! |
|
732 | member.save! | |
733 | assert_equal [], issue.required_attribute_names(user.reload) |
|
733 | assert_equal [], issue.required_attribute_names(user.reload) | |
734 |
|
734 | |||
735 | WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, |
|
735 | WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, | |
736 | :role_id => 2, :field_name => 'due_date', |
|
736 | :role_id => 2, :field_name => 'due_date', | |
737 | :rule => 'required') |
|
737 | :rule => 'required') | |
738 | assert_equal %w(due_date), issue.required_attribute_names(user) |
|
738 | assert_equal %w(due_date), issue.required_attribute_names(user) | |
739 |
|
739 | |||
740 | member.role_ids = [1, 2, 3] |
|
740 | member.role_ids = [1, 2, 3] | |
741 | member.save! |
|
741 | member.save! | |
742 | assert_equal [], issue.required_attribute_names(user.reload) |
|
742 | assert_equal [], issue.required_attribute_names(user.reload) | |
743 |
|
743 | |||
744 | WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, |
|
744 | WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, | |
745 | :role_id => 2, :field_name => 'due_date', |
|
745 | :role_id => 2, :field_name => 'due_date', | |
746 | :rule => 'readonly') |
|
746 | :rule => 'readonly') | |
747 | # required + readonly => required |
|
747 | # required + readonly => required | |
748 | assert_equal %w(due_date), issue.required_attribute_names(user) |
|
748 | assert_equal %w(due_date), issue.required_attribute_names(user) | |
749 | end |
|
749 | end | |
750 |
|
750 | |||
751 | def test_read_only_attribute_names_for_multiple_roles_should_intersect_rules |
|
751 | def test_read_only_attribute_names_for_multiple_roles_should_intersect_rules | |
752 | WorkflowPermission.delete_all |
|
752 | WorkflowPermission.delete_all | |
753 | WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, |
|
753 | WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, | |
754 | :role_id => 1, :field_name => 'due_date', |
|
754 | :role_id => 1, :field_name => 'due_date', | |
755 | :rule => 'readonly') |
|
755 | :rule => 'readonly') | |
756 | WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, |
|
756 | WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, | |
757 | :role_id => 1, :field_name => 'start_date', |
|
757 | :role_id => 1, :field_name => 'start_date', | |
758 | :rule => 'readonly') |
|
758 | :rule => 'readonly') | |
759 | user = User.find(2) |
|
759 | user = User.find(2) | |
760 | member = Member.find(1) |
|
760 | member = Member.find(1) | |
761 | issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1) |
|
761 | issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1) | |
762 |
|
762 | |||
763 | assert_equal %w(due_date start_date), issue.read_only_attribute_names(user).sort |
|
763 | assert_equal %w(due_date start_date), issue.read_only_attribute_names(user).sort | |
764 |
|
764 | |||
765 | member.role_ids = [1, 2] |
|
765 | member.role_ids = [1, 2] | |
766 | member.save! |
|
766 | member.save! | |
767 | assert_equal [], issue.read_only_attribute_names(user.reload) |
|
767 | assert_equal [], issue.read_only_attribute_names(user.reload) | |
768 |
|
768 | |||
769 | WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, |
|
769 | WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, | |
770 | :role_id => 2, :field_name => 'due_date', |
|
770 | :role_id => 2, :field_name => 'due_date', | |
771 | :rule => 'readonly') |
|
771 | :rule => 'readonly') | |
772 | assert_equal %w(due_date), issue.read_only_attribute_names(user) |
|
772 | assert_equal %w(due_date), issue.read_only_attribute_names(user) | |
773 | end |
|
773 | end | |
774 |
|
774 | |||
775 | def test_copy |
|
775 | def test_copy | |
776 | issue = Issue.new.copy_from(1) |
|
776 | issue = Issue.new.copy_from(1) | |
777 | assert issue.copy? |
|
777 | assert issue.copy? | |
778 | assert issue.save |
|
778 | assert issue.save | |
779 | issue.reload |
|
779 | issue.reload | |
780 | orig = Issue.find(1) |
|
780 | orig = Issue.find(1) | |
781 | assert_equal orig.subject, issue.subject |
|
781 | assert_equal orig.subject, issue.subject | |
782 | assert_equal orig.tracker, issue.tracker |
|
782 | assert_equal orig.tracker, issue.tracker | |
783 | assert_equal "125", issue.custom_value_for(2).value |
|
783 | assert_equal "125", issue.custom_value_for(2).value | |
784 | end |
|
784 | end | |
785 |
|
785 | |||
786 | def test_copy_should_copy_status |
|
786 | def test_copy_should_copy_status | |
787 | orig = Issue.find(8) |
|
787 | orig = Issue.find(8) | |
788 | assert orig.status != IssueStatus.default |
|
788 | assert orig.status != IssueStatus.default | |
789 |
|
789 | |||
790 | issue = Issue.new.copy_from(orig) |
|
790 | issue = Issue.new.copy_from(orig) | |
791 | assert issue.save |
|
791 | assert issue.save | |
792 | issue.reload |
|
792 | issue.reload | |
793 | assert_equal orig.status, issue.status |
|
793 | assert_equal orig.status, issue.status | |
794 | end |
|
794 | end | |
795 |
|
795 | |||
796 | def test_copy_should_add_relation_with_copied_issue |
|
796 | def test_copy_should_add_relation_with_copied_issue | |
797 | copied = Issue.find(1) |
|
797 | copied = Issue.find(1) | |
798 | issue = Issue.new.copy_from(copied) |
|
798 | issue = Issue.new.copy_from(copied) | |
799 | assert issue.save |
|
799 | assert issue.save | |
800 | issue.reload |
|
800 | issue.reload | |
801 |
|
801 | |||
802 | assert_equal 1, issue.relations.size |
|
802 | assert_equal 1, issue.relations.size | |
803 | relation = issue.relations.first |
|
803 | relation = issue.relations.first | |
804 | assert_equal 'copied_to', relation.relation_type |
|
804 | assert_equal 'copied_to', relation.relation_type | |
805 | assert_equal copied, relation.issue_from |
|
805 | assert_equal copied, relation.issue_from | |
806 | assert_equal issue, relation.issue_to |
|
806 | assert_equal issue, relation.issue_to | |
807 | end |
|
807 | end | |
808 |
|
808 | |||
809 | def test_copy_should_copy_subtasks |
|
809 | def test_copy_should_copy_subtasks | |
810 | issue = Issue.generate_with_descendants! |
|
810 | issue = Issue.generate_with_descendants! | |
811 |
|
811 | |||
812 | copy = issue.reload.copy |
|
812 | copy = issue.reload.copy | |
813 | copy.author = User.find(7) |
|
813 | copy.author = User.find(7) | |
814 | assert_difference 'Issue.count', 1+issue.descendants.count do |
|
814 | assert_difference 'Issue.count', 1+issue.descendants.count do | |
815 | assert copy.save |
|
815 | assert copy.save | |
816 | end |
|
816 | end | |
817 | copy.reload |
|
817 | copy.reload | |
818 | assert_equal %w(Child1 Child2), copy.children.map(&:subject).sort |
|
818 | assert_equal %w(Child1 Child2), copy.children.map(&:subject).sort | |
819 | child_copy = copy.children.detect {|c| c.subject == 'Child1'} |
|
819 | child_copy = copy.children.detect {|c| c.subject == 'Child1'} | |
820 | assert_equal %w(Child11), child_copy.children.map(&:subject).sort |
|
820 | assert_equal %w(Child11), child_copy.children.map(&:subject).sort | |
821 | assert_equal copy.author, child_copy.author |
|
821 | assert_equal copy.author, child_copy.author | |
822 | end |
|
822 | end | |
823 |
|
823 | |||
824 | def test_copy_should_copy_subtasks_to_target_project |
|
824 | def test_copy_should_copy_subtasks_to_target_project | |
825 | issue = Issue.generate_with_descendants! |
|
825 | issue = Issue.generate_with_descendants! | |
826 |
|
826 | |||
827 | copy = issue.copy(:project_id => 3) |
|
827 | copy = issue.copy(:project_id => 3) | |
828 | assert_difference 'Issue.count', 1+issue.descendants.count do |
|
828 | assert_difference 'Issue.count', 1+issue.descendants.count do | |
829 | assert copy.save |
|
829 | assert copy.save | |
830 | end |
|
830 | end | |
831 | assert_equal [3], copy.reload.descendants.map(&:project_id).uniq |
|
831 | assert_equal [3], copy.reload.descendants.map(&:project_id).uniq | |
832 | end |
|
832 | end | |
833 |
|
833 | |||
834 | def test_copy_should_not_copy_subtasks_twice_when_saving_twice |
|
834 | def test_copy_should_not_copy_subtasks_twice_when_saving_twice | |
835 | issue = Issue.generate_with_descendants! |
|
835 | issue = Issue.generate_with_descendants! | |
836 |
|
836 | |||
837 | copy = issue.reload.copy |
|
837 | copy = issue.reload.copy | |
838 | assert_difference 'Issue.count', 1+issue.descendants.count do |
|
838 | assert_difference 'Issue.count', 1+issue.descendants.count do | |
839 | assert copy.save |
|
839 | assert copy.save | |
840 | assert copy.save |
|
840 | assert copy.save | |
841 | end |
|
841 | end | |
842 | end |
|
842 | end | |
843 |
|
843 | |||
844 | def test_should_not_call_after_project_change_on_creation |
|
844 | def test_should_not_call_after_project_change_on_creation | |
845 | issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1, |
|
845 | issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1, | |
846 | :subject => 'Test', :author_id => 1) |
|
846 | :subject => 'Test', :author_id => 1) | |
847 | issue.expects(:after_project_change).never |
|
847 | issue.expects(:after_project_change).never | |
848 | issue.save! |
|
848 | issue.save! | |
849 | end |
|
849 | end | |
850 |
|
850 | |||
851 | def test_should_not_call_after_project_change_on_update |
|
851 | def test_should_not_call_after_project_change_on_update | |
852 | issue = Issue.find(1) |
|
852 | issue = Issue.find(1) | |
853 | issue.project = Project.find(1) |
|
853 | issue.project = Project.find(1) | |
854 | issue.subject = 'No project change' |
|
854 | issue.subject = 'No project change' | |
855 | issue.expects(:after_project_change).never |
|
855 | issue.expects(:after_project_change).never | |
856 | issue.save! |
|
856 | issue.save! | |
857 | end |
|
857 | end | |
858 |
|
858 | |||
859 | def test_should_call_after_project_change_on_project_change |
|
859 | def test_should_call_after_project_change_on_project_change | |
860 | issue = Issue.find(1) |
|
860 | issue = Issue.find(1) | |
861 | issue.project = Project.find(2) |
|
861 | issue.project = Project.find(2) | |
862 | issue.expects(:after_project_change).once |
|
862 | issue.expects(:after_project_change).once | |
863 | issue.save! |
|
863 | issue.save! | |
864 | end |
|
864 | end | |
865 |
|
865 | |||
866 | def test_adding_journal_should_update_timestamp |
|
866 | def test_adding_journal_should_update_timestamp | |
867 | issue = Issue.find(1) |
|
867 | issue = Issue.find(1) | |
868 | updated_on_was = issue.updated_on |
|
868 | updated_on_was = issue.updated_on | |
869 |
|
869 | |||
870 | issue.init_journal(User.first, "Adding notes") |
|
870 | issue.init_journal(User.first, "Adding notes") | |
871 | assert_difference 'Journal.count' do |
|
871 | assert_difference 'Journal.count' do | |
872 | assert issue.save |
|
872 | assert issue.save | |
873 | end |
|
873 | end | |
874 | issue.reload |
|
874 | issue.reload | |
875 |
|
875 | |||
876 | assert_not_equal updated_on_was, issue.updated_on |
|
876 | assert_not_equal updated_on_was, issue.updated_on | |
877 | end |
|
877 | end | |
878 |
|
878 | |||
879 | def test_should_close_duplicates |
|
879 | def test_should_close_duplicates | |
880 | # Create 3 issues |
|
880 | # Create 3 issues | |
881 | issue1 = Issue.generate! |
|
881 | issue1 = Issue.generate! | |
882 | issue2 = Issue.generate! |
|
882 | issue2 = Issue.generate! | |
883 | issue3 = Issue.generate! |
|
883 | issue3 = Issue.generate! | |
884 |
|
884 | |||
885 | # 2 is a dupe of 1 |
|
885 | # 2 is a dupe of 1 | |
886 | IssueRelation.create!(:issue_from => issue2, :issue_to => issue1, |
|
886 | IssueRelation.create!(:issue_from => issue2, :issue_to => issue1, | |
887 | :relation_type => IssueRelation::TYPE_DUPLICATES) |
|
887 | :relation_type => IssueRelation::TYPE_DUPLICATES) | |
888 | # And 3 is a dupe of 2 |
|
888 | # And 3 is a dupe of 2 | |
889 | IssueRelation.create!(:issue_from => issue3, :issue_to => issue2, |
|
889 | IssueRelation.create!(:issue_from => issue3, :issue_to => issue2, | |
890 | :relation_type => IssueRelation::TYPE_DUPLICATES) |
|
890 | :relation_type => IssueRelation::TYPE_DUPLICATES) | |
891 | # And 3 is a dupe of 1 (circular duplicates) |
|
891 | # And 3 is a dupe of 1 (circular duplicates) | |
892 | IssueRelation.create!(:issue_from => issue3, :issue_to => issue1, |
|
892 | IssueRelation.create!(:issue_from => issue3, :issue_to => issue1, | |
893 | :relation_type => IssueRelation::TYPE_DUPLICATES) |
|
893 | :relation_type => IssueRelation::TYPE_DUPLICATES) | |
894 |
|
894 | |||
895 | assert issue1.reload.duplicates.include?(issue2) |
|
895 | assert issue1.reload.duplicates.include?(issue2) | |
896 |
|
896 | |||
897 | # Closing issue 1 |
|
897 | # Closing issue 1 | |
898 | issue1.init_journal(User.first, "Closing issue1") |
|
898 | issue1.init_journal(User.first, "Closing issue1") | |
899 | issue1.status = IssueStatus.where(:is_closed => true).first |
|
899 | issue1.status = IssueStatus.where(:is_closed => true).first | |
900 | assert issue1.save |
|
900 | assert issue1.save | |
901 | # 2 and 3 should be also closed |
|
901 | # 2 and 3 should be also closed | |
902 | assert issue2.reload.closed? |
|
902 | assert issue2.reload.closed? | |
903 | assert issue3.reload.closed? |
|
903 | assert issue3.reload.closed? | |
904 | end |
|
904 | end | |
905 |
|
905 | |||
906 | def test_should_not_close_duplicated_issue |
|
906 | def test_should_not_close_duplicated_issue | |
907 | issue1 = Issue.generate! |
|
907 | issue1 = Issue.generate! | |
908 | issue2 = Issue.generate! |
|
908 | issue2 = Issue.generate! | |
909 |
|
909 | |||
910 | # 2 is a dupe of 1 |
|
910 | # 2 is a dupe of 1 | |
911 | IssueRelation.create(:issue_from => issue2, :issue_to => issue1, |
|
911 | IssueRelation.create(:issue_from => issue2, :issue_to => issue1, | |
912 | :relation_type => IssueRelation::TYPE_DUPLICATES) |
|
912 | :relation_type => IssueRelation::TYPE_DUPLICATES) | |
913 | # 2 is a dup of 1 but 1 is not a duplicate of 2 |
|
913 | # 2 is a dup of 1 but 1 is not a duplicate of 2 | |
914 | assert !issue2.reload.duplicates.include?(issue1) |
|
914 | assert !issue2.reload.duplicates.include?(issue1) | |
915 |
|
915 | |||
916 | # Closing issue 2 |
|
916 | # Closing issue 2 | |
917 | issue2.init_journal(User.first, "Closing issue2") |
|
917 | issue2.init_journal(User.first, "Closing issue2") | |
918 | issue2.status = IssueStatus.where(:is_closed => true).first |
|
918 | issue2.status = IssueStatus.where(:is_closed => true).first | |
919 | assert issue2.save |
|
919 | assert issue2.save | |
920 | # 1 should not be also closed |
|
920 | # 1 should not be also closed | |
921 | assert !issue1.reload.closed? |
|
921 | assert !issue1.reload.closed? | |
922 | end |
|
922 | end | |
923 |
|
923 | |||
924 | def test_assignable_versions |
|
924 | def test_assignable_versions | |
925 | issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, |
|
925 | issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, | |
926 | :status_id => 1, :fixed_version_id => 1, |
|
926 | :status_id => 1, :fixed_version_id => 1, | |
927 | :subject => 'New issue') |
|
927 | :subject => 'New issue') | |
928 | assert_equal ['open'], issue.assignable_versions.collect(&:status).uniq |
|
928 | assert_equal ['open'], issue.assignable_versions.collect(&:status).uniq | |
929 | end |
|
929 | end | |
930 |
|
930 | |||
931 | def test_should_not_be_able_to_assign_a_new_issue_to_a_closed_version |
|
931 | def test_should_not_be_able_to_assign_a_new_issue_to_a_closed_version | |
932 | issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, |
|
932 | issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, | |
933 | :status_id => 1, :fixed_version_id => 1, |
|
933 | :status_id => 1, :fixed_version_id => 1, | |
934 | :subject => 'New issue') |
|
934 | :subject => 'New issue') | |
935 | assert !issue.save |
|
935 | assert !issue.save | |
936 | assert_not_nil issue.errors[:fixed_version_id] |
|
936 | assert_not_nil issue.errors[:fixed_version_id] | |
937 | end |
|
937 | end | |
938 |
|
938 | |||
939 | def test_should_not_be_able_to_assign_a_new_issue_to_a_locked_version |
|
939 | def test_should_not_be_able_to_assign_a_new_issue_to_a_locked_version | |
940 | issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, |
|
940 | issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, | |
941 | :status_id => 1, :fixed_version_id => 2, |
|
941 | :status_id => 1, :fixed_version_id => 2, | |
942 | :subject => 'New issue') |
|
942 | :subject => 'New issue') | |
943 | assert !issue.save |
|
943 | assert !issue.save | |
944 | assert_not_nil issue.errors[:fixed_version_id] |
|
944 | assert_not_nil issue.errors[:fixed_version_id] | |
945 | end |
|
945 | end | |
946 |
|
946 | |||
947 | def test_should_be_able_to_assign_a_new_issue_to_an_open_version |
|
947 | def test_should_be_able_to_assign_a_new_issue_to_an_open_version | |
948 | issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, |
|
948 | issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, | |
949 | :status_id => 1, :fixed_version_id => 3, |
|
949 | :status_id => 1, :fixed_version_id => 3, | |
950 | :subject => 'New issue') |
|
950 | :subject => 'New issue') | |
951 | assert issue.save |
|
951 | assert issue.save | |
952 | end |
|
952 | end | |
953 |
|
953 | |||
954 | def test_should_be_able_to_update_an_issue_assigned_to_a_closed_version |
|
954 | def test_should_be_able_to_update_an_issue_assigned_to_a_closed_version | |
955 | issue = Issue.find(11) |
|
955 | issue = Issue.find(11) | |
956 | assert_equal 'closed', issue.fixed_version.status |
|
956 | assert_equal 'closed', issue.fixed_version.status | |
957 | issue.subject = 'Subject changed' |
|
957 | issue.subject = 'Subject changed' | |
958 | assert issue.save |
|
958 | assert issue.save | |
959 | end |
|
959 | end | |
960 |
|
960 | |||
961 | def test_should_not_be_able_to_reopen_an_issue_assigned_to_a_closed_version |
|
961 | def test_should_not_be_able_to_reopen_an_issue_assigned_to_a_closed_version | |
962 | issue = Issue.find(11) |
|
962 | issue = Issue.find(11) | |
963 | issue.status_id = 1 |
|
963 | issue.status_id = 1 | |
964 | assert !issue.save |
|
964 | assert !issue.save | |
965 | assert_not_nil issue.errors[:base] |
|
965 | assert_not_nil issue.errors[:base] | |
966 | end |
|
966 | end | |
967 |
|
967 | |||
968 | def test_should_be_able_to_reopen_and_reassign_an_issue_assigned_to_a_closed_version |
|
968 | def test_should_be_able_to_reopen_and_reassign_an_issue_assigned_to_a_closed_version | |
969 | issue = Issue.find(11) |
|
969 | issue = Issue.find(11) | |
970 | issue.status_id = 1 |
|
970 | issue.status_id = 1 | |
971 | issue.fixed_version_id = 3 |
|
971 | issue.fixed_version_id = 3 | |
972 | assert issue.save |
|
972 | assert issue.save | |
973 | end |
|
973 | end | |
974 |
|
974 | |||
975 | def test_should_be_able_to_reopen_an_issue_assigned_to_a_locked_version |
|
975 | def test_should_be_able_to_reopen_an_issue_assigned_to_a_locked_version | |
976 | issue = Issue.find(12) |
|
976 | issue = Issue.find(12) | |
977 | assert_equal 'locked', issue.fixed_version.status |
|
977 | assert_equal 'locked', issue.fixed_version.status | |
978 | issue.status_id = 1 |
|
978 | issue.status_id = 1 | |
979 | assert issue.save |
|
979 | assert issue.save | |
980 | end |
|
980 | end | |
981 |
|
981 | |||
982 | def test_should_not_be_able_to_keep_unshared_version_when_changing_project |
|
982 | def test_should_not_be_able_to_keep_unshared_version_when_changing_project | |
983 | issue = Issue.find(2) |
|
983 | issue = Issue.find(2) | |
984 | assert_equal 2, issue.fixed_version_id |
|
984 | assert_equal 2, issue.fixed_version_id | |
985 | issue.project_id = 3 |
|
985 | issue.project_id = 3 | |
986 | assert_nil issue.fixed_version_id |
|
986 | assert_nil issue.fixed_version_id | |
987 | issue.fixed_version_id = 2 |
|
987 | issue.fixed_version_id = 2 | |
988 | assert !issue.save |
|
988 | assert !issue.save | |
989 | assert_include 'Target version is not included in the list', issue.errors.full_messages |
|
989 | assert_include 'Target version is not included in the list', issue.errors.full_messages | |
990 | end |
|
990 | end | |
991 |
|
991 | |||
992 | def test_should_keep_shared_version_when_changing_project |
|
992 | def test_should_keep_shared_version_when_changing_project | |
993 | Version.find(2).update_attribute :sharing, 'tree' |
|
993 | Version.find(2).update_attribute :sharing, 'tree' | |
994 |
|
994 | |||
995 | issue = Issue.find(2) |
|
995 | issue = Issue.find(2) | |
996 | assert_equal 2, issue.fixed_version_id |
|
996 | assert_equal 2, issue.fixed_version_id | |
997 | issue.project_id = 3 |
|
997 | issue.project_id = 3 | |
998 | assert_equal 2, issue.fixed_version_id |
|
998 | assert_equal 2, issue.fixed_version_id | |
999 | assert issue.save |
|
999 | assert issue.save | |
1000 | end |
|
1000 | end | |
1001 |
|
1001 | |||
1002 | def test_allowed_target_projects_on_move_should_include_projects_with_issue_tracking_enabled |
|
1002 | def test_allowed_target_projects_on_move_should_include_projects_with_issue_tracking_enabled | |
1003 | assert_include Project.find(2), Issue.allowed_target_projects_on_move(User.find(2)) |
|
1003 | assert_include Project.find(2), Issue.allowed_target_projects_on_move(User.find(2)) | |
1004 | end |
|
1004 | end | |
1005 |
|
1005 | |||
1006 | def test_allowed_target_projects_on_move_should_not_include_projects_with_issue_tracking_disabled |
|
1006 | def test_allowed_target_projects_on_move_should_not_include_projects_with_issue_tracking_disabled | |
1007 | Project.find(2).disable_module! :issue_tracking |
|
1007 | Project.find(2).disable_module! :issue_tracking | |
1008 | assert_not_include Project.find(2), Issue.allowed_target_projects_on_move(User.find(2)) |
|
1008 | assert_not_include Project.find(2), Issue.allowed_target_projects_on_move(User.find(2)) | |
1009 | end |
|
1009 | end | |
1010 |
|
1010 | |||
1011 | def test_move_to_another_project_with_same_category |
|
1011 | def test_move_to_another_project_with_same_category | |
1012 | issue = Issue.find(1) |
|
1012 | issue = Issue.find(1) | |
1013 | issue.project = Project.find(2) |
|
1013 | issue.project = Project.find(2) | |
1014 | assert issue.save |
|
1014 | assert issue.save | |
1015 | issue.reload |
|
1015 | issue.reload | |
1016 | assert_equal 2, issue.project_id |
|
1016 | assert_equal 2, issue.project_id | |
1017 | # Category changes |
|
1017 | # Category changes | |
1018 | assert_equal 4, issue.category_id |
|
1018 | assert_equal 4, issue.category_id | |
1019 | # Make sure time entries were move to the target project |
|
1019 | # Make sure time entries were move to the target project | |
1020 | assert_equal 2, issue.time_entries.first.project_id |
|
1020 | assert_equal 2, issue.time_entries.first.project_id | |
1021 | end |
|
1021 | end | |
1022 |
|
1022 | |||
1023 | def test_move_to_another_project_without_same_category |
|
1023 | def test_move_to_another_project_without_same_category | |
1024 | issue = Issue.find(2) |
|
1024 | issue = Issue.find(2) | |
1025 | issue.project = Project.find(2) |
|
1025 | issue.project = Project.find(2) | |
1026 | assert issue.save |
|
1026 | assert issue.save | |
1027 | issue.reload |
|
1027 | issue.reload | |
1028 | assert_equal 2, issue.project_id |
|
1028 | assert_equal 2, issue.project_id | |
1029 | # Category cleared |
|
1029 | # Category cleared | |
1030 | assert_nil issue.category_id |
|
1030 | assert_nil issue.category_id | |
1031 | end |
|
1031 | end | |
1032 |
|
1032 | |||
1033 | def test_move_to_another_project_should_clear_fixed_version_when_not_shared |
|
1033 | def test_move_to_another_project_should_clear_fixed_version_when_not_shared | |
1034 | issue = Issue.find(1) |
|
1034 | issue = Issue.find(1) | |
1035 | issue.update_attribute(:fixed_version_id, 1) |
|
1035 | issue.update_attribute(:fixed_version_id, 1) | |
1036 | issue.project = Project.find(2) |
|
1036 | issue.project = Project.find(2) | |
1037 | assert issue.save |
|
1037 | assert issue.save | |
1038 | issue.reload |
|
1038 | issue.reload | |
1039 | assert_equal 2, issue.project_id |
|
1039 | assert_equal 2, issue.project_id | |
1040 | # Cleared fixed_version |
|
1040 | # Cleared fixed_version | |
1041 | assert_equal nil, issue.fixed_version |
|
1041 | assert_equal nil, issue.fixed_version | |
1042 | end |
|
1042 | end | |
1043 |
|
1043 | |||
1044 | def test_move_to_another_project_should_keep_fixed_version_when_shared_with_the_target_project |
|
1044 | def test_move_to_another_project_should_keep_fixed_version_when_shared_with_the_target_project | |
1045 | issue = Issue.find(1) |
|
1045 | issue = Issue.find(1) | |
1046 | issue.update_attribute(:fixed_version_id, 4) |
|
1046 | issue.update_attribute(:fixed_version_id, 4) | |
1047 | issue.project = Project.find(5) |
|
1047 | issue.project = Project.find(5) | |
1048 | assert issue.save |
|
1048 | assert issue.save | |
1049 | issue.reload |
|
1049 | issue.reload | |
1050 | assert_equal 5, issue.project_id |
|
1050 | assert_equal 5, issue.project_id | |
1051 | # Keep fixed_version |
|
1051 | # Keep fixed_version | |
1052 | assert_equal 4, issue.fixed_version_id |
|
1052 | assert_equal 4, issue.fixed_version_id | |
1053 | end |
|
1053 | end | |
1054 |
|
1054 | |||
1055 | def test_move_to_another_project_should_clear_fixed_version_when_not_shared_with_the_target_project |
|
1055 | def test_move_to_another_project_should_clear_fixed_version_when_not_shared_with_the_target_project | |
1056 | issue = Issue.find(1) |
|
1056 | issue = Issue.find(1) | |
1057 | issue.update_attribute(:fixed_version_id, 1) |
|
1057 | issue.update_attribute(:fixed_version_id, 1) | |
1058 | issue.project = Project.find(5) |
|
1058 | issue.project = Project.find(5) | |
1059 | assert issue.save |
|
1059 | assert issue.save | |
1060 | issue.reload |
|
1060 | issue.reload | |
1061 | assert_equal 5, issue.project_id |
|
1061 | assert_equal 5, issue.project_id | |
1062 | # Cleared fixed_version |
|
1062 | # Cleared fixed_version | |
1063 | assert_equal nil, issue.fixed_version |
|
1063 | assert_equal nil, issue.fixed_version | |
1064 | end |
|
1064 | end | |
1065 |
|
1065 | |||
1066 | def test_move_to_another_project_should_keep_fixed_version_when_shared_systemwide |
|
1066 | def test_move_to_another_project_should_keep_fixed_version_when_shared_systemwide | |
1067 | issue = Issue.find(1) |
|
1067 | issue = Issue.find(1) | |
1068 | issue.update_attribute(:fixed_version_id, 7) |
|
1068 | issue.update_attribute(:fixed_version_id, 7) | |
1069 | issue.project = Project.find(2) |
|
1069 | issue.project = Project.find(2) | |
1070 | assert issue.save |
|
1070 | assert issue.save | |
1071 | issue.reload |
|
1071 | issue.reload | |
1072 | assert_equal 2, issue.project_id |
|
1072 | assert_equal 2, issue.project_id | |
1073 | # Keep fixed_version |
|
1073 | # Keep fixed_version | |
1074 | assert_equal 7, issue.fixed_version_id |
|
1074 | assert_equal 7, issue.fixed_version_id | |
1075 | end |
|
1075 | end | |
1076 |
|
1076 | |||
1077 | def test_move_to_another_project_should_keep_parent_if_valid |
|
1077 | def test_move_to_another_project_should_keep_parent_if_valid | |
1078 | issue = Issue.find(1) |
|
1078 | issue = Issue.find(1) | |
1079 | issue.update_attribute(:parent_issue_id, 2) |
|
1079 | issue.update_attribute(:parent_issue_id, 2) | |
1080 | issue.project = Project.find(3) |
|
1080 | issue.project = Project.find(3) | |
1081 | assert issue.save |
|
1081 | assert issue.save | |
1082 | issue.reload |
|
1082 | issue.reload | |
1083 | assert_equal 2, issue.parent_id |
|
1083 | assert_equal 2, issue.parent_id | |
1084 | end |
|
1084 | end | |
1085 |
|
1085 | |||
1086 | def test_move_to_another_project_should_clear_parent_if_not_valid |
|
1086 | def test_move_to_another_project_should_clear_parent_if_not_valid | |
1087 | issue = Issue.find(1) |
|
1087 | issue = Issue.find(1) | |
1088 | issue.update_attribute(:parent_issue_id, 2) |
|
1088 | issue.update_attribute(:parent_issue_id, 2) | |
1089 | issue.project = Project.find(2) |
|
1089 | issue.project = Project.find(2) | |
1090 | assert issue.save |
|
1090 | assert issue.save | |
1091 | issue.reload |
|
1091 | issue.reload | |
1092 | assert_nil issue.parent_id |
|
1092 | assert_nil issue.parent_id | |
1093 | end |
|
1093 | end | |
1094 |
|
1094 | |||
1095 | def test_move_to_another_project_with_disabled_tracker |
|
1095 | def test_move_to_another_project_with_disabled_tracker | |
1096 | issue = Issue.find(1) |
|
1096 | issue = Issue.find(1) | |
1097 | target = Project.find(2) |
|
1097 | target = Project.find(2) | |
1098 | target.tracker_ids = [3] |
|
1098 | target.tracker_ids = [3] | |
1099 | target.save |
|
1099 | target.save | |
1100 | issue.project = target |
|
1100 | issue.project = target | |
1101 | assert issue.save |
|
1101 | assert issue.save | |
1102 | issue.reload |
|
1102 | issue.reload | |
1103 | assert_equal 2, issue.project_id |
|
1103 | assert_equal 2, issue.project_id | |
1104 | assert_equal 3, issue.tracker_id |
|
1104 | assert_equal 3, issue.tracker_id | |
1105 | end |
|
1105 | end | |
1106 |
|
1106 | |||
1107 | def test_copy_to_the_same_project |
|
1107 | def test_copy_to_the_same_project | |
1108 | issue = Issue.find(1) |
|
1108 | issue = Issue.find(1) | |
1109 | copy = issue.copy |
|
1109 | copy = issue.copy | |
1110 | assert_difference 'Issue.count' do |
|
1110 | assert_difference 'Issue.count' do | |
1111 | copy.save! |
|
1111 | copy.save! | |
1112 | end |
|
1112 | end | |
1113 | assert_kind_of Issue, copy |
|
1113 | assert_kind_of Issue, copy | |
1114 | assert_equal issue.project, copy.project |
|
1114 | assert_equal issue.project, copy.project | |
1115 | assert_equal "125", copy.custom_value_for(2).value |
|
1115 | assert_equal "125", copy.custom_value_for(2).value | |
1116 | end |
|
1116 | end | |
1117 |
|
1117 | |||
1118 | def test_copy_to_another_project_and_tracker |
|
1118 | def test_copy_to_another_project_and_tracker | |
1119 | issue = Issue.find(1) |
|
1119 | issue = Issue.find(1) | |
1120 | copy = issue.copy(:project_id => 3, :tracker_id => 2) |
|
1120 | copy = issue.copy(:project_id => 3, :tracker_id => 2) | |
1121 | assert_difference 'Issue.count' do |
|
1121 | assert_difference 'Issue.count' do | |
1122 | copy.save! |
|
1122 | copy.save! | |
1123 | end |
|
1123 | end | |
1124 | copy.reload |
|
1124 | copy.reload | |
1125 | assert_kind_of Issue, copy |
|
1125 | assert_kind_of Issue, copy | |
1126 | assert_equal Project.find(3), copy.project |
|
1126 | assert_equal Project.find(3), copy.project | |
1127 | assert_equal Tracker.find(2), copy.tracker |
|
1127 | assert_equal Tracker.find(2), copy.tracker | |
1128 | # Custom field #2 is not associated with target tracker |
|
1128 | # Custom field #2 is not associated with target tracker | |
1129 | assert_nil copy.custom_value_for(2) |
|
1129 | assert_nil copy.custom_value_for(2) | |
1130 | end |
|
1130 | end | |
1131 |
|
1131 | |||
1132 | context "#copy" do |
|
1132 | test "#copy should not create a journal" do | |
1133 | setup do |
|
1133 | copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2, :assigned_to_id => 3) | |
1134 | @issue = Issue.find(1) |
|
|||
1135 | end |
|
|||
1136 |
|
||||
1137 | should "not create a journal" do |
|
|||
1138 | copy = @issue.copy(:project_id => 3, :tracker_id => 2, :assigned_to_id => 3) |
|
|||
1139 |
|
|
1134 | copy.save! | |
1140 |
|
|
1135 | assert_equal 0, copy.reload.journals.size | |
1141 |
|
|
1136 | end | |
1142 |
|
1137 | |||
1143 |
|
|
1138 | test "#copy should allow assigned_to changes" do | |
1144 |
|
|
1139 | copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2, :assigned_to_id => 3) | |
1145 |
|
|
1140 | assert_equal 3, copy.assigned_to_id | |
1146 |
|
|
1141 | end | |
1147 |
|
1142 | |||
1148 |
|
|
1143 | test "#copy should allow status changes" do | |
1149 |
|
|
1144 | copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2, :status_id => 2) | |
1150 |
|
|
1145 | assert_equal 2, copy.status_id | |
1151 |
|
|
1146 | end | |
1152 |
|
1147 | |||
1153 |
|
|
1148 | test "#copy should allow start date changes" do | |
1154 |
|
|
1149 | date = Date.today | |
1155 |
|
|
1150 | copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2, :start_date => date) | |
1156 |
|
|
1151 | assert_equal date, copy.start_date | |
1157 |
|
|
1152 | end | |
1158 |
|
1153 | |||
1159 |
|
|
1154 | test "#copy should allow due date changes" do | |
1160 |
|
|
1155 | date = Date.today | |
1161 |
|
|
1156 | copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2, :due_date => date) | |
1162 |
|
|
1157 | assert_equal date, copy.due_date | |
1163 |
|
|
1158 | end | |
1164 |
|
1159 | |||
1165 |
|
|
1160 | test "#copy should set current user as author" do | |
1166 |
|
|
1161 | User.current = User.find(9) | |
1167 |
|
|
1162 | copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2) | |
1168 |
|
|
1163 | assert_equal User.current, copy.author | |
1169 |
|
|
1164 | end | |
1170 |
|
1165 | |||
1171 |
|
|
1166 | test "#copy should create a journal with notes" do | |
1172 |
|
|
1167 | date = Date.today | |
1173 |
|
|
1168 | notes = "Notes added when copying" | |
1174 |
|
|
1169 | copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2, :start_date => date) | |
1175 |
|
|
1170 | copy.init_journal(User.current, notes) | |
1176 |
|
|
1171 | copy.save! | |
1177 |
|
1172 | |||
1178 |
|
|
1173 | assert_equal 1, copy.journals.size | |
1179 |
|
|
1174 | journal = copy.journals.first | |
1180 |
|
|
1175 | assert_equal 0, journal.details.size | |
1181 |
|
|
1176 | assert_equal notes, journal.notes | |
1182 |
|
|
1177 | end | |
1183 | end |
|
|||
1184 |
|
1178 | |||
1185 | def test_valid_parent_project |
|
1179 | def test_valid_parent_project | |
1186 | issue = Issue.find(1) |
|
1180 | issue = Issue.find(1) | |
1187 | issue_in_same_project = Issue.find(2) |
|
1181 | issue_in_same_project = Issue.find(2) | |
1188 | issue_in_child_project = Issue.find(5) |
|
1182 | issue_in_child_project = Issue.find(5) | |
1189 | issue_in_grandchild_project = Issue.generate!(:project_id => 6, :tracker_id => 1) |
|
1183 | issue_in_grandchild_project = Issue.generate!(:project_id => 6, :tracker_id => 1) | |
1190 | issue_in_other_child_project = Issue.find(6) |
|
1184 | issue_in_other_child_project = Issue.find(6) | |
1191 | issue_in_different_tree = Issue.find(4) |
|
1185 | issue_in_different_tree = Issue.find(4) | |
1192 |
|
1186 | |||
1193 | with_settings :cross_project_subtasks => '' do |
|
1187 | with_settings :cross_project_subtasks => '' do | |
1194 | assert_equal true, issue.valid_parent_project?(issue_in_same_project) |
|
1188 | assert_equal true, issue.valid_parent_project?(issue_in_same_project) | |
1195 | assert_equal false, issue.valid_parent_project?(issue_in_child_project) |
|
1189 | assert_equal false, issue.valid_parent_project?(issue_in_child_project) | |
1196 | assert_equal false, issue.valid_parent_project?(issue_in_grandchild_project) |
|
1190 | assert_equal false, issue.valid_parent_project?(issue_in_grandchild_project) | |
1197 | assert_equal false, issue.valid_parent_project?(issue_in_different_tree) |
|
1191 | assert_equal false, issue.valid_parent_project?(issue_in_different_tree) | |
1198 | end |
|
1192 | end | |
1199 |
|
1193 | |||
1200 | with_settings :cross_project_subtasks => 'system' do |
|
1194 | with_settings :cross_project_subtasks => 'system' do | |
1201 | assert_equal true, issue.valid_parent_project?(issue_in_same_project) |
|
1195 | assert_equal true, issue.valid_parent_project?(issue_in_same_project) | |
1202 | assert_equal true, issue.valid_parent_project?(issue_in_child_project) |
|
1196 | assert_equal true, issue.valid_parent_project?(issue_in_child_project) | |
1203 | assert_equal true, issue.valid_parent_project?(issue_in_different_tree) |
|
1197 | assert_equal true, issue.valid_parent_project?(issue_in_different_tree) | |
1204 | end |
|
1198 | end | |
1205 |
|
1199 | |||
1206 | with_settings :cross_project_subtasks => 'tree' do |
|
1200 | with_settings :cross_project_subtasks => 'tree' do | |
1207 | assert_equal true, issue.valid_parent_project?(issue_in_same_project) |
|
1201 | assert_equal true, issue.valid_parent_project?(issue_in_same_project) | |
1208 | assert_equal true, issue.valid_parent_project?(issue_in_child_project) |
|
1202 | assert_equal true, issue.valid_parent_project?(issue_in_child_project) | |
1209 | assert_equal true, issue.valid_parent_project?(issue_in_grandchild_project) |
|
1203 | assert_equal true, issue.valid_parent_project?(issue_in_grandchild_project) | |
1210 | assert_equal false, issue.valid_parent_project?(issue_in_different_tree) |
|
1204 | assert_equal false, issue.valid_parent_project?(issue_in_different_tree) | |
1211 |
|
1205 | |||
1212 | assert_equal true, issue_in_child_project.valid_parent_project?(issue_in_same_project) |
|
1206 | assert_equal true, issue_in_child_project.valid_parent_project?(issue_in_same_project) | |
1213 | assert_equal true, issue_in_child_project.valid_parent_project?(issue_in_other_child_project) |
|
1207 | assert_equal true, issue_in_child_project.valid_parent_project?(issue_in_other_child_project) | |
1214 | end |
|
1208 | end | |
1215 |
|
1209 | |||
1216 | with_settings :cross_project_subtasks => 'descendants' do |
|
1210 | with_settings :cross_project_subtasks => 'descendants' do | |
1217 | assert_equal true, issue.valid_parent_project?(issue_in_same_project) |
|
1211 | assert_equal true, issue.valid_parent_project?(issue_in_same_project) | |
1218 | assert_equal false, issue.valid_parent_project?(issue_in_child_project) |
|
1212 | assert_equal false, issue.valid_parent_project?(issue_in_child_project) | |
1219 | assert_equal false, issue.valid_parent_project?(issue_in_grandchild_project) |
|
1213 | assert_equal false, issue.valid_parent_project?(issue_in_grandchild_project) | |
1220 | assert_equal false, issue.valid_parent_project?(issue_in_different_tree) |
|
1214 | assert_equal false, issue.valid_parent_project?(issue_in_different_tree) | |
1221 |
|
1215 | |||
1222 | assert_equal true, issue_in_child_project.valid_parent_project?(issue) |
|
1216 | assert_equal true, issue_in_child_project.valid_parent_project?(issue) | |
1223 | assert_equal false, issue_in_child_project.valid_parent_project?(issue_in_other_child_project) |
|
1217 | assert_equal false, issue_in_child_project.valid_parent_project?(issue_in_other_child_project) | |
1224 | end |
|
1218 | end | |
1225 | end |
|
1219 | end | |
1226 |
|
1220 | |||
1227 | def test_recipients_should_include_previous_assignee |
|
1221 | def test_recipients_should_include_previous_assignee | |
1228 | user = User.find(3) |
|
1222 | user = User.find(3) | |
1229 | user.members.update_all ["mail_notification = ?", false] |
|
1223 | user.members.update_all ["mail_notification = ?", false] | |
1230 | user.update_attribute :mail_notification, 'only_assigned' |
|
1224 | user.update_attribute :mail_notification, 'only_assigned' | |
1231 |
|
1225 | |||
1232 | issue = Issue.find(2) |
|
1226 | issue = Issue.find(2) | |
1233 | issue.assigned_to = nil |
|
1227 | issue.assigned_to = nil | |
1234 | assert_include user.mail, issue.recipients |
|
1228 | assert_include user.mail, issue.recipients | |
1235 | issue.save! |
|
1229 | issue.save! | |
1236 | assert !issue.recipients.include?(user.mail) |
|
1230 | assert !issue.recipients.include?(user.mail) | |
1237 | end |
|
1231 | end | |
1238 |
|
1232 | |||
1239 | def test_recipients_should_not_include_users_that_cannot_view_the_issue |
|
1233 | def test_recipients_should_not_include_users_that_cannot_view_the_issue | |
1240 | issue = Issue.find(12) |
|
1234 | issue = Issue.find(12) | |
1241 | assert issue.recipients.include?(issue.author.mail) |
|
1235 | assert issue.recipients.include?(issue.author.mail) | |
1242 | # copy the issue to a private project |
|
1236 | # copy the issue to a private project | |
1243 | copy = issue.copy(:project_id => 5, :tracker_id => 2) |
|
1237 | copy = issue.copy(:project_id => 5, :tracker_id => 2) | |
1244 | # author is not a member of project anymore |
|
1238 | # author is not a member of project anymore | |
1245 | assert !copy.recipients.include?(copy.author.mail) |
|
1239 | assert !copy.recipients.include?(copy.author.mail) | |
1246 | end |
|
1240 | end | |
1247 |
|
1241 | |||
1248 | def test_recipients_should_include_the_assigned_group_members |
|
1242 | def test_recipients_should_include_the_assigned_group_members | |
1249 | group_member = User.generate! |
|
1243 | group_member = User.generate! | |
1250 | group = Group.generate! |
|
1244 | group = Group.generate! | |
1251 | group.users << group_member |
|
1245 | group.users << group_member | |
1252 |
|
1246 | |||
1253 | issue = Issue.find(12) |
|
1247 | issue = Issue.find(12) | |
1254 | issue.assigned_to = group |
|
1248 | issue.assigned_to = group | |
1255 | assert issue.recipients.include?(group_member.mail) |
|
1249 | assert issue.recipients.include?(group_member.mail) | |
1256 | end |
|
1250 | end | |
1257 |
|
1251 | |||
1258 | def test_watcher_recipients_should_not_include_users_that_cannot_view_the_issue |
|
1252 | def test_watcher_recipients_should_not_include_users_that_cannot_view_the_issue | |
1259 | user = User.find(3) |
|
1253 | user = User.find(3) | |
1260 | issue = Issue.find(9) |
|
1254 | issue = Issue.find(9) | |
1261 | Watcher.create!(:user => user, :watchable => issue) |
|
1255 | Watcher.create!(:user => user, :watchable => issue) | |
1262 | assert issue.watched_by?(user) |
|
1256 | assert issue.watched_by?(user) | |
1263 | assert !issue.watcher_recipients.include?(user.mail) |
|
1257 | assert !issue.watcher_recipients.include?(user.mail) | |
1264 | end |
|
1258 | end | |
1265 |
|
1259 | |||
1266 | def test_issue_destroy |
|
1260 | def test_issue_destroy | |
1267 | Issue.find(1).destroy |
|
1261 | Issue.find(1).destroy | |
1268 | assert_nil Issue.find_by_id(1) |
|
1262 | assert_nil Issue.find_by_id(1) | |
1269 | assert_nil TimeEntry.find_by_issue_id(1) |
|
1263 | assert_nil TimeEntry.find_by_issue_id(1) | |
1270 | end |
|
1264 | end | |
1271 |
|
1265 | |||
1272 | def test_destroying_a_deleted_issue_should_not_raise_an_error |
|
1266 | def test_destroying_a_deleted_issue_should_not_raise_an_error | |
1273 | issue = Issue.find(1) |
|
1267 | issue = Issue.find(1) | |
1274 | Issue.find(1).destroy |
|
1268 | Issue.find(1).destroy | |
1275 |
|
1269 | |||
1276 | assert_nothing_raised do |
|
1270 | assert_nothing_raised do | |
1277 | assert_no_difference 'Issue.count' do |
|
1271 | assert_no_difference 'Issue.count' do | |
1278 | issue.destroy |
|
1272 | issue.destroy | |
1279 | end |
|
1273 | end | |
1280 | assert issue.destroyed? |
|
1274 | assert issue.destroyed? | |
1281 | end |
|
1275 | end | |
1282 | end |
|
1276 | end | |
1283 |
|
1277 | |||
1284 | def test_destroying_a_stale_issue_should_not_raise_an_error |
|
1278 | def test_destroying_a_stale_issue_should_not_raise_an_error | |
1285 | issue = Issue.find(1) |
|
1279 | issue = Issue.find(1) | |
1286 | Issue.find(1).update_attribute :subject, "Updated" |
|
1280 | Issue.find(1).update_attribute :subject, "Updated" | |
1287 |
|
1281 | |||
1288 | assert_nothing_raised do |
|
1282 | assert_nothing_raised do | |
1289 | assert_difference 'Issue.count', -1 do |
|
1283 | assert_difference 'Issue.count', -1 do | |
1290 | issue.destroy |
|
1284 | issue.destroy | |
1291 | end |
|
1285 | end | |
1292 | assert issue.destroyed? |
|
1286 | assert issue.destroyed? | |
1293 | end |
|
1287 | end | |
1294 | end |
|
1288 | end | |
1295 |
|
1289 | |||
1296 | def test_blocked |
|
1290 | def test_blocked | |
1297 | blocked_issue = Issue.find(9) |
|
1291 | blocked_issue = Issue.find(9) | |
1298 | blocking_issue = Issue.find(10) |
|
1292 | blocking_issue = Issue.find(10) | |
1299 |
|
1293 | |||
1300 | assert blocked_issue.blocked? |
|
1294 | assert blocked_issue.blocked? | |
1301 | assert !blocking_issue.blocked? |
|
1295 | assert !blocking_issue.blocked? | |
1302 | end |
|
1296 | end | |
1303 |
|
1297 | |||
1304 | def test_blocked_issues_dont_allow_closed_statuses |
|
1298 | def test_blocked_issues_dont_allow_closed_statuses | |
1305 | blocked_issue = Issue.find(9) |
|
1299 | blocked_issue = Issue.find(9) | |
1306 |
|
1300 | |||
1307 | allowed_statuses = blocked_issue.new_statuses_allowed_to(users(:users_002)) |
|
1301 | allowed_statuses = blocked_issue.new_statuses_allowed_to(users(:users_002)) | |
1308 | assert !allowed_statuses.empty? |
|
1302 | assert !allowed_statuses.empty? | |
1309 | closed_statuses = allowed_statuses.select {|st| st.is_closed?} |
|
1303 | closed_statuses = allowed_statuses.select {|st| st.is_closed?} | |
1310 | assert closed_statuses.empty? |
|
1304 | assert closed_statuses.empty? | |
1311 | end |
|
1305 | end | |
1312 |
|
1306 | |||
1313 | def test_unblocked_issues_allow_closed_statuses |
|
1307 | def test_unblocked_issues_allow_closed_statuses | |
1314 | blocking_issue = Issue.find(10) |
|
1308 | blocking_issue = Issue.find(10) | |
1315 |
|
1309 | |||
1316 | allowed_statuses = blocking_issue.new_statuses_allowed_to(users(:users_002)) |
|
1310 | allowed_statuses = blocking_issue.new_statuses_allowed_to(users(:users_002)) | |
1317 | assert !allowed_statuses.empty? |
|
1311 | assert !allowed_statuses.empty? | |
1318 | closed_statuses = allowed_statuses.select {|st| st.is_closed?} |
|
1312 | closed_statuses = allowed_statuses.select {|st| st.is_closed?} | |
1319 | assert !closed_statuses.empty? |
|
1313 | assert !closed_statuses.empty? | |
1320 | end |
|
1314 | end | |
1321 |
|
1315 | |||
1322 | def test_reschedule_an_issue_without_dates |
|
1316 | def test_reschedule_an_issue_without_dates | |
1323 | with_settings :non_working_week_days => [] do |
|
1317 | with_settings :non_working_week_days => [] do | |
1324 | issue = Issue.new(:start_date => nil, :due_date => nil) |
|
1318 | issue = Issue.new(:start_date => nil, :due_date => nil) | |
1325 | issue.reschedule_on '2012-10-09'.to_date |
|
1319 | issue.reschedule_on '2012-10-09'.to_date | |
1326 | assert_equal '2012-10-09'.to_date, issue.start_date |
|
1320 | assert_equal '2012-10-09'.to_date, issue.start_date | |
1327 | assert_equal '2012-10-09'.to_date, issue.due_date |
|
1321 | assert_equal '2012-10-09'.to_date, issue.due_date | |
1328 | end |
|
1322 | end | |
1329 |
|
1323 | |||
1330 | with_settings :non_working_week_days => %w(6 7) do |
|
1324 | with_settings :non_working_week_days => %w(6 7) do | |
1331 | issue = Issue.new(:start_date => nil, :due_date => nil) |
|
1325 | issue = Issue.new(:start_date => nil, :due_date => nil) | |
1332 | issue.reschedule_on '2012-10-09'.to_date |
|
1326 | issue.reschedule_on '2012-10-09'.to_date | |
1333 | assert_equal '2012-10-09'.to_date, issue.start_date |
|
1327 | assert_equal '2012-10-09'.to_date, issue.start_date | |
1334 | assert_equal '2012-10-09'.to_date, issue.due_date |
|
1328 | assert_equal '2012-10-09'.to_date, issue.due_date | |
1335 |
|
1329 | |||
1336 | issue = Issue.new(:start_date => nil, :due_date => nil) |
|
1330 | issue = Issue.new(:start_date => nil, :due_date => nil) | |
1337 | issue.reschedule_on '2012-10-13'.to_date |
|
1331 | issue.reschedule_on '2012-10-13'.to_date | |
1338 | assert_equal '2012-10-15'.to_date, issue.start_date |
|
1332 | assert_equal '2012-10-15'.to_date, issue.start_date | |
1339 | assert_equal '2012-10-15'.to_date, issue.due_date |
|
1333 | assert_equal '2012-10-15'.to_date, issue.due_date | |
1340 | end |
|
1334 | end | |
1341 | end |
|
1335 | end | |
1342 |
|
1336 | |||
1343 | def test_reschedule_an_issue_with_start_date |
|
1337 | def test_reschedule_an_issue_with_start_date | |
1344 | with_settings :non_working_week_days => [] do |
|
1338 | with_settings :non_working_week_days => [] do | |
1345 | issue = Issue.new(:start_date => '2012-10-09', :due_date => nil) |
|
1339 | issue = Issue.new(:start_date => '2012-10-09', :due_date => nil) | |
1346 | issue.reschedule_on '2012-10-13'.to_date |
|
1340 | issue.reschedule_on '2012-10-13'.to_date | |
1347 | assert_equal '2012-10-13'.to_date, issue.start_date |
|
1341 | assert_equal '2012-10-13'.to_date, issue.start_date | |
1348 | assert_equal '2012-10-13'.to_date, issue.due_date |
|
1342 | assert_equal '2012-10-13'.to_date, issue.due_date | |
1349 | end |
|
1343 | end | |
1350 |
|
1344 | |||
1351 | with_settings :non_working_week_days => %w(6 7) do |
|
1345 | with_settings :non_working_week_days => %w(6 7) do | |
1352 | issue = Issue.new(:start_date => '2012-10-09', :due_date => nil) |
|
1346 | issue = Issue.new(:start_date => '2012-10-09', :due_date => nil) | |
1353 | issue.reschedule_on '2012-10-11'.to_date |
|
1347 | issue.reschedule_on '2012-10-11'.to_date | |
1354 | assert_equal '2012-10-11'.to_date, issue.start_date |
|
1348 | assert_equal '2012-10-11'.to_date, issue.start_date | |
1355 | assert_equal '2012-10-11'.to_date, issue.due_date |
|
1349 | assert_equal '2012-10-11'.to_date, issue.due_date | |
1356 |
|
1350 | |||
1357 | issue = Issue.new(:start_date => '2012-10-09', :due_date => nil) |
|
1351 | issue = Issue.new(:start_date => '2012-10-09', :due_date => nil) | |
1358 | issue.reschedule_on '2012-10-13'.to_date |
|
1352 | issue.reschedule_on '2012-10-13'.to_date | |
1359 | assert_equal '2012-10-15'.to_date, issue.start_date |
|
1353 | assert_equal '2012-10-15'.to_date, issue.start_date | |
1360 | assert_equal '2012-10-15'.to_date, issue.due_date |
|
1354 | assert_equal '2012-10-15'.to_date, issue.due_date | |
1361 | end |
|
1355 | end | |
1362 | end |
|
1356 | end | |
1363 |
|
1357 | |||
1364 | def test_reschedule_an_issue_with_start_and_due_dates |
|
1358 | def test_reschedule_an_issue_with_start_and_due_dates | |
1365 | with_settings :non_working_week_days => [] do |
|
1359 | with_settings :non_working_week_days => [] do | |
1366 | issue = Issue.new(:start_date => '2012-10-09', :due_date => '2012-10-15') |
|
1360 | issue = Issue.new(:start_date => '2012-10-09', :due_date => '2012-10-15') | |
1367 | issue.reschedule_on '2012-10-13'.to_date |
|
1361 | issue.reschedule_on '2012-10-13'.to_date | |
1368 | assert_equal '2012-10-13'.to_date, issue.start_date |
|
1362 | assert_equal '2012-10-13'.to_date, issue.start_date | |
1369 | assert_equal '2012-10-19'.to_date, issue.due_date |
|
1363 | assert_equal '2012-10-19'.to_date, issue.due_date | |
1370 | end |
|
1364 | end | |
1371 |
|
1365 | |||
1372 | with_settings :non_working_week_days => %w(6 7) do |
|
1366 | with_settings :non_working_week_days => %w(6 7) do | |
1373 | issue = Issue.new(:start_date => '2012-10-09', :due_date => '2012-10-19') # 8 working days |
|
1367 | issue = Issue.new(:start_date => '2012-10-09', :due_date => '2012-10-19') # 8 working days | |
1374 | issue.reschedule_on '2012-10-11'.to_date |
|
1368 | issue.reschedule_on '2012-10-11'.to_date | |
1375 | assert_equal '2012-10-11'.to_date, issue.start_date |
|
1369 | assert_equal '2012-10-11'.to_date, issue.start_date | |
1376 | assert_equal '2012-10-23'.to_date, issue.due_date |
|
1370 | assert_equal '2012-10-23'.to_date, issue.due_date | |
1377 |
|
1371 | |||
1378 | issue = Issue.new(:start_date => '2012-10-09', :due_date => '2012-10-19') |
|
1372 | issue = Issue.new(:start_date => '2012-10-09', :due_date => '2012-10-19') | |
1379 | issue.reschedule_on '2012-10-13'.to_date |
|
1373 | issue.reschedule_on '2012-10-13'.to_date | |
1380 | assert_equal '2012-10-15'.to_date, issue.start_date |
|
1374 | assert_equal '2012-10-15'.to_date, issue.start_date | |
1381 | assert_equal '2012-10-25'.to_date, issue.due_date |
|
1375 | assert_equal '2012-10-25'.to_date, issue.due_date | |
1382 | end |
|
1376 | end | |
1383 | end |
|
1377 | end | |
1384 |
|
1378 | |||
1385 | def test_rescheduling_an_issue_to_a_later_due_date_should_reschedule_following_issue |
|
1379 | def test_rescheduling_an_issue_to_a_later_due_date_should_reschedule_following_issue | |
1386 | issue1 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17') |
|
1380 | issue1 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17') | |
1387 | issue2 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17') |
|
1381 | issue2 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17') | |
1388 | IssueRelation.create!(:issue_from => issue1, :issue_to => issue2, |
|
1382 | IssueRelation.create!(:issue_from => issue1, :issue_to => issue2, | |
1389 | :relation_type => IssueRelation::TYPE_PRECEDES) |
|
1383 | :relation_type => IssueRelation::TYPE_PRECEDES) | |
1390 | assert_equal Date.parse('2012-10-18'), issue2.reload.start_date |
|
1384 | assert_equal Date.parse('2012-10-18'), issue2.reload.start_date | |
1391 |
|
1385 | |||
1392 | issue1.due_date = '2012-10-23' |
|
1386 | issue1.due_date = '2012-10-23' | |
1393 | issue1.save! |
|
1387 | issue1.save! | |
1394 | issue2.reload |
|
1388 | issue2.reload | |
1395 | assert_equal Date.parse('2012-10-24'), issue2.start_date |
|
1389 | assert_equal Date.parse('2012-10-24'), issue2.start_date | |
1396 | assert_equal Date.parse('2012-10-26'), issue2.due_date |
|
1390 | assert_equal Date.parse('2012-10-26'), issue2.due_date | |
1397 | end |
|
1391 | end | |
1398 |
|
1392 | |||
1399 | def test_rescheduling_an_issue_to_an_earlier_due_date_should_reschedule_following_issue |
|
1393 | def test_rescheduling_an_issue_to_an_earlier_due_date_should_reschedule_following_issue | |
1400 | issue1 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17') |
|
1394 | issue1 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17') | |
1401 | issue2 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17') |
|
1395 | issue2 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17') | |
1402 | IssueRelation.create!(:issue_from => issue1, :issue_to => issue2, |
|
1396 | IssueRelation.create!(:issue_from => issue1, :issue_to => issue2, | |
1403 | :relation_type => IssueRelation::TYPE_PRECEDES) |
|
1397 | :relation_type => IssueRelation::TYPE_PRECEDES) | |
1404 | assert_equal Date.parse('2012-10-18'), issue2.reload.start_date |
|
1398 | assert_equal Date.parse('2012-10-18'), issue2.reload.start_date | |
1405 |
|
1399 | |||
1406 | issue1.start_date = '2012-09-17' |
|
1400 | issue1.start_date = '2012-09-17' | |
1407 | issue1.due_date = '2012-09-18' |
|
1401 | issue1.due_date = '2012-09-18' | |
1408 | issue1.save! |
|
1402 | issue1.save! | |
1409 | issue2.reload |
|
1403 | issue2.reload | |
1410 | assert_equal Date.parse('2012-09-19'), issue2.start_date |
|
1404 | assert_equal Date.parse('2012-09-19'), issue2.start_date | |
1411 | assert_equal Date.parse('2012-09-21'), issue2.due_date |
|
1405 | assert_equal Date.parse('2012-09-21'), issue2.due_date | |
1412 | end |
|
1406 | end | |
1413 |
|
1407 | |||
1414 | def test_rescheduling_reschedule_following_issue_earlier_should_consider_other_preceding_issues |
|
1408 | def test_rescheduling_reschedule_following_issue_earlier_should_consider_other_preceding_issues | |
1415 | issue1 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17') |
|
1409 | issue1 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17') | |
1416 | issue2 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17') |
|
1410 | issue2 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17') | |
1417 | issue3 = Issue.generate!(:start_date => '2012-10-01', :due_date => '2012-10-02') |
|
1411 | issue3 = Issue.generate!(:start_date => '2012-10-01', :due_date => '2012-10-02') | |
1418 | IssueRelation.create!(:issue_from => issue1, :issue_to => issue2, |
|
1412 | IssueRelation.create!(:issue_from => issue1, :issue_to => issue2, | |
1419 | :relation_type => IssueRelation::TYPE_PRECEDES) |
|
1413 | :relation_type => IssueRelation::TYPE_PRECEDES) | |
1420 | IssueRelation.create!(:issue_from => issue3, :issue_to => issue2, |
|
1414 | IssueRelation.create!(:issue_from => issue3, :issue_to => issue2, | |
1421 | :relation_type => IssueRelation::TYPE_PRECEDES) |
|
1415 | :relation_type => IssueRelation::TYPE_PRECEDES) | |
1422 | assert_equal Date.parse('2012-10-18'), issue2.reload.start_date |
|
1416 | assert_equal Date.parse('2012-10-18'), issue2.reload.start_date | |
1423 |
|
1417 | |||
1424 | issue1.start_date = '2012-09-17' |
|
1418 | issue1.start_date = '2012-09-17' | |
1425 | issue1.due_date = '2012-09-18' |
|
1419 | issue1.due_date = '2012-09-18' | |
1426 | issue1.save! |
|
1420 | issue1.save! | |
1427 | issue2.reload |
|
1421 | issue2.reload | |
1428 | # Issue 2 must start after Issue 3 |
|
1422 | # Issue 2 must start after Issue 3 | |
1429 | assert_equal Date.parse('2012-10-03'), issue2.start_date |
|
1423 | assert_equal Date.parse('2012-10-03'), issue2.start_date | |
1430 | assert_equal Date.parse('2012-10-05'), issue2.due_date |
|
1424 | assert_equal Date.parse('2012-10-05'), issue2.due_date | |
1431 | end |
|
1425 | end | |
1432 |
|
1426 | |||
1433 | def test_rescheduling_a_stale_issue_should_not_raise_an_error |
|
1427 | def test_rescheduling_a_stale_issue_should_not_raise_an_error | |
1434 | with_settings :non_working_week_days => [] do |
|
1428 | with_settings :non_working_week_days => [] do | |
1435 | stale = Issue.find(1) |
|
1429 | stale = Issue.find(1) | |
1436 | issue = Issue.find(1) |
|
1430 | issue = Issue.find(1) | |
1437 | issue.subject = "Updated" |
|
1431 | issue.subject = "Updated" | |
1438 | issue.save! |
|
1432 | issue.save! | |
1439 | date = 10.days.from_now.to_date |
|
1433 | date = 10.days.from_now.to_date | |
1440 | assert_nothing_raised do |
|
1434 | assert_nothing_raised do | |
1441 | stale.reschedule_on!(date) |
|
1435 | stale.reschedule_on!(date) | |
1442 | end |
|
1436 | end | |
1443 | assert_equal date, stale.reload.start_date |
|
1437 | assert_equal date, stale.reload.start_date | |
1444 | end |
|
1438 | end | |
1445 | end |
|
1439 | end | |
1446 |
|
1440 | |||
1447 | def test_overdue |
|
1441 | def test_overdue | |
1448 | assert Issue.new(:due_date => 1.day.ago.to_date).overdue? |
|
1442 | assert Issue.new(:due_date => 1.day.ago.to_date).overdue? | |
1449 | assert !Issue.new(:due_date => Date.today).overdue? |
|
1443 | assert !Issue.new(:due_date => Date.today).overdue? | |
1450 | assert !Issue.new(:due_date => 1.day.from_now.to_date).overdue? |
|
1444 | assert !Issue.new(:due_date => 1.day.from_now.to_date).overdue? | |
1451 | assert !Issue.new(:due_date => nil).overdue? |
|
1445 | assert !Issue.new(:due_date => nil).overdue? | |
1452 | assert !Issue.new(:due_date => 1.day.ago.to_date, |
|
1446 | assert !Issue.new(:due_date => 1.day.ago.to_date, | |
1453 | :status => IssueStatus.where(:is_closed => true).first |
|
1447 | :status => IssueStatus.where(:is_closed => true).first | |
1454 | ).overdue? |
|
1448 | ).overdue? | |
1455 | end |
|
1449 | end | |
1456 |
|
1450 | |||
1457 | context "#behind_schedule?" do |
|
1451 | test "#behind_schedule? should be false if the issue has no start_date" do | |
1458 | should "be false if the issue has no start_date" do |
|
|||
1459 |
|
|
1452 | assert !Issue.new(:start_date => nil, | |
1460 |
|
|
1453 | :due_date => 1.day.from_now.to_date, | |
1461 |
|
|
1454 | :done_ratio => 0).behind_schedule? | |
1462 |
|
|
1455 | end | |
1463 |
|
1456 | |||
1464 |
|
|
1457 | test "#behind_schedule? should be false if the issue has no end_date" do | |
1465 |
|
|
1458 | assert !Issue.new(:start_date => 1.day.from_now.to_date, | |
1466 |
|
|
1459 | :due_date => nil, | |
1467 |
|
|
1460 | :done_ratio => 0).behind_schedule? | |
1468 |
|
|
1461 | end | |
1469 |
|
1462 | |||
1470 |
|
|
1463 | test "#behind_schedule? should be false if the issue has more done than it's calendar time" do | |
1471 |
|
|
1464 | assert !Issue.new(:start_date => 50.days.ago.to_date, | |
1472 |
|
|
1465 | :due_date => 50.days.from_now.to_date, | |
1473 |
|
|
1466 | :done_ratio => 90).behind_schedule? | |
1474 |
|
|
1467 | end | |
1475 |
|
1468 | |||
1476 |
|
|
1469 | test "#behind_schedule? should be true if the issue hasn't been started at all" do | |
1477 |
|
|
1470 | assert Issue.new(:start_date => 1.day.ago.to_date, | |
1478 |
|
|
1471 | :due_date => 1.day.from_now.to_date, | |
1479 |
|
|
1472 | :done_ratio => 0).behind_schedule? | |
1480 |
|
|
1473 | end | |
1481 |
|
1474 | |||
1482 |
|
|
1475 | test "#behind_schedule? should be true if the issue has used more calendar time than it's done ratio" do | |
1483 |
|
|
1476 | assert Issue.new(:start_date => 100.days.ago.to_date, | |
1484 |
|
|
1477 | :due_date => Date.today, | |
1485 |
|
|
1478 | :done_ratio => 90).behind_schedule? | |
1486 |
|
|
1479 | end | |
1487 | end |
|
|||
1488 |
|
1480 | |||
1489 |
|
|
1481 | test "#assignable_users should be Users" do | |
1490 | should "be Users" do |
|
|||
1491 |
|
|
1482 | assert_kind_of User, Issue.find(1).assignable_users.first | |
1492 |
|
|
1483 | end | |
1493 |
|
1484 | |||
1494 |
|
|
1485 | test "#assignable_users should include the issue author" do | |
1495 |
|
|
1486 | non_project_member = User.generate! | |
1496 |
|
|
1487 | issue = Issue.generate!(:author => non_project_member) | |
1497 |
|
1488 | |||
1498 |
|
|
1489 | assert issue.assignable_users.include?(non_project_member) | |
1499 |
|
|
1490 | end | |
1500 |
|
1491 | |||
1501 |
|
|
1492 | test "#assignable_users should include the current assignee" do | |
1502 |
|
|
1493 | user = User.generate! | |
1503 |
|
|
1494 | issue = Issue.generate!(:assigned_to => user) | |
1504 |
|
|
1495 | user.lock! | |
1505 |
|
1496 | |||
1506 |
|
|
1497 | assert Issue.find(issue.id).assignable_users.include?(user) | |
1507 |
|
|
1498 | end | |
1508 |
|
1499 | |||
1509 |
|
|
1500 | test "#assignable_users should not show the issue author twice" do | |
1510 |
|
|
1501 | assignable_user_ids = Issue.find(1).assignable_users.collect(&:id) | |
1511 |
|
|
1502 | assert_equal 2, assignable_user_ids.length | |
1512 |
|
1503 | |||
1513 |
|
|
1504 | assignable_user_ids.each do |user_id| | |
1514 |
|
|
1505 | assert_equal 1, assignable_user_ids.select {|i| i == user_id}.length, | |
1515 |
|
|
1506 | "User #{user_id} appears more or less than once" | |
1516 |
|
|
1507 | end | |
1517 |
|
|
1508 | end | |
1518 |
|
1509 | |||
1519 |
|
|
1510 | test "#assignable_users with issue_group_assignment should include groups" do | |
1520 | should "include groups" do |
|
|||
1521 |
|
|
1511 | issue = Issue.new(:project => Project.find(2)) | |
1522 |
|
1512 | |||
1523 |
|
|
1513 | with_settings :issue_group_assignment => '1' do | |
1524 |
|
|
1514 | assert_equal %w(Group User), issue.assignable_users.map {|a| a.class.name}.uniq.sort | |
1525 |
|
|
1515 | assert issue.assignable_users.include?(Group.find(11)) | |
1526 |
|
|
1516 | end | |
1527 |
|
|
1517 | end | |
1528 | end |
|
|||
1529 |
|
1518 | |||
1530 |
|
|
1519 | test "#assignable_users without issue_group_assignment should not include groups" do | |
1531 | should "not include groups" do |
|
|||
1532 |
|
|
1520 | issue = Issue.new(:project => Project.find(2)) | |
1533 |
|
1521 | |||
1534 |
|
|
1522 | with_settings :issue_group_assignment => '0' do | |
1535 |
|
|
1523 | assert_equal %w(User), issue.assignable_users.map {|a| a.class.name}.uniq.sort | |
1536 |
|
|
1524 | assert !issue.assignable_users.include?(Group.find(11)) | |
1537 |
|
|
1525 | end | |
1538 |
|
|
1526 | end | |
1539 | end |
|
|||
1540 | end |
|
|||
1541 |
|
1527 | |||
1542 | def test_create_should_send_email_notification |
|
1528 | def test_create_should_send_email_notification | |
1543 | ActionMailer::Base.deliveries.clear |
|
1529 | ActionMailer::Base.deliveries.clear | |
1544 | issue = Issue.new(:project_id => 1, :tracker_id => 1, |
|
1530 | issue = Issue.new(:project_id => 1, :tracker_id => 1, | |
1545 | :author_id => 3, :status_id => 1, |
|
1531 | :author_id => 3, :status_id => 1, | |
1546 | :priority => IssuePriority.all.first, |
|
1532 | :priority => IssuePriority.all.first, | |
1547 | :subject => 'test_create', :estimated_hours => '1:30') |
|
1533 | :subject => 'test_create', :estimated_hours => '1:30') | |
1548 |
|
1534 | |||
1549 | assert issue.save |
|
1535 | assert issue.save | |
1550 | assert_equal 1, ActionMailer::Base.deliveries.size |
|
1536 | assert_equal 1, ActionMailer::Base.deliveries.size | |
1551 | end |
|
1537 | end | |
1552 |
|
1538 | |||
1553 | def test_stale_issue_should_not_send_email_notification |
|
1539 | def test_stale_issue_should_not_send_email_notification | |
1554 | ActionMailer::Base.deliveries.clear |
|
1540 | ActionMailer::Base.deliveries.clear | |
1555 | issue = Issue.find(1) |
|
1541 | issue = Issue.find(1) | |
1556 | stale = Issue.find(1) |
|
1542 | stale = Issue.find(1) | |
1557 |
|
1543 | |||
1558 | issue.init_journal(User.find(1)) |
|
1544 | issue.init_journal(User.find(1)) | |
1559 | issue.subject = 'Subjet update' |
|
1545 | issue.subject = 'Subjet update' | |
1560 | assert issue.save |
|
1546 | assert issue.save | |
1561 | assert_equal 1, ActionMailer::Base.deliveries.size |
|
1547 | assert_equal 1, ActionMailer::Base.deliveries.size | |
1562 | ActionMailer::Base.deliveries.clear |
|
1548 | ActionMailer::Base.deliveries.clear | |
1563 |
|
1549 | |||
1564 | stale.init_journal(User.find(1)) |
|
1550 | stale.init_journal(User.find(1)) | |
1565 | stale.subject = 'Another subjet update' |
|
1551 | stale.subject = 'Another subjet update' | |
1566 | assert_raise ActiveRecord::StaleObjectError do |
|
1552 | assert_raise ActiveRecord::StaleObjectError do | |
1567 | stale.save |
|
1553 | stale.save | |
1568 | end |
|
1554 | end | |
1569 | assert ActionMailer::Base.deliveries.empty? |
|
1555 | assert ActionMailer::Base.deliveries.empty? | |
1570 | end |
|
1556 | end | |
1571 |
|
1557 | |||
1572 | def test_journalized_description |
|
1558 | def test_journalized_description | |
1573 | IssueCustomField.delete_all |
|
1559 | IssueCustomField.delete_all | |
1574 |
|
1560 | |||
1575 | i = Issue.first |
|
1561 | i = Issue.first | |
1576 | old_description = i.description |
|
1562 | old_description = i.description | |
1577 | new_description = "This is the new description" |
|
1563 | new_description = "This is the new description" | |
1578 |
|
1564 | |||
1579 | i.init_journal(User.find(2)) |
|
1565 | i.init_journal(User.find(2)) | |
1580 | i.description = new_description |
|
1566 | i.description = new_description | |
1581 | assert_difference 'Journal.count', 1 do |
|
1567 | assert_difference 'Journal.count', 1 do | |
1582 | assert_difference 'JournalDetail.count', 1 do |
|
1568 | assert_difference 'JournalDetail.count', 1 do | |
1583 | i.save! |
|
1569 | i.save! | |
1584 | end |
|
1570 | end | |
1585 | end |
|
1571 | end | |
1586 |
|
1572 | |||
1587 | detail = JournalDetail.first(:order => 'id DESC') |
|
1573 | detail = JournalDetail.first(:order => 'id DESC') | |
1588 | assert_equal i, detail.journal.journalized |
|
1574 | assert_equal i, detail.journal.journalized | |
1589 | assert_equal 'attr', detail.property |
|
1575 | assert_equal 'attr', detail.property | |
1590 | assert_equal 'description', detail.prop_key |
|
1576 | assert_equal 'description', detail.prop_key | |
1591 | assert_equal old_description, detail.old_value |
|
1577 | assert_equal old_description, detail.old_value | |
1592 | assert_equal new_description, detail.value |
|
1578 | assert_equal new_description, detail.value | |
1593 | end |
|
1579 | end | |
1594 |
|
1580 | |||
1595 | def test_blank_descriptions_should_not_be_journalized |
|
1581 | def test_blank_descriptions_should_not_be_journalized | |
1596 | IssueCustomField.delete_all |
|
1582 | IssueCustomField.delete_all | |
1597 | Issue.update_all("description = NULL", "id=1") |
|
1583 | Issue.update_all("description = NULL", "id=1") | |
1598 |
|
1584 | |||
1599 | i = Issue.find(1) |
|
1585 | i = Issue.find(1) | |
1600 | i.init_journal(User.find(2)) |
|
1586 | i.init_journal(User.find(2)) | |
1601 | i.subject = "blank description" |
|
1587 | i.subject = "blank description" | |
1602 | i.description = "\r\n" |
|
1588 | i.description = "\r\n" | |
1603 |
|
1589 | |||
1604 | assert_difference 'Journal.count', 1 do |
|
1590 | assert_difference 'Journal.count', 1 do | |
1605 | assert_difference 'JournalDetail.count', 1 do |
|
1591 | assert_difference 'JournalDetail.count', 1 do | |
1606 | i.save! |
|
1592 | i.save! | |
1607 | end |
|
1593 | end | |
1608 | end |
|
1594 | end | |
1609 | end |
|
1595 | end | |
1610 |
|
1596 | |||
1611 | def test_journalized_multi_custom_field |
|
1597 | def test_journalized_multi_custom_field | |
1612 | field = IssueCustomField.create!(:name => 'filter', :field_format => 'list', |
|
1598 | field = IssueCustomField.create!(:name => 'filter', :field_format => 'list', | |
1613 | :is_filter => true, :is_for_all => true, |
|
1599 | :is_filter => true, :is_for_all => true, | |
1614 | :tracker_ids => [1], |
|
1600 | :tracker_ids => [1], | |
1615 | :possible_values => ['value1', 'value2', 'value3'], |
|
1601 | :possible_values => ['value1', 'value2', 'value3'], | |
1616 | :multiple => true) |
|
1602 | :multiple => true) | |
1617 |
|
1603 | |||
1618 | issue = Issue.create!(:project_id => 1, :tracker_id => 1, |
|
1604 | issue = Issue.create!(:project_id => 1, :tracker_id => 1, | |
1619 | :subject => 'Test', :author_id => 1) |
|
1605 | :subject => 'Test', :author_id => 1) | |
1620 |
|
1606 | |||
1621 | assert_difference 'Journal.count' do |
|
1607 | assert_difference 'Journal.count' do | |
1622 | assert_difference 'JournalDetail.count' do |
|
1608 | assert_difference 'JournalDetail.count' do | |
1623 | issue.init_journal(User.first) |
|
1609 | issue.init_journal(User.first) | |
1624 | issue.custom_field_values = {field.id => ['value1']} |
|
1610 | issue.custom_field_values = {field.id => ['value1']} | |
1625 | issue.save! |
|
1611 | issue.save! | |
1626 | end |
|
1612 | end | |
1627 | assert_difference 'JournalDetail.count' do |
|
1613 | assert_difference 'JournalDetail.count' do | |
1628 | issue.init_journal(User.first) |
|
1614 | issue.init_journal(User.first) | |
1629 | issue.custom_field_values = {field.id => ['value1', 'value2']} |
|
1615 | issue.custom_field_values = {field.id => ['value1', 'value2']} | |
1630 | issue.save! |
|
1616 | issue.save! | |
1631 | end |
|
1617 | end | |
1632 | assert_difference 'JournalDetail.count', 2 do |
|
1618 | assert_difference 'JournalDetail.count', 2 do | |
1633 | issue.init_journal(User.first) |
|
1619 | issue.init_journal(User.first) | |
1634 | issue.custom_field_values = {field.id => ['value3', 'value2']} |
|
1620 | issue.custom_field_values = {field.id => ['value3', 'value2']} | |
1635 | issue.save! |
|
1621 | issue.save! | |
1636 | end |
|
1622 | end | |
1637 | assert_difference 'JournalDetail.count', 2 do |
|
1623 | assert_difference 'JournalDetail.count', 2 do | |
1638 | issue.init_journal(User.first) |
|
1624 | issue.init_journal(User.first) | |
1639 | issue.custom_field_values = {field.id => nil} |
|
1625 | issue.custom_field_values = {field.id => nil} | |
1640 | issue.save! |
|
1626 | issue.save! | |
1641 | end |
|
1627 | end | |
1642 | end |
|
1628 | end | |
1643 | end |
|
1629 | end | |
1644 |
|
1630 | |||
1645 | def test_description_eol_should_be_normalized |
|
1631 | def test_description_eol_should_be_normalized | |
1646 | i = Issue.new(:description => "CR \r LF \n CRLF \r\n") |
|
1632 | i = Issue.new(:description => "CR \r LF \n CRLF \r\n") | |
1647 | assert_equal "CR \r\n LF \r\n CRLF \r\n", i.description |
|
1633 | assert_equal "CR \r\n LF \r\n CRLF \r\n", i.description | |
1648 | end |
|
1634 | end | |
1649 |
|
1635 | |||
1650 | def test_saving_twice_should_not_duplicate_journal_details |
|
1636 | def test_saving_twice_should_not_duplicate_journal_details | |
1651 | i = Issue.first |
|
1637 | i = Issue.first | |
1652 | i.init_journal(User.find(2), 'Some notes') |
|
1638 | i.init_journal(User.find(2), 'Some notes') | |
1653 | # initial changes |
|
1639 | # initial changes | |
1654 | i.subject = 'New subject' |
|
1640 | i.subject = 'New subject' | |
1655 | i.done_ratio = i.done_ratio + 10 |
|
1641 | i.done_ratio = i.done_ratio + 10 | |
1656 | assert_difference 'Journal.count' do |
|
1642 | assert_difference 'Journal.count' do | |
1657 | assert i.save |
|
1643 | assert i.save | |
1658 | end |
|
1644 | end | |
1659 | # 1 more change |
|
1645 | # 1 more change | |
1660 | i.priority = IssuePriority.where("id <> ?", i.priority_id).first |
|
1646 | i.priority = IssuePriority.where("id <> ?", i.priority_id).first | |
1661 | assert_no_difference 'Journal.count' do |
|
1647 | assert_no_difference 'Journal.count' do | |
1662 | assert_difference 'JournalDetail.count', 1 do |
|
1648 | assert_difference 'JournalDetail.count', 1 do | |
1663 | i.save |
|
1649 | i.save | |
1664 | end |
|
1650 | end | |
1665 | end |
|
1651 | end | |
1666 | # no more change |
|
1652 | # no more change | |
1667 | assert_no_difference 'Journal.count' do |
|
1653 | assert_no_difference 'Journal.count' do | |
1668 | assert_no_difference 'JournalDetail.count' do |
|
1654 | assert_no_difference 'JournalDetail.count' do | |
1669 | i.save |
|
1655 | i.save | |
1670 | end |
|
1656 | end | |
1671 | end |
|
1657 | end | |
1672 | end |
|
1658 | end | |
1673 |
|
1659 | |||
1674 | def test_all_dependent_issues |
|
1660 | def test_all_dependent_issues | |
1675 | IssueRelation.delete_all |
|
1661 | IssueRelation.delete_all | |
1676 | assert IssueRelation.create!(:issue_from => Issue.find(1), |
|
1662 | assert IssueRelation.create!(:issue_from => Issue.find(1), | |
1677 | :issue_to => Issue.find(2), |
|
1663 | :issue_to => Issue.find(2), | |
1678 | :relation_type => IssueRelation::TYPE_PRECEDES) |
|
1664 | :relation_type => IssueRelation::TYPE_PRECEDES) | |
1679 | assert IssueRelation.create!(:issue_from => Issue.find(2), |
|
1665 | assert IssueRelation.create!(:issue_from => Issue.find(2), | |
1680 | :issue_to => Issue.find(3), |
|
1666 | :issue_to => Issue.find(3), | |
1681 | :relation_type => IssueRelation::TYPE_PRECEDES) |
|
1667 | :relation_type => IssueRelation::TYPE_PRECEDES) | |
1682 | assert IssueRelation.create!(:issue_from => Issue.find(3), |
|
1668 | assert IssueRelation.create!(:issue_from => Issue.find(3), | |
1683 | :issue_to => Issue.find(8), |
|
1669 | :issue_to => Issue.find(8), | |
1684 | :relation_type => IssueRelation::TYPE_PRECEDES) |
|
1670 | :relation_type => IssueRelation::TYPE_PRECEDES) | |
1685 |
|
1671 | |||
1686 | assert_equal [2, 3, 8], Issue.find(1).all_dependent_issues.collect(&:id).sort |
|
1672 | assert_equal [2, 3, 8], Issue.find(1).all_dependent_issues.collect(&:id).sort | |
1687 | end |
|
1673 | end | |
1688 |
|
1674 | |||
1689 | def test_all_dependent_issues_with_persistent_circular_dependency |
|
1675 | def test_all_dependent_issues_with_persistent_circular_dependency | |
1690 | IssueRelation.delete_all |
|
1676 | IssueRelation.delete_all | |
1691 | assert IssueRelation.create!(:issue_from => Issue.find(1), |
|
1677 | assert IssueRelation.create!(:issue_from => Issue.find(1), | |
1692 | :issue_to => Issue.find(2), |
|
1678 | :issue_to => Issue.find(2), | |
1693 | :relation_type => IssueRelation::TYPE_PRECEDES) |
|
1679 | :relation_type => IssueRelation::TYPE_PRECEDES) | |
1694 | assert IssueRelation.create!(:issue_from => Issue.find(2), |
|
1680 | assert IssueRelation.create!(:issue_from => Issue.find(2), | |
1695 | :issue_to => Issue.find(3), |
|
1681 | :issue_to => Issue.find(3), | |
1696 | :relation_type => IssueRelation::TYPE_PRECEDES) |
|
1682 | :relation_type => IssueRelation::TYPE_PRECEDES) | |
1697 |
|
1683 | |||
1698 | r = IssueRelation.create!(:issue_from => Issue.find(3), |
|
1684 | r = IssueRelation.create!(:issue_from => Issue.find(3), | |
1699 | :issue_to => Issue.find(7), |
|
1685 | :issue_to => Issue.find(7), | |
1700 | :relation_type => IssueRelation::TYPE_PRECEDES) |
|
1686 | :relation_type => IssueRelation::TYPE_PRECEDES) | |
1701 | IssueRelation.update_all("issue_to_id = 1", ["id = ?", r.id]) |
|
1687 | IssueRelation.update_all("issue_to_id = 1", ["id = ?", r.id]) | |
1702 |
|
1688 | |||
1703 | assert_equal [2, 3], Issue.find(1).all_dependent_issues.collect(&:id).sort |
|
1689 | assert_equal [2, 3], Issue.find(1).all_dependent_issues.collect(&:id).sort | |
1704 | end |
|
1690 | end | |
1705 |
|
1691 | |||
1706 | def test_all_dependent_issues_with_persistent_multiple_circular_dependencies |
|
1692 | def test_all_dependent_issues_with_persistent_multiple_circular_dependencies | |
1707 | IssueRelation.delete_all |
|
1693 | IssueRelation.delete_all | |
1708 | assert IssueRelation.create!(:issue_from => Issue.find(1), |
|
1694 | assert IssueRelation.create!(:issue_from => Issue.find(1), | |
1709 | :issue_to => Issue.find(2), |
|
1695 | :issue_to => Issue.find(2), | |
1710 | :relation_type => IssueRelation::TYPE_RELATES) |
|
1696 | :relation_type => IssueRelation::TYPE_RELATES) | |
1711 | assert IssueRelation.create!(:issue_from => Issue.find(2), |
|
1697 | assert IssueRelation.create!(:issue_from => Issue.find(2), | |
1712 | :issue_to => Issue.find(3), |
|
1698 | :issue_to => Issue.find(3), | |
1713 | :relation_type => IssueRelation::TYPE_RELATES) |
|
1699 | :relation_type => IssueRelation::TYPE_RELATES) | |
1714 | assert IssueRelation.create!(:issue_from => Issue.find(3), |
|
1700 | assert IssueRelation.create!(:issue_from => Issue.find(3), | |
1715 | :issue_to => Issue.find(8), |
|
1701 | :issue_to => Issue.find(8), | |
1716 | :relation_type => IssueRelation::TYPE_RELATES) |
|
1702 | :relation_type => IssueRelation::TYPE_RELATES) | |
1717 |
|
1703 | |||
1718 | r = IssueRelation.create!(:issue_from => Issue.find(8), |
|
1704 | r = IssueRelation.create!(:issue_from => Issue.find(8), | |
1719 | :issue_to => Issue.find(7), |
|
1705 | :issue_to => Issue.find(7), | |
1720 | :relation_type => IssueRelation::TYPE_RELATES) |
|
1706 | :relation_type => IssueRelation::TYPE_RELATES) | |
1721 | IssueRelation.update_all("issue_to_id = 2", ["id = ?", r.id]) |
|
1707 | IssueRelation.update_all("issue_to_id = 2", ["id = ?", r.id]) | |
1722 |
|
1708 | |||
1723 | r = IssueRelation.create!(:issue_from => Issue.find(3), |
|
1709 | r = IssueRelation.create!(:issue_from => Issue.find(3), | |
1724 | :issue_to => Issue.find(7), |
|
1710 | :issue_to => Issue.find(7), | |
1725 | :relation_type => IssueRelation::TYPE_RELATES) |
|
1711 | :relation_type => IssueRelation::TYPE_RELATES) | |
1726 | IssueRelation.update_all("issue_to_id = 1", ["id = ?", r.id]) |
|
1712 | IssueRelation.update_all("issue_to_id = 1", ["id = ?", r.id]) | |
1727 |
|
1713 | |||
1728 | assert_equal [2, 3, 8], Issue.find(1).all_dependent_issues.collect(&:id).sort |
|
1714 | assert_equal [2, 3, 8], Issue.find(1).all_dependent_issues.collect(&:id).sort | |
1729 | end |
|
1715 | end | |
1730 |
|
1716 | |||
1731 | context "#done_ratio" do |
|
1717 | test "#done_ratio should use the issue_status according to Setting.issue_done_ratio" do | |
1732 | setup do |
|
|||
1733 |
|
|
1718 | @issue = Issue.find(1) | |
1734 |
|
|
1719 | @issue_status = IssueStatus.find(1) | |
1735 |
|
|
1720 | @issue_status.update_attribute(:default_done_ratio, 50) | |
1736 |
|
|
1721 | @issue2 = Issue.find(2) | |
1737 |
|
|
1722 | @issue_status2 = IssueStatus.find(2) | |
1738 |
|
|
1723 | @issue_status2.update_attribute(:default_done_ratio, 0) | |
1739 | end |
|
|||
1740 |
|
||||
1741 | teardown do |
|
|||
1742 | Setting.issue_done_ratio = 'issue_field' |
|
|||
1743 | end |
|
|||
1744 |
|
||||
1745 | context "with Setting.issue_done_ratio using the issue_field" do |
|
|||
1746 | setup do |
|
|||
1747 | Setting.issue_done_ratio = 'issue_field' |
|
|||
1748 | end |
|
|||
1749 |
|
1724 | |||
1750 | should "read the issue's field" do |
|
1725 | with_settings :issue_done_ratio => 'issue_field' do | |
1751 |
|
|
1726 | assert_equal 0, @issue.done_ratio | |
1752 |
|
|
1727 | assert_equal 30, @issue2.done_ratio | |
1753 |
|
|
1728 | end | |
1754 | end |
|
|||
1755 |
|
||||
1756 | context "with Setting.issue_done_ratio using the issue_status" do |
|
|||
1757 | setup do |
|
|||
1758 | Setting.issue_done_ratio = 'issue_status' |
|
|||
1759 | end |
|
|||
1760 |
|
1729 | |||
1761 | should "read the Issue Status's default done ratio" do |
|
1730 | with_settings :issue_done_ratio => 'issue_status' do | |
1762 |
|
|
1731 | assert_equal 50, @issue.done_ratio | |
1763 |
|
|
1732 | assert_equal 0, @issue2.done_ratio | |
1764 |
|
|
1733 | end | |
1765 |
|
|
1734 | end | |
1766 | end |
|
|||
1767 |
|
1735 | |||
1768 | context "#update_done_ratio_from_issue_status" do |
|
1736 | test "#update_done_ratio_from_issue_status should update done_ratio according to Setting.issue_done_ratio" do | |
1769 | setup do |
|
|||
1770 |
|
|
1737 | @issue = Issue.find(1) | |
1771 |
|
|
1738 | @issue_status = IssueStatus.find(1) | |
1772 |
|
|
1739 | @issue_status.update_attribute(:default_done_ratio, 50) | |
1773 |
|
|
1740 | @issue2 = Issue.find(2) | |
1774 |
|
|
1741 | @issue_status2 = IssueStatus.find(2) | |
1775 |
|
|
1742 | @issue_status2.update_attribute(:default_done_ratio, 0) | |
1776 | end |
|
|||
1777 |
|
||||
1778 | context "with Setting.issue_done_ratio using the issue_field" do |
|
|||
1779 | setup do |
|
|||
1780 | Setting.issue_done_ratio = 'issue_field' |
|
|||
1781 | end |
|
|||
1782 |
|
1743 | |||
1783 | should "not change the issue" do |
|
1744 | with_settings :issue_done_ratio => 'issue_field' do | |
1784 |
|
|
1745 | @issue.update_done_ratio_from_issue_status | |
1785 |
|
|
1746 | @issue2.update_done_ratio_from_issue_status | |
1786 |
|
1747 | |||
1787 |
|
|
1748 | assert_equal 0, @issue.read_attribute(:done_ratio) | |
1788 |
|
|
1749 | assert_equal 30, @issue2.read_attribute(:done_ratio) | |
1789 |
|
|
1750 | end | |
1790 | end |
|
|||
1791 |
|
||||
1792 | context "with Setting.issue_done_ratio using the issue_status" do |
|
|||
1793 | setup do |
|
|||
1794 | Setting.issue_done_ratio = 'issue_status' |
|
|||
1795 | end |
|
|||
1796 |
|
1751 | |||
1797 | should "change the issue's done ratio" do |
|
1752 | with_settings :issue_done_ratio => 'issue_status' do | |
1798 |
|
|
1753 | @issue.update_done_ratio_from_issue_status | |
1799 |
|
|
1754 | @issue2.update_done_ratio_from_issue_status | |
1800 |
|
1755 | |||
1801 |
|
|
1756 | assert_equal 50, @issue.read_attribute(:done_ratio) | |
1802 |
|
|
1757 | assert_equal 0, @issue2.read_attribute(:done_ratio) | |
1803 |
|
|
1758 | end | |
1804 |
|
|
1759 | end | |
1805 | end |
|
|||
1806 |
|
1760 | |||
1807 | test "#by_tracker" do |
|
1761 | test "#by_tracker" do | |
1808 | User.current = User.anonymous |
|
1762 | User.current = User.anonymous | |
1809 | groups = Issue.by_tracker(Project.find(1)) |
|
1763 | groups = Issue.by_tracker(Project.find(1)) | |
1810 | assert_equal 3, groups.size |
|
1764 | assert_equal 3, groups.size | |
1811 | assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i} |
|
1765 | assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i} | |
1812 | end |
|
1766 | end | |
1813 |
|
1767 | |||
1814 | test "#by_version" do |
|
1768 | test "#by_version" do | |
1815 | User.current = User.anonymous |
|
1769 | User.current = User.anonymous | |
1816 | groups = Issue.by_version(Project.find(1)) |
|
1770 | groups = Issue.by_version(Project.find(1)) | |
1817 | assert_equal 3, groups.size |
|
1771 | assert_equal 3, groups.size | |
1818 | assert_equal 3, groups.inject(0) {|sum, group| sum + group['total'].to_i} |
|
1772 | assert_equal 3, groups.inject(0) {|sum, group| sum + group['total'].to_i} | |
1819 | end |
|
1773 | end | |
1820 |
|
1774 | |||
1821 | test "#by_priority" do |
|
1775 | test "#by_priority" do | |
1822 | User.current = User.anonymous |
|
1776 | User.current = User.anonymous | |
1823 | groups = Issue.by_priority(Project.find(1)) |
|
1777 | groups = Issue.by_priority(Project.find(1)) | |
1824 | assert_equal 4, groups.size |
|
1778 | assert_equal 4, groups.size | |
1825 | assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i} |
|
1779 | assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i} | |
1826 | end |
|
1780 | end | |
1827 |
|
1781 | |||
1828 | test "#by_category" do |
|
1782 | test "#by_category" do | |
1829 | User.current = User.anonymous |
|
1783 | User.current = User.anonymous | |
1830 | groups = Issue.by_category(Project.find(1)) |
|
1784 | groups = Issue.by_category(Project.find(1)) | |
1831 | assert_equal 2, groups.size |
|
1785 | assert_equal 2, groups.size | |
1832 | assert_equal 3, groups.inject(0) {|sum, group| sum + group['total'].to_i} |
|
1786 | assert_equal 3, groups.inject(0) {|sum, group| sum + group['total'].to_i} | |
1833 | end |
|
1787 | end | |
1834 |
|
1788 | |||
1835 | test "#by_assigned_to" do |
|
1789 | test "#by_assigned_to" do | |
1836 | User.current = User.anonymous |
|
1790 | User.current = User.anonymous | |
1837 | groups = Issue.by_assigned_to(Project.find(1)) |
|
1791 | groups = Issue.by_assigned_to(Project.find(1)) | |
1838 | assert_equal 2, groups.size |
|
1792 | assert_equal 2, groups.size | |
1839 | assert_equal 2, groups.inject(0) {|sum, group| sum + group['total'].to_i} |
|
1793 | assert_equal 2, groups.inject(0) {|sum, group| sum + group['total'].to_i} | |
1840 | end |
|
1794 | end | |
1841 |
|
1795 | |||
1842 | test "#by_author" do |
|
1796 | test "#by_author" do | |
1843 | User.current = User.anonymous |
|
1797 | User.current = User.anonymous | |
1844 | groups = Issue.by_author(Project.find(1)) |
|
1798 | groups = Issue.by_author(Project.find(1)) | |
1845 | assert_equal 4, groups.size |
|
1799 | assert_equal 4, groups.size | |
1846 | assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i} |
|
1800 | assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i} | |
1847 | end |
|
1801 | end | |
1848 |
|
1802 | |||
1849 | test "#by_subproject" do |
|
1803 | test "#by_subproject" do | |
1850 | User.current = User.anonymous |
|
1804 | User.current = User.anonymous | |
1851 | groups = Issue.by_subproject(Project.find(1)) |
|
1805 | groups = Issue.by_subproject(Project.find(1)) | |
1852 | # Private descendant not visible |
|
1806 | # Private descendant not visible | |
1853 | assert_equal 1, groups.size |
|
1807 | assert_equal 1, groups.size | |
1854 | assert_equal 2, groups.inject(0) {|sum, group| sum + group['total'].to_i} |
|
1808 | assert_equal 2, groups.inject(0) {|sum, group| sum + group['total'].to_i} | |
1855 | end |
|
1809 | end | |
1856 |
|
1810 | |||
1857 | def test_recently_updated_scope |
|
1811 | def test_recently_updated_scope | |
1858 | #should return the last updated issue |
|
1812 | #should return the last updated issue | |
1859 | assert_equal Issue.reorder("updated_on DESC").first, Issue.recently_updated.limit(1).first |
|
1813 | assert_equal Issue.reorder("updated_on DESC").first, Issue.recently_updated.limit(1).first | |
1860 | end |
|
1814 | end | |
1861 |
|
1815 | |||
1862 | def test_on_active_projects_scope |
|
1816 | def test_on_active_projects_scope | |
1863 | assert Project.find(2).archive |
|
1817 | assert Project.find(2).archive | |
1864 |
|
1818 | |||
1865 | before = Issue.on_active_project.length |
|
1819 | before = Issue.on_active_project.length | |
1866 | # test inclusion to results |
|
1820 | # test inclusion to results | |
1867 | issue = Issue.generate!(:tracker => Project.find(2).trackers.first) |
|
1821 | issue = Issue.generate!(:tracker => Project.find(2).trackers.first) | |
1868 | assert_equal before + 1, Issue.on_active_project.length |
|
1822 | assert_equal before + 1, Issue.on_active_project.length | |
1869 |
|
1823 | |||
1870 | # Move to an archived project |
|
1824 | # Move to an archived project | |
1871 | issue.project = Project.find(2) |
|
1825 | issue.project = Project.find(2) | |
1872 | assert issue.save |
|
1826 | assert issue.save | |
1873 | assert_equal before, Issue.on_active_project.length |
|
1827 | assert_equal before, Issue.on_active_project.length | |
1874 | end |
|
1828 | end | |
1875 |
|
1829 | |||
1876 | context "Issue#recipients" do |
|
1830 | test "Issue#recipients should include project recipients" do | |
1877 | setup do |
|
1831 | issue = Issue.generate! | |
1878 | @project = Project.find(1) |
|
1832 | assert issue.project.recipients.present? | |
1879 | @author = User.generate! |
|
1833 | issue.project.recipients.each do |project_recipient| | |
1880 | @assignee = User.generate! |
|
1834 | assert issue.recipients.include?(project_recipient) | |
1881 | @issue = Issue.generate!(:project => @project, :assigned_to => @assignee, :author => @author) |
|
|||
1882 | end |
|
|||
1883 |
|
||||
1884 | should "include project recipients" do |
|
|||
1885 | assert @project.recipients.present? |
|
|||
1886 | @project.recipients.each do |project_recipient| |
|
|||
1887 | assert @issue.recipients.include?(project_recipient) |
|
|||
1888 |
|
|
1835 | end | |
1889 |
|
|
1836 | end | |
1890 |
|
1837 | |||
1891 |
|
|
1838 | test "Issue#recipients should include the author if the author is active" do | |
1892 | assert @issue.author, "No author set for Issue" |
|
1839 | issue = Issue.generate!(:author => User.generate!) | |
1893 | assert @issue.recipients.include?(@issue.author.mail) |
|
1840 | assert issue.author, "No author set for Issue" | |
|
1841 | assert issue.recipients.include?(issue.author.mail) | |||
1894 |
|
|
1842 | end | |
1895 |
|
1843 | |||
1896 |
|
|
1844 | test "Issue#recipients should include the assigned to user if the assigned to user is active" do | |
1897 | assert @issue.assigned_to, "No assigned_to set for Issue" |
|
1845 | issue = Issue.generate!(:assigned_to => User.generate!) | |
1898 | assert @issue.recipients.include?(@issue.assigned_to.mail) |
|
1846 | assert issue.assigned_to, "No assigned_to set for Issue" | |
|
1847 | assert issue.recipients.include?(issue.assigned_to.mail) | |||
1899 |
|
|
1848 | end | |
1900 |
|
1849 | |||
1901 |
|
|
1850 | test "Issue#recipients should not include users who opt out of all email" do | |
1902 | @author.update_attribute(:mail_notification, :none) |
|
1851 | issue = Issue.generate!(:author => User.generate!) | |
1903 |
|
1852 | issue.author.update_attribute(:mail_notification, :none) | ||
1904 |
|
|
1853 | assert !issue.recipients.include?(issue.author.mail) | |
1905 |
|
|
1854 | end | |
1906 |
|
1855 | |||
1907 |
|
|
1856 | test "Issue#recipients should not include the issue author if they are only notified of assigned issues" do | |
1908 | @author.update_attribute(:mail_notification, :only_assigned) |
|
1857 | issue = Issue.generate!(:author => User.generate!) | |
1909 |
|
1858 | issue.author.update_attribute(:mail_notification, :only_assigned) | ||
1910 |
|
|
1859 | assert !issue.recipients.include?(issue.author.mail) | |
1911 |
|
|
1860 | end | |
1912 |
|
1861 | |||
1913 |
|
|
1862 | test "Issue#recipients should not include the assigned user if they are only notified of owned issues" do | |
1914 | @assignee.update_attribute(:mail_notification, :only_owner) |
|
1863 | issue = Issue.generate!(:assigned_to => User.generate!) | |
1915 |
|
1864 | issue.assigned_to.update_attribute(:mail_notification, :only_owner) | ||
1916 |
|
|
1865 | assert !issue.recipients.include?(issue.assigned_to.mail) | |
1917 | end |
|
|||
1918 | end |
|
1866 | end | |
1919 |
|
1867 | |||
1920 | def test_last_journal_id_with_journals_should_return_the_journal_id |
|
1868 | def test_last_journal_id_with_journals_should_return_the_journal_id | |
1921 | assert_equal 2, Issue.find(1).last_journal_id |
|
1869 | assert_equal 2, Issue.find(1).last_journal_id | |
1922 | end |
|
1870 | end | |
1923 |
|
1871 | |||
1924 | def test_last_journal_id_without_journals_should_return_nil |
|
1872 | def test_last_journal_id_without_journals_should_return_nil | |
1925 | assert_nil Issue.find(3).last_journal_id |
|
1873 | assert_nil Issue.find(3).last_journal_id | |
1926 | end |
|
1874 | end | |
1927 |
|
1875 | |||
1928 | def test_journals_after_should_return_journals_with_greater_id |
|
1876 | def test_journals_after_should_return_journals_with_greater_id | |
1929 | assert_equal [Journal.find(2)], Issue.find(1).journals_after('1') |
|
1877 | assert_equal [Journal.find(2)], Issue.find(1).journals_after('1') | |
1930 | assert_equal [], Issue.find(1).journals_after('2') |
|
1878 | assert_equal [], Issue.find(1).journals_after('2') | |
1931 | end |
|
1879 | end | |
1932 |
|
1880 | |||
1933 | def test_journals_after_with_blank_arg_should_return_all_journals |
|
1881 | def test_journals_after_with_blank_arg_should_return_all_journals | |
1934 | assert_equal [Journal.find(1), Journal.find(2)], Issue.find(1).journals_after('') |
|
1882 | assert_equal [Journal.find(1), Journal.find(2)], Issue.find(1).journals_after('') | |
1935 | end |
|
1883 | end | |
1936 |
|
1884 | |||
1937 | def test_css_classes_should_include_priority |
|
1885 | def test_css_classes_should_include_priority | |
1938 | issue = Issue.new(:priority => IssuePriority.find(8)) |
|
1886 | issue = Issue.new(:priority => IssuePriority.find(8)) | |
1939 | classes = issue.css_classes.split(' ') |
|
1887 | classes = issue.css_classes.split(' ') | |
1940 | assert_include 'priority-8', classes |
|
1888 | assert_include 'priority-8', classes | |
1941 | assert_include 'priority-highest', classes |
|
1889 | assert_include 'priority-highest', classes | |
1942 | end |
|
1890 | end | |
1943 |
|
1891 | |||
1944 | def test_save_attachments_with_hash_should_save_attachments_in_keys_order |
|
1892 | def test_save_attachments_with_hash_should_save_attachments_in_keys_order | |
1945 | set_tmp_attachments_directory |
|
1893 | set_tmp_attachments_directory | |
1946 | issue = Issue.generate! |
|
1894 | issue = Issue.generate! | |
1947 | issue.save_attachments({ |
|
1895 | issue.save_attachments({ | |
1948 | 'p0' => {'file' => mock_file_with_options(:original_filename => 'upload')}, |
|
1896 | 'p0' => {'file' => mock_file_with_options(:original_filename => 'upload')}, | |
1949 | '3' => {'file' => mock_file_with_options(:original_filename => 'bar')}, |
|
1897 | '3' => {'file' => mock_file_with_options(:original_filename => 'bar')}, | |
1950 | '1' => {'file' => mock_file_with_options(:original_filename => 'foo')} |
|
1898 | '1' => {'file' => mock_file_with_options(:original_filename => 'foo')} | |
1951 | }) |
|
1899 | }) | |
1952 | issue.attach_saved_attachments |
|
1900 | issue.attach_saved_attachments | |
1953 |
|
1901 | |||
1954 | assert_equal 3, issue.reload.attachments.count |
|
1902 | assert_equal 3, issue.reload.attachments.count | |
1955 | assert_equal %w(upload foo bar), issue.attachments.map(&:filename) |
|
1903 | assert_equal %w(upload foo bar), issue.attachments.map(&:filename) | |
1956 | end |
|
1904 | end | |
1957 | end |
|
1905 | end |
@@ -1,794 +1,776 | |||||
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 MailHandlerTest < ActiveSupport::TestCase |
|
22 | class MailHandlerTest < ActiveSupport::TestCase | |
23 | fixtures :users, :projects, :enabled_modules, :roles, |
|
23 | fixtures :users, :projects, :enabled_modules, :roles, | |
24 | :members, :member_roles, :users, |
|
24 | :members, :member_roles, :users, | |
25 | :issues, :issue_statuses, |
|
25 | :issues, :issue_statuses, | |
26 | :workflows, :trackers, :projects_trackers, |
|
26 | :workflows, :trackers, :projects_trackers, | |
27 | :versions, :enumerations, :issue_categories, |
|
27 | :versions, :enumerations, :issue_categories, | |
28 | :custom_fields, :custom_fields_trackers, :custom_fields_projects, |
|
28 | :custom_fields, :custom_fields_trackers, :custom_fields_projects, | |
29 | :boards, :messages |
|
29 | :boards, :messages | |
30 |
|
30 | |||
31 | FIXTURES_PATH = File.dirname(__FILE__) + '/../fixtures/mail_handler' |
|
31 | FIXTURES_PATH = File.dirname(__FILE__) + '/../fixtures/mail_handler' | |
32 |
|
32 | |||
33 | def setup |
|
33 | def setup | |
34 | ActionMailer::Base.deliveries.clear |
|
34 | ActionMailer::Base.deliveries.clear | |
35 | Setting.notified_events = Redmine::Notifiable.all.collect(&:name) |
|
35 | Setting.notified_events = Redmine::Notifiable.all.collect(&:name) | |
36 | end |
|
36 | end | |
37 |
|
37 | |||
38 | def teardown |
|
38 | def teardown | |
39 | Setting.clear_cache |
|
39 | Setting.clear_cache | |
40 | end |
|
40 | end | |
41 |
|
41 | |||
42 | def test_add_issue |
|
42 | def test_add_issue | |
43 | ActionMailer::Base.deliveries.clear |
|
43 | ActionMailer::Base.deliveries.clear | |
44 | # This email contains: 'Project: onlinestore' |
|
44 | # This email contains: 'Project: onlinestore' | |
45 | issue = submit_email('ticket_on_given_project.eml') |
|
45 | issue = submit_email('ticket_on_given_project.eml') | |
46 | assert issue.is_a?(Issue) |
|
46 | assert issue.is_a?(Issue) | |
47 | assert !issue.new_record? |
|
47 | assert !issue.new_record? | |
48 | issue.reload |
|
48 | issue.reload | |
49 | assert_equal Project.find(2), issue.project |
|
49 | assert_equal Project.find(2), issue.project | |
50 | assert_equal issue.project.trackers.first, issue.tracker |
|
50 | assert_equal issue.project.trackers.first, issue.tracker | |
51 | assert_equal 'New ticket on a given project', issue.subject |
|
51 | assert_equal 'New ticket on a given project', issue.subject | |
52 | assert_equal User.find_by_login('jsmith'), issue.author |
|
52 | assert_equal User.find_by_login('jsmith'), issue.author | |
53 | assert_equal IssueStatus.find_by_name('Resolved'), issue.status |
|
53 | assert_equal IssueStatus.find_by_name('Resolved'), issue.status | |
54 | assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.') |
|
54 | assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.') | |
55 | assert_equal '2010-01-01', issue.start_date.to_s |
|
55 | assert_equal '2010-01-01', issue.start_date.to_s | |
56 | assert_equal '2010-12-31', issue.due_date.to_s |
|
56 | assert_equal '2010-12-31', issue.due_date.to_s | |
57 | assert_equal User.find_by_login('jsmith'), issue.assigned_to |
|
57 | assert_equal User.find_by_login('jsmith'), issue.assigned_to | |
58 | assert_equal Version.find_by_name('Alpha'), issue.fixed_version |
|
58 | assert_equal Version.find_by_name('Alpha'), issue.fixed_version | |
59 | assert_equal 2.5, issue.estimated_hours |
|
59 | assert_equal 2.5, issue.estimated_hours | |
60 | assert_equal 30, issue.done_ratio |
|
60 | assert_equal 30, issue.done_ratio | |
61 | assert_equal [issue.id, 1, 2], [issue.root_id, issue.lft, issue.rgt] |
|
61 | assert_equal [issue.id, 1, 2], [issue.root_id, issue.lft, issue.rgt] | |
62 | # keywords should be removed from the email body |
|
62 | # keywords should be removed from the email body | |
63 | assert !issue.description.match(/^Project:/i) |
|
63 | assert !issue.description.match(/^Project:/i) | |
64 | assert !issue.description.match(/^Status:/i) |
|
64 | assert !issue.description.match(/^Status:/i) | |
65 | assert !issue.description.match(/^Start Date:/i) |
|
65 | assert !issue.description.match(/^Start Date:/i) | |
66 | # Email notification should be sent |
|
66 | # Email notification should be sent | |
67 | mail = ActionMailer::Base.deliveries.last |
|
67 | mail = ActionMailer::Base.deliveries.last | |
68 | assert_not_nil mail |
|
68 | assert_not_nil mail | |
69 | assert mail.subject.include?('New ticket on a given project') |
|
69 | assert mail.subject.include?('New ticket on a given project') | |
70 | end |
|
70 | end | |
71 |
|
71 | |||
72 | def test_add_issue_with_default_tracker |
|
72 | def test_add_issue_with_default_tracker | |
73 | # This email contains: 'Project: onlinestore' |
|
73 | # This email contains: 'Project: onlinestore' | |
74 | issue = submit_email( |
|
74 | issue = submit_email( | |
75 | 'ticket_on_given_project.eml', |
|
75 | 'ticket_on_given_project.eml', | |
76 | :issue => {:tracker => 'Support request'} |
|
76 | :issue => {:tracker => 'Support request'} | |
77 | ) |
|
77 | ) | |
78 | assert issue.is_a?(Issue) |
|
78 | assert issue.is_a?(Issue) | |
79 | assert !issue.new_record? |
|
79 | assert !issue.new_record? | |
80 | issue.reload |
|
80 | issue.reload | |
81 | assert_equal 'Support request', issue.tracker.name |
|
81 | assert_equal 'Support request', issue.tracker.name | |
82 | end |
|
82 | end | |
83 |
|
83 | |||
84 | def test_add_issue_with_status |
|
84 | def test_add_issue_with_status | |
85 | # This email contains: 'Project: onlinestore' and 'Status: Resolved' |
|
85 | # This email contains: 'Project: onlinestore' and 'Status: Resolved' | |
86 | issue = submit_email('ticket_on_given_project.eml') |
|
86 | issue = submit_email('ticket_on_given_project.eml') | |
87 | assert issue.is_a?(Issue) |
|
87 | assert issue.is_a?(Issue) | |
88 | assert !issue.new_record? |
|
88 | assert !issue.new_record? | |
89 | issue.reload |
|
89 | issue.reload | |
90 | assert_equal Project.find(2), issue.project |
|
90 | assert_equal Project.find(2), issue.project | |
91 | assert_equal IssueStatus.find_by_name("Resolved"), issue.status |
|
91 | assert_equal IssueStatus.find_by_name("Resolved"), issue.status | |
92 | end |
|
92 | end | |
93 |
|
93 | |||
94 | def test_add_issue_with_attributes_override |
|
94 | def test_add_issue_with_attributes_override | |
95 | issue = submit_email( |
|
95 | issue = submit_email( | |
96 | 'ticket_with_attributes.eml', |
|
96 | 'ticket_with_attributes.eml', | |
97 | :allow_override => 'tracker,category,priority' |
|
97 | :allow_override => 'tracker,category,priority' | |
98 | ) |
|
98 | ) | |
99 | assert issue.is_a?(Issue) |
|
99 | assert issue.is_a?(Issue) | |
100 | assert !issue.new_record? |
|
100 | assert !issue.new_record? | |
101 | issue.reload |
|
101 | issue.reload | |
102 | assert_equal 'New ticket on a given project', issue.subject |
|
102 | assert_equal 'New ticket on a given project', issue.subject | |
103 | assert_equal User.find_by_login('jsmith'), issue.author |
|
103 | assert_equal User.find_by_login('jsmith'), issue.author | |
104 | assert_equal Project.find(2), issue.project |
|
104 | assert_equal Project.find(2), issue.project | |
105 | assert_equal 'Feature request', issue.tracker.to_s |
|
105 | assert_equal 'Feature request', issue.tracker.to_s | |
106 | assert_equal 'Stock management', issue.category.to_s |
|
106 | assert_equal 'Stock management', issue.category.to_s | |
107 | assert_equal 'Urgent', issue.priority.to_s |
|
107 | assert_equal 'Urgent', issue.priority.to_s | |
108 | assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.') |
|
108 | assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.') | |
109 | end |
|
109 | end | |
110 |
|
110 | |||
111 | def test_add_issue_with_group_assignment |
|
111 | def test_add_issue_with_group_assignment | |
112 | with_settings :issue_group_assignment => '1' do |
|
112 | with_settings :issue_group_assignment => '1' do | |
113 | issue = submit_email('ticket_on_given_project.eml') do |email| |
|
113 | issue = submit_email('ticket_on_given_project.eml') do |email| | |
114 | email.gsub!('Assigned to: John Smith', 'Assigned to: B Team') |
|
114 | email.gsub!('Assigned to: John Smith', 'Assigned to: B Team') | |
115 | end |
|
115 | end | |
116 | assert issue.is_a?(Issue) |
|
116 | assert issue.is_a?(Issue) | |
117 | assert !issue.new_record? |
|
117 | assert !issue.new_record? | |
118 | issue.reload |
|
118 | issue.reload | |
119 | assert_equal Group.find(11), issue.assigned_to |
|
119 | assert_equal Group.find(11), issue.assigned_to | |
120 | end |
|
120 | end | |
121 | end |
|
121 | end | |
122 |
|
122 | |||
123 | def test_add_issue_with_partial_attributes_override |
|
123 | def test_add_issue_with_partial_attributes_override | |
124 | issue = submit_email( |
|
124 | issue = submit_email( | |
125 | 'ticket_with_attributes.eml', |
|
125 | 'ticket_with_attributes.eml', | |
126 | :issue => {:priority => 'High'}, |
|
126 | :issue => {:priority => 'High'}, | |
127 | :allow_override => ['tracker'] |
|
127 | :allow_override => ['tracker'] | |
128 | ) |
|
128 | ) | |
129 | assert issue.is_a?(Issue) |
|
129 | assert issue.is_a?(Issue) | |
130 | assert !issue.new_record? |
|
130 | assert !issue.new_record? | |
131 | issue.reload |
|
131 | issue.reload | |
132 | assert_equal 'New ticket on a given project', issue.subject |
|
132 | assert_equal 'New ticket on a given project', issue.subject | |
133 | assert_equal User.find_by_login('jsmith'), issue.author |
|
133 | assert_equal User.find_by_login('jsmith'), issue.author | |
134 | assert_equal Project.find(2), issue.project |
|
134 | assert_equal Project.find(2), issue.project | |
135 | assert_equal 'Feature request', issue.tracker.to_s |
|
135 | assert_equal 'Feature request', issue.tracker.to_s | |
136 | assert_nil issue.category |
|
136 | assert_nil issue.category | |
137 | assert_equal 'High', issue.priority.to_s |
|
137 | assert_equal 'High', issue.priority.to_s | |
138 | assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.') |
|
138 | assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.') | |
139 | end |
|
139 | end | |
140 |
|
140 | |||
141 | def test_add_issue_with_spaces_between_attribute_and_separator |
|
141 | def test_add_issue_with_spaces_between_attribute_and_separator | |
142 | issue = submit_email( |
|
142 | issue = submit_email( | |
143 | 'ticket_with_spaces_between_attribute_and_separator.eml', |
|
143 | 'ticket_with_spaces_between_attribute_and_separator.eml', | |
144 | :allow_override => 'tracker,category,priority' |
|
144 | :allow_override => 'tracker,category,priority' | |
145 | ) |
|
145 | ) | |
146 | assert issue.is_a?(Issue) |
|
146 | assert issue.is_a?(Issue) | |
147 | assert !issue.new_record? |
|
147 | assert !issue.new_record? | |
148 | issue.reload |
|
148 | issue.reload | |
149 | assert_equal 'New ticket on a given project', issue.subject |
|
149 | assert_equal 'New ticket on a given project', issue.subject | |
150 | assert_equal User.find_by_login('jsmith'), issue.author |
|
150 | assert_equal User.find_by_login('jsmith'), issue.author | |
151 | assert_equal Project.find(2), issue.project |
|
151 | assert_equal Project.find(2), issue.project | |
152 | assert_equal 'Feature request', issue.tracker.to_s |
|
152 | assert_equal 'Feature request', issue.tracker.to_s | |
153 | assert_equal 'Stock management', issue.category.to_s |
|
153 | assert_equal 'Stock management', issue.category.to_s | |
154 | assert_equal 'Urgent', issue.priority.to_s |
|
154 | assert_equal 'Urgent', issue.priority.to_s | |
155 | assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.') |
|
155 | assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.') | |
156 | end |
|
156 | end | |
157 |
|
157 | |||
158 | def test_add_issue_with_attachment_to_specific_project |
|
158 | def test_add_issue_with_attachment_to_specific_project | |
159 | issue = submit_email('ticket_with_attachment.eml', :issue => {:project => 'onlinestore'}) |
|
159 | issue = submit_email('ticket_with_attachment.eml', :issue => {:project => 'onlinestore'}) | |
160 | assert issue.is_a?(Issue) |
|
160 | assert issue.is_a?(Issue) | |
161 | assert !issue.new_record? |
|
161 | assert !issue.new_record? | |
162 | issue.reload |
|
162 | issue.reload | |
163 | assert_equal 'Ticket created by email with attachment', issue.subject |
|
163 | assert_equal 'Ticket created by email with attachment', issue.subject | |
164 | assert_equal User.find_by_login('jsmith'), issue.author |
|
164 | assert_equal User.find_by_login('jsmith'), issue.author | |
165 | assert_equal Project.find(2), issue.project |
|
165 | assert_equal Project.find(2), issue.project | |
166 | assert_equal 'This is a new ticket with attachments', issue.description |
|
166 | assert_equal 'This is a new ticket with attachments', issue.description | |
167 | # Attachment properties |
|
167 | # Attachment properties | |
168 | assert_equal 1, issue.attachments.size |
|
168 | assert_equal 1, issue.attachments.size | |
169 | assert_equal 'Paella.jpg', issue.attachments.first.filename |
|
169 | assert_equal 'Paella.jpg', issue.attachments.first.filename | |
170 | assert_equal 'image/jpeg', issue.attachments.first.content_type |
|
170 | assert_equal 'image/jpeg', issue.attachments.first.content_type | |
171 | assert_equal 10790, issue.attachments.first.filesize |
|
171 | assert_equal 10790, issue.attachments.first.filesize | |
172 | end |
|
172 | end | |
173 |
|
173 | |||
174 | def test_add_issue_with_custom_fields |
|
174 | def test_add_issue_with_custom_fields | |
175 | issue = submit_email('ticket_with_custom_fields.eml', :issue => {:project => 'onlinestore'}) |
|
175 | issue = submit_email('ticket_with_custom_fields.eml', :issue => {:project => 'onlinestore'}) | |
176 | assert issue.is_a?(Issue) |
|
176 | assert issue.is_a?(Issue) | |
177 | assert !issue.new_record? |
|
177 | assert !issue.new_record? | |
178 | issue.reload |
|
178 | issue.reload | |
179 | assert_equal 'New ticket with custom field values', issue.subject |
|
179 | assert_equal 'New ticket with custom field values', issue.subject | |
180 | assert_equal 'PostgreSQL', issue.custom_field_value(1) |
|
180 | assert_equal 'PostgreSQL', issue.custom_field_value(1) | |
181 | assert_equal 'Value for a custom field', issue.custom_field_value(2) |
|
181 | assert_equal 'Value for a custom field', issue.custom_field_value(2) | |
182 | assert !issue.description.match(/^searchable field:/i) |
|
182 | assert !issue.description.match(/^searchable field:/i) | |
183 | end |
|
183 | end | |
184 |
|
184 | |||
185 | def test_add_issue_with_version_custom_fields |
|
185 | def test_add_issue_with_version_custom_fields | |
186 | field = IssueCustomField.create!(:name => 'Affected version', :field_format => 'version', :is_for_all => true, :tracker_ids => [1,2,3]) |
|
186 | field = IssueCustomField.create!(:name => 'Affected version', :field_format => 'version', :is_for_all => true, :tracker_ids => [1,2,3]) | |
187 |
|
187 | |||
188 | issue = submit_email('ticket_with_custom_fields.eml', :issue => {:project => 'ecookbook'}) do |email| |
|
188 | issue = submit_email('ticket_with_custom_fields.eml', :issue => {:project => 'ecookbook'}) do |email| | |
189 | email << "Affected version: 1.0\n" |
|
189 | email << "Affected version: 1.0\n" | |
190 | end |
|
190 | end | |
191 | assert issue.is_a?(Issue) |
|
191 | assert issue.is_a?(Issue) | |
192 | assert !issue.new_record? |
|
192 | assert !issue.new_record? | |
193 | issue.reload |
|
193 | issue.reload | |
194 | assert_equal '2', issue.custom_field_value(field) |
|
194 | assert_equal '2', issue.custom_field_value(field) | |
195 | end |
|
195 | end | |
196 |
|
196 | |||
197 | def test_add_issue_should_match_assignee_on_display_name |
|
197 | def test_add_issue_should_match_assignee_on_display_name | |
198 | user = User.generate!(:firstname => 'Foo Bar', :lastname => 'Foo Baz') |
|
198 | user = User.generate!(:firstname => 'Foo Bar', :lastname => 'Foo Baz') | |
199 | User.add_to_project(user, Project.find(2)) |
|
199 | User.add_to_project(user, Project.find(2)) | |
200 | issue = submit_email('ticket_on_given_project.eml') do |email| |
|
200 | issue = submit_email('ticket_on_given_project.eml') do |email| | |
201 | email.sub!(/^Assigned to.*$/, 'Assigned to: Foo Bar Foo baz') |
|
201 | email.sub!(/^Assigned to.*$/, 'Assigned to: Foo Bar Foo baz') | |
202 | end |
|
202 | end | |
203 | assert issue.is_a?(Issue) |
|
203 | assert issue.is_a?(Issue) | |
204 | assert_equal user, issue.assigned_to |
|
204 | assert_equal user, issue.assigned_to | |
205 | end |
|
205 | end | |
206 |
|
206 | |||
207 | def test_add_issue_with_cc |
|
207 | def test_add_issue_with_cc | |
208 | issue = submit_email('ticket_with_cc.eml', :issue => {:project => 'ecookbook'}) |
|
208 | issue = submit_email('ticket_with_cc.eml', :issue => {:project => 'ecookbook'}) | |
209 | assert issue.is_a?(Issue) |
|
209 | assert issue.is_a?(Issue) | |
210 | assert !issue.new_record? |
|
210 | assert !issue.new_record? | |
211 | issue.reload |
|
211 | issue.reload | |
212 | assert issue.watched_by?(User.find_by_mail('dlopper@somenet.foo')) |
|
212 | assert issue.watched_by?(User.find_by_mail('dlopper@somenet.foo')) | |
213 | assert_equal 1, issue.watcher_user_ids.size |
|
213 | assert_equal 1, issue.watcher_user_ids.size | |
214 | end |
|
214 | end | |
215 |
|
215 | |||
216 | def test_add_issue_by_unknown_user |
|
216 | def test_add_issue_by_unknown_user | |
217 | assert_no_difference 'User.count' do |
|
217 | assert_no_difference 'User.count' do | |
218 | assert_equal false, |
|
218 | assert_equal false, | |
219 | submit_email( |
|
219 | submit_email( | |
220 | 'ticket_by_unknown_user.eml', |
|
220 | 'ticket_by_unknown_user.eml', | |
221 | :issue => {:project => 'ecookbook'} |
|
221 | :issue => {:project => 'ecookbook'} | |
222 | ) |
|
222 | ) | |
223 | end |
|
223 | end | |
224 | end |
|
224 | end | |
225 |
|
225 | |||
226 | def test_add_issue_by_anonymous_user |
|
226 | def test_add_issue_by_anonymous_user | |
227 | Role.anonymous.add_permission!(:add_issues) |
|
227 | Role.anonymous.add_permission!(:add_issues) | |
228 | assert_no_difference 'User.count' do |
|
228 | assert_no_difference 'User.count' do | |
229 | issue = submit_email( |
|
229 | issue = submit_email( | |
230 | 'ticket_by_unknown_user.eml', |
|
230 | 'ticket_by_unknown_user.eml', | |
231 | :issue => {:project => 'ecookbook'}, |
|
231 | :issue => {:project => 'ecookbook'}, | |
232 | :unknown_user => 'accept' |
|
232 | :unknown_user => 'accept' | |
233 | ) |
|
233 | ) | |
234 | assert issue.is_a?(Issue) |
|
234 | assert issue.is_a?(Issue) | |
235 | assert issue.author.anonymous? |
|
235 | assert issue.author.anonymous? | |
236 | end |
|
236 | end | |
237 | end |
|
237 | end | |
238 |
|
238 | |||
239 | def test_add_issue_by_anonymous_user_with_no_from_address |
|
239 | def test_add_issue_by_anonymous_user_with_no_from_address | |
240 | Role.anonymous.add_permission!(:add_issues) |
|
240 | Role.anonymous.add_permission!(:add_issues) | |
241 | assert_no_difference 'User.count' do |
|
241 | assert_no_difference 'User.count' do | |
242 | issue = submit_email( |
|
242 | issue = submit_email( | |
243 | 'ticket_by_empty_user.eml', |
|
243 | 'ticket_by_empty_user.eml', | |
244 | :issue => {:project => 'ecookbook'}, |
|
244 | :issue => {:project => 'ecookbook'}, | |
245 | :unknown_user => 'accept' |
|
245 | :unknown_user => 'accept' | |
246 | ) |
|
246 | ) | |
247 | assert issue.is_a?(Issue) |
|
247 | assert issue.is_a?(Issue) | |
248 | assert issue.author.anonymous? |
|
248 | assert issue.author.anonymous? | |
249 | end |
|
249 | end | |
250 | end |
|
250 | end | |
251 |
|
251 | |||
252 | def test_add_issue_by_anonymous_user_on_private_project |
|
252 | def test_add_issue_by_anonymous_user_on_private_project | |
253 | Role.anonymous.add_permission!(:add_issues) |
|
253 | Role.anonymous.add_permission!(:add_issues) | |
254 | assert_no_difference 'User.count' do |
|
254 | assert_no_difference 'User.count' do | |
255 | assert_no_difference 'Issue.count' do |
|
255 | assert_no_difference 'Issue.count' do | |
256 | assert_equal false, |
|
256 | assert_equal false, | |
257 | submit_email( |
|
257 | submit_email( | |
258 | 'ticket_by_unknown_user.eml', |
|
258 | 'ticket_by_unknown_user.eml', | |
259 | :issue => {:project => 'onlinestore'}, |
|
259 | :issue => {:project => 'onlinestore'}, | |
260 | :unknown_user => 'accept' |
|
260 | :unknown_user => 'accept' | |
261 | ) |
|
261 | ) | |
262 | end |
|
262 | end | |
263 | end |
|
263 | end | |
264 | end |
|
264 | end | |
265 |
|
265 | |||
266 | def test_add_issue_by_anonymous_user_on_private_project_without_permission_check |
|
266 | def test_add_issue_by_anonymous_user_on_private_project_without_permission_check | |
267 | assert_no_difference 'User.count' do |
|
267 | assert_no_difference 'User.count' do | |
268 | assert_difference 'Issue.count' do |
|
268 | assert_difference 'Issue.count' do | |
269 | issue = submit_email( |
|
269 | issue = submit_email( | |
270 | 'ticket_by_unknown_user.eml', |
|
270 | 'ticket_by_unknown_user.eml', | |
271 | :issue => {:project => 'onlinestore'}, |
|
271 | :issue => {:project => 'onlinestore'}, | |
272 | :no_permission_check => '1', |
|
272 | :no_permission_check => '1', | |
273 | :unknown_user => 'accept' |
|
273 | :unknown_user => 'accept' | |
274 | ) |
|
274 | ) | |
275 | assert issue.is_a?(Issue) |
|
275 | assert issue.is_a?(Issue) | |
276 | assert issue.author.anonymous? |
|
276 | assert issue.author.anonymous? | |
277 | assert !issue.project.is_public? |
|
277 | assert !issue.project.is_public? | |
278 | assert_equal [issue.id, 1, 2], [issue.root_id, issue.lft, issue.rgt] |
|
278 | assert_equal [issue.id, 1, 2], [issue.root_id, issue.lft, issue.rgt] | |
279 | end |
|
279 | end | |
280 | end |
|
280 | end | |
281 | end |
|
281 | end | |
282 |
|
282 | |||
283 | def test_add_issue_by_created_user |
|
283 | def test_add_issue_by_created_user | |
284 | Setting.default_language = 'en' |
|
284 | Setting.default_language = 'en' | |
285 | assert_difference 'User.count' do |
|
285 | assert_difference 'User.count' do | |
286 | issue = submit_email( |
|
286 | issue = submit_email( | |
287 | 'ticket_by_unknown_user.eml', |
|
287 | 'ticket_by_unknown_user.eml', | |
288 | :issue => {:project => 'ecookbook'}, |
|
288 | :issue => {:project => 'ecookbook'}, | |
289 | :unknown_user => 'create' |
|
289 | :unknown_user => 'create' | |
290 | ) |
|
290 | ) | |
291 | assert issue.is_a?(Issue) |
|
291 | assert issue.is_a?(Issue) | |
292 | assert issue.author.active? |
|
292 | assert issue.author.active? | |
293 | assert_equal 'john.doe@somenet.foo', issue.author.mail |
|
293 | assert_equal 'john.doe@somenet.foo', issue.author.mail | |
294 | assert_equal 'John', issue.author.firstname |
|
294 | assert_equal 'John', issue.author.firstname | |
295 | assert_equal 'Doe', issue.author.lastname |
|
295 | assert_equal 'Doe', issue.author.lastname | |
296 |
|
296 | |||
297 | # account information |
|
297 | # account information | |
298 | email = ActionMailer::Base.deliveries.first |
|
298 | email = ActionMailer::Base.deliveries.first | |
299 | assert_not_nil email |
|
299 | assert_not_nil email | |
300 | assert email.subject.include?('account activation') |
|
300 | assert email.subject.include?('account activation') | |
301 | login = mail_body(email).match(/\* Login: (.*)$/)[1].strip |
|
301 | login = mail_body(email).match(/\* Login: (.*)$/)[1].strip | |
302 | password = mail_body(email).match(/\* Password: (.*)$/)[1].strip |
|
302 | password = mail_body(email).match(/\* Password: (.*)$/)[1].strip | |
303 | assert_equal issue.author, User.try_to_login(login, password) |
|
303 | assert_equal issue.author, User.try_to_login(login, password) | |
304 | end |
|
304 | end | |
305 | end |
|
305 | end | |
306 |
|
306 | |||
307 | def test_add_issue_without_from_header |
|
307 | def test_add_issue_without_from_header | |
308 | Role.anonymous.add_permission!(:add_issues) |
|
308 | Role.anonymous.add_permission!(:add_issues) | |
309 | assert_equal false, submit_email('ticket_without_from_header.eml') |
|
309 | assert_equal false, submit_email('ticket_without_from_header.eml') | |
310 | end |
|
310 | end | |
311 |
|
311 | |||
312 | def test_add_issue_with_invalid_attributes |
|
312 | def test_add_issue_with_invalid_attributes | |
313 | issue = submit_email( |
|
313 | issue = submit_email( | |
314 | 'ticket_with_invalid_attributes.eml', |
|
314 | 'ticket_with_invalid_attributes.eml', | |
315 | :allow_override => 'tracker,category,priority' |
|
315 | :allow_override => 'tracker,category,priority' | |
316 | ) |
|
316 | ) | |
317 | assert issue.is_a?(Issue) |
|
317 | assert issue.is_a?(Issue) | |
318 | assert !issue.new_record? |
|
318 | assert !issue.new_record? | |
319 | issue.reload |
|
319 | issue.reload | |
320 | assert_nil issue.assigned_to |
|
320 | assert_nil issue.assigned_to | |
321 | assert_nil issue.start_date |
|
321 | assert_nil issue.start_date | |
322 | assert_nil issue.due_date |
|
322 | assert_nil issue.due_date | |
323 | assert_equal 0, issue.done_ratio |
|
323 | assert_equal 0, issue.done_ratio | |
324 | assert_equal 'Normal', issue.priority.to_s |
|
324 | assert_equal 'Normal', issue.priority.to_s | |
325 | assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.') |
|
325 | assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.') | |
326 | end |
|
326 | end | |
327 |
|
327 | |||
328 | def test_add_issue_with_localized_attributes |
|
328 | def test_add_issue_with_localized_attributes | |
329 | User.find_by_mail('jsmith@somenet.foo').update_attribute 'language', 'fr' |
|
329 | User.find_by_mail('jsmith@somenet.foo').update_attribute 'language', 'fr' | |
330 | issue = submit_email( |
|
330 | issue = submit_email( | |
331 | 'ticket_with_localized_attributes.eml', |
|
331 | 'ticket_with_localized_attributes.eml', | |
332 | :allow_override => 'tracker,category,priority' |
|
332 | :allow_override => 'tracker,category,priority' | |
333 | ) |
|
333 | ) | |
334 | assert issue.is_a?(Issue) |
|
334 | assert issue.is_a?(Issue) | |
335 | assert !issue.new_record? |
|
335 | assert !issue.new_record? | |
336 | issue.reload |
|
336 | issue.reload | |
337 | assert_equal 'New ticket on a given project', issue.subject |
|
337 | assert_equal 'New ticket on a given project', issue.subject | |
338 | assert_equal User.find_by_login('jsmith'), issue.author |
|
338 | assert_equal User.find_by_login('jsmith'), issue.author | |
339 | assert_equal Project.find(2), issue.project |
|
339 | assert_equal Project.find(2), issue.project | |
340 | assert_equal 'Feature request', issue.tracker.to_s |
|
340 | assert_equal 'Feature request', issue.tracker.to_s | |
341 | assert_equal 'Stock management', issue.category.to_s |
|
341 | assert_equal 'Stock management', issue.category.to_s | |
342 | assert_equal 'Urgent', issue.priority.to_s |
|
342 | assert_equal 'Urgent', issue.priority.to_s | |
343 | assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.') |
|
343 | assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.') | |
344 | end |
|
344 | end | |
345 |
|
345 | |||
346 | def test_add_issue_with_japanese_keywords |
|
346 | def test_add_issue_with_japanese_keywords | |
347 | ja_dev = "\xe9\x96\x8b\xe7\x99\xba" |
|
347 | ja_dev = "\xe9\x96\x8b\xe7\x99\xba" | |
348 | ja_dev.force_encoding('UTF-8') if ja_dev.respond_to?(:force_encoding) |
|
348 | ja_dev.force_encoding('UTF-8') if ja_dev.respond_to?(:force_encoding) | |
349 | tracker = Tracker.create!(:name => ja_dev) |
|
349 | tracker = Tracker.create!(:name => ja_dev) | |
350 | Project.find(1).trackers << tracker |
|
350 | Project.find(1).trackers << tracker | |
351 | issue = submit_email( |
|
351 | issue = submit_email( | |
352 | 'japanese_keywords_iso_2022_jp.eml', |
|
352 | 'japanese_keywords_iso_2022_jp.eml', | |
353 | :issue => {:project => 'ecookbook'}, |
|
353 | :issue => {:project => 'ecookbook'}, | |
354 | :allow_override => 'tracker' |
|
354 | :allow_override => 'tracker' | |
355 | ) |
|
355 | ) | |
356 | assert_kind_of Issue, issue |
|
356 | assert_kind_of Issue, issue | |
357 | assert_equal tracker, issue.tracker |
|
357 | assert_equal tracker, issue.tracker | |
358 | end |
|
358 | end | |
359 |
|
359 | |||
360 | def test_add_issue_from_apple_mail |
|
360 | def test_add_issue_from_apple_mail | |
361 | issue = submit_email( |
|
361 | issue = submit_email( | |
362 | 'apple_mail_with_attachment.eml', |
|
362 | 'apple_mail_with_attachment.eml', | |
363 | :issue => {:project => 'ecookbook'} |
|
363 | :issue => {:project => 'ecookbook'} | |
364 | ) |
|
364 | ) | |
365 | assert_kind_of Issue, issue |
|
365 | assert_kind_of Issue, issue | |
366 | assert_equal 1, issue.attachments.size |
|
366 | assert_equal 1, issue.attachments.size | |
367 |
|
367 | |||
368 | attachment = issue.attachments.first |
|
368 | attachment = issue.attachments.first | |
369 | assert_equal 'paella.jpg', attachment.filename |
|
369 | assert_equal 'paella.jpg', attachment.filename | |
370 | assert_equal 10790, attachment.filesize |
|
370 | assert_equal 10790, attachment.filesize | |
371 | assert File.exist?(attachment.diskfile) |
|
371 | assert File.exist?(attachment.diskfile) | |
372 | assert_equal 10790, File.size(attachment.diskfile) |
|
372 | assert_equal 10790, File.size(attachment.diskfile) | |
373 | assert_equal 'caaf384198bcbc9563ab5c058acd73cd', attachment.digest |
|
373 | assert_equal 'caaf384198bcbc9563ab5c058acd73cd', attachment.digest | |
374 | end |
|
374 | end | |
375 |
|
375 | |||
376 | def test_thunderbird_with_attachment_ja |
|
376 | def test_thunderbird_with_attachment_ja | |
377 | issue = submit_email( |
|
377 | issue = submit_email( | |
378 | 'thunderbird_with_attachment_ja.eml', |
|
378 | 'thunderbird_with_attachment_ja.eml', | |
379 | :issue => {:project => 'ecookbook'} |
|
379 | :issue => {:project => 'ecookbook'} | |
380 | ) |
|
380 | ) | |
381 | assert_kind_of Issue, issue |
|
381 | assert_kind_of Issue, issue | |
382 | assert_equal 1, issue.attachments.size |
|
382 | assert_equal 1, issue.attachments.size | |
383 | ja = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88.txt" |
|
383 | ja = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88.txt" | |
384 | ja.force_encoding('UTF-8') if ja.respond_to?(:force_encoding) |
|
384 | ja.force_encoding('UTF-8') if ja.respond_to?(:force_encoding) | |
385 | attachment = issue.attachments.first |
|
385 | attachment = issue.attachments.first | |
386 | assert_equal ja, attachment.filename |
|
386 | assert_equal ja, attachment.filename | |
387 | assert_equal 5, attachment.filesize |
|
387 | assert_equal 5, attachment.filesize | |
388 | assert File.exist?(attachment.diskfile) |
|
388 | assert File.exist?(attachment.diskfile) | |
389 | assert_equal 5, File.size(attachment.diskfile) |
|
389 | assert_equal 5, File.size(attachment.diskfile) | |
390 | assert_equal 'd8e8fca2dc0f896fd7cb4cb0031ba249', attachment.digest |
|
390 | assert_equal 'd8e8fca2dc0f896fd7cb4cb0031ba249', attachment.digest | |
391 | end |
|
391 | end | |
392 |
|
392 | |||
393 | def test_gmail_with_attachment_ja |
|
393 | def test_gmail_with_attachment_ja | |
394 | issue = submit_email( |
|
394 | issue = submit_email( | |
395 | 'gmail_with_attachment_ja.eml', |
|
395 | 'gmail_with_attachment_ja.eml', | |
396 | :issue => {:project => 'ecookbook'} |
|
396 | :issue => {:project => 'ecookbook'} | |
397 | ) |
|
397 | ) | |
398 | assert_kind_of Issue, issue |
|
398 | assert_kind_of Issue, issue | |
399 | assert_equal 1, issue.attachments.size |
|
399 | assert_equal 1, issue.attachments.size | |
400 | ja = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88.txt" |
|
400 | ja = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88.txt" | |
401 | ja.force_encoding('UTF-8') if ja.respond_to?(:force_encoding) |
|
401 | ja.force_encoding('UTF-8') if ja.respond_to?(:force_encoding) | |
402 | attachment = issue.attachments.first |
|
402 | attachment = issue.attachments.first | |
403 | assert_equal ja, attachment.filename |
|
403 | assert_equal ja, attachment.filename | |
404 | assert_equal 5, attachment.filesize |
|
404 | assert_equal 5, attachment.filesize | |
405 | assert File.exist?(attachment.diskfile) |
|
405 | assert File.exist?(attachment.diskfile) | |
406 | assert_equal 5, File.size(attachment.diskfile) |
|
406 | assert_equal 5, File.size(attachment.diskfile) | |
407 | assert_equal 'd8e8fca2dc0f896fd7cb4cb0031ba249', attachment.digest |
|
407 | assert_equal 'd8e8fca2dc0f896fd7cb4cb0031ba249', attachment.digest | |
408 | end |
|
408 | end | |
409 |
|
409 | |||
410 | def test_thunderbird_with_attachment_latin1 |
|
410 | def test_thunderbird_with_attachment_latin1 | |
411 | issue = submit_email( |
|
411 | issue = submit_email( | |
412 | 'thunderbird_with_attachment_iso-8859-1.eml', |
|
412 | 'thunderbird_with_attachment_iso-8859-1.eml', | |
413 | :issue => {:project => 'ecookbook'} |
|
413 | :issue => {:project => 'ecookbook'} | |
414 | ) |
|
414 | ) | |
415 | assert_kind_of Issue, issue |
|
415 | assert_kind_of Issue, issue | |
416 | assert_equal 1, issue.attachments.size |
|
416 | assert_equal 1, issue.attachments.size | |
417 | u = "" |
|
417 | u = "" | |
418 | u.force_encoding('UTF-8') if u.respond_to?(:force_encoding) |
|
418 | u.force_encoding('UTF-8') if u.respond_to?(:force_encoding) | |
419 | u1 = "\xc3\x84\xc3\xa4\xc3\x96\xc3\xb6\xc3\x9c\xc3\xbc" |
|
419 | u1 = "\xc3\x84\xc3\xa4\xc3\x96\xc3\xb6\xc3\x9c\xc3\xbc" | |
420 | u1.force_encoding('UTF-8') if u1.respond_to?(:force_encoding) |
|
420 | u1.force_encoding('UTF-8') if u1.respond_to?(:force_encoding) | |
421 | 11.times { u << u1 } |
|
421 | 11.times { u << u1 } | |
422 | attachment = issue.attachments.first |
|
422 | attachment = issue.attachments.first | |
423 | assert_equal "#{u}.png", attachment.filename |
|
423 | assert_equal "#{u}.png", attachment.filename | |
424 | assert_equal 130, attachment.filesize |
|
424 | assert_equal 130, attachment.filesize | |
425 | assert File.exist?(attachment.diskfile) |
|
425 | assert File.exist?(attachment.diskfile) | |
426 | assert_equal 130, File.size(attachment.diskfile) |
|
426 | assert_equal 130, File.size(attachment.diskfile) | |
427 | assert_equal '4d80e667ac37dddfe05502530f152abb', attachment.digest |
|
427 | assert_equal '4d80e667ac37dddfe05502530f152abb', attachment.digest | |
428 | end |
|
428 | end | |
429 |
|
429 | |||
430 | def test_gmail_with_attachment_latin1 |
|
430 | def test_gmail_with_attachment_latin1 | |
431 | issue = submit_email( |
|
431 | issue = submit_email( | |
432 | 'gmail_with_attachment_iso-8859-1.eml', |
|
432 | 'gmail_with_attachment_iso-8859-1.eml', | |
433 | :issue => {:project => 'ecookbook'} |
|
433 | :issue => {:project => 'ecookbook'} | |
434 | ) |
|
434 | ) | |
435 | assert_kind_of Issue, issue |
|
435 | assert_kind_of Issue, issue | |
436 | assert_equal 1, issue.attachments.size |
|
436 | assert_equal 1, issue.attachments.size | |
437 | u = "" |
|
437 | u = "" | |
438 | u.force_encoding('UTF-8') if u.respond_to?(:force_encoding) |
|
438 | u.force_encoding('UTF-8') if u.respond_to?(:force_encoding) | |
439 | u1 = "\xc3\x84\xc3\xa4\xc3\x96\xc3\xb6\xc3\x9c\xc3\xbc" |
|
439 | u1 = "\xc3\x84\xc3\xa4\xc3\x96\xc3\xb6\xc3\x9c\xc3\xbc" | |
440 | u1.force_encoding('UTF-8') if u1.respond_to?(:force_encoding) |
|
440 | u1.force_encoding('UTF-8') if u1.respond_to?(:force_encoding) | |
441 | 11.times { u << u1 } |
|
441 | 11.times { u << u1 } | |
442 | attachment = issue.attachments.first |
|
442 | attachment = issue.attachments.first | |
443 | assert_equal "#{u}.txt", attachment.filename |
|
443 | assert_equal "#{u}.txt", attachment.filename | |
444 | assert_equal 5, attachment.filesize |
|
444 | assert_equal 5, attachment.filesize | |
445 | assert File.exist?(attachment.diskfile) |
|
445 | assert File.exist?(attachment.diskfile) | |
446 | assert_equal 5, File.size(attachment.diskfile) |
|
446 | assert_equal 5, File.size(attachment.diskfile) | |
447 | assert_equal 'd8e8fca2dc0f896fd7cb4cb0031ba249', attachment.digest |
|
447 | assert_equal 'd8e8fca2dc0f896fd7cb4cb0031ba249', attachment.digest | |
448 | end |
|
448 | end | |
449 |
|
449 | |||
450 | def test_add_issue_with_iso_8859_1_subject |
|
450 | def test_add_issue_with_iso_8859_1_subject | |
451 | issue = submit_email( |
|
451 | issue = submit_email( | |
452 | 'subject_as_iso-8859-1.eml', |
|
452 | 'subject_as_iso-8859-1.eml', | |
453 | :issue => {:project => 'ecookbook'} |
|
453 | :issue => {:project => 'ecookbook'} | |
454 | ) |
|
454 | ) | |
455 | str = "Testmail from Webmail: \xc3\xa4 \xc3\xb6 \xc3\xbc..." |
|
455 | str = "Testmail from Webmail: \xc3\xa4 \xc3\xb6 \xc3\xbc..." | |
456 | str.force_encoding('UTF-8') if str.respond_to?(:force_encoding) |
|
456 | str.force_encoding('UTF-8') if str.respond_to?(:force_encoding) | |
457 | assert_kind_of Issue, issue |
|
457 | assert_kind_of Issue, issue | |
458 | assert_equal str, issue.subject |
|
458 | assert_equal str, issue.subject | |
459 | end |
|
459 | end | |
460 |
|
460 | |||
461 | def test_add_issue_with_japanese_subject |
|
461 | def test_add_issue_with_japanese_subject | |
462 | issue = submit_email( |
|
462 | issue = submit_email( | |
463 | 'subject_japanese_1.eml', |
|
463 | 'subject_japanese_1.eml', | |
464 | :issue => {:project => 'ecookbook'} |
|
464 | :issue => {:project => 'ecookbook'} | |
465 | ) |
|
465 | ) | |
466 | assert_kind_of Issue, issue |
|
466 | assert_kind_of Issue, issue | |
467 | ja = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88" |
|
467 | ja = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88" | |
468 | ja.force_encoding('UTF-8') if ja.respond_to?(:force_encoding) |
|
468 | ja.force_encoding('UTF-8') if ja.respond_to?(:force_encoding) | |
469 | assert_equal ja, issue.subject |
|
469 | assert_equal ja, issue.subject | |
470 | end |
|
470 | end | |
471 |
|
471 | |||
472 | def test_add_issue_with_no_subject_header |
|
472 | def test_add_issue_with_no_subject_header | |
473 | issue = submit_email( |
|
473 | issue = submit_email( | |
474 | 'no_subject_header.eml', |
|
474 | 'no_subject_header.eml', | |
475 | :issue => {:project => 'ecookbook'} |
|
475 | :issue => {:project => 'ecookbook'} | |
476 | ) |
|
476 | ) | |
477 | assert_kind_of Issue, issue |
|
477 | assert_kind_of Issue, issue | |
478 | assert_equal '(no subject)', issue.subject |
|
478 | assert_equal '(no subject)', issue.subject | |
479 | end |
|
479 | end | |
480 |
|
480 | |||
481 | def test_add_issue_with_mixed_japanese_subject |
|
481 | def test_add_issue_with_mixed_japanese_subject | |
482 | issue = submit_email( |
|
482 | issue = submit_email( | |
483 | 'subject_japanese_2.eml', |
|
483 | 'subject_japanese_2.eml', | |
484 | :issue => {:project => 'ecookbook'} |
|
484 | :issue => {:project => 'ecookbook'} | |
485 | ) |
|
485 | ) | |
486 | assert_kind_of Issue, issue |
|
486 | assert_kind_of Issue, issue | |
487 | ja = "Re: \xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88" |
|
487 | ja = "Re: \xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88" | |
488 | ja.force_encoding('UTF-8') if ja.respond_to?(:force_encoding) |
|
488 | ja.force_encoding('UTF-8') if ja.respond_to?(:force_encoding) | |
489 | assert_equal ja, issue.subject |
|
489 | assert_equal ja, issue.subject | |
490 | end |
|
490 | end | |
491 |
|
491 | |||
492 | def test_should_ignore_emails_from_locked_users |
|
492 | def test_should_ignore_emails_from_locked_users | |
493 | User.find(2).lock! |
|
493 | User.find(2).lock! | |
494 |
|
494 | |||
495 | MailHandler.any_instance.expects(:dispatch).never |
|
495 | MailHandler.any_instance.expects(:dispatch).never | |
496 | assert_no_difference 'Issue.count' do |
|
496 | assert_no_difference 'Issue.count' do | |
497 | assert_equal false, submit_email('ticket_on_given_project.eml') |
|
497 | assert_equal false, submit_email('ticket_on_given_project.eml') | |
498 | end |
|
498 | end | |
499 | end |
|
499 | end | |
500 |
|
500 | |||
501 | def test_should_ignore_emails_from_emission_address |
|
501 | def test_should_ignore_emails_from_emission_address | |
502 | Role.anonymous.add_permission!(:add_issues) |
|
502 | Role.anonymous.add_permission!(:add_issues) | |
503 | assert_no_difference 'User.count' do |
|
503 | assert_no_difference 'User.count' do | |
504 | assert_equal false, |
|
504 | assert_equal false, | |
505 | submit_email( |
|
505 | submit_email( | |
506 | 'ticket_from_emission_address.eml', |
|
506 | 'ticket_from_emission_address.eml', | |
507 | :issue => {:project => 'ecookbook'}, |
|
507 | :issue => {:project => 'ecookbook'}, | |
508 | :unknown_user => 'create' |
|
508 | :unknown_user => 'create' | |
509 | ) |
|
509 | ) | |
510 | end |
|
510 | end | |
511 | end |
|
511 | end | |
512 |
|
512 | |||
513 | def test_should_ignore_auto_replied_emails |
|
513 | def test_should_ignore_auto_replied_emails | |
514 | MailHandler.any_instance.expects(:dispatch).never |
|
514 | MailHandler.any_instance.expects(:dispatch).never | |
515 | [ |
|
515 | [ | |
516 | "X-Auto-Response-Suppress: OOF", |
|
516 | "X-Auto-Response-Suppress: OOF", | |
517 | "Auto-Submitted: auto-replied", |
|
517 | "Auto-Submitted: auto-replied", | |
518 | "Auto-Submitted: Auto-Replied", |
|
518 | "Auto-Submitted: Auto-Replied", | |
519 | "Auto-Submitted: auto-generated" |
|
519 | "Auto-Submitted: auto-generated" | |
520 | ].each do |header| |
|
520 | ].each do |header| | |
521 | raw = IO.read(File.join(FIXTURES_PATH, 'ticket_on_given_project.eml')) |
|
521 | raw = IO.read(File.join(FIXTURES_PATH, 'ticket_on_given_project.eml')) | |
522 | raw = header + "\n" + raw |
|
522 | raw = header + "\n" + raw | |
523 |
|
523 | |||
524 | assert_no_difference 'Issue.count' do |
|
524 | assert_no_difference 'Issue.count' do | |
525 | assert_equal false, MailHandler.receive(raw), "email with #{header} header was not ignored" |
|
525 | assert_equal false, MailHandler.receive(raw), "email with #{header} header was not ignored" | |
526 | end |
|
526 | end | |
527 | end |
|
527 | end | |
528 | end |
|
528 | end | |
529 |
|
529 | |||
530 | def test_add_issue_should_send_email_notification |
|
530 | def test_add_issue_should_send_email_notification | |
531 | Setting.notified_events = ['issue_added'] |
|
531 | Setting.notified_events = ['issue_added'] | |
532 | ActionMailer::Base.deliveries.clear |
|
532 | ActionMailer::Base.deliveries.clear | |
533 | # This email contains: 'Project: onlinestore' |
|
533 | # This email contains: 'Project: onlinestore' | |
534 | issue = submit_email('ticket_on_given_project.eml') |
|
534 | issue = submit_email('ticket_on_given_project.eml') | |
535 | assert issue.is_a?(Issue) |
|
535 | assert issue.is_a?(Issue) | |
536 | assert_equal 1, ActionMailer::Base.deliveries.size |
|
536 | assert_equal 1, ActionMailer::Base.deliveries.size | |
537 | end |
|
537 | end | |
538 |
|
538 | |||
539 | def test_update_issue |
|
539 | def test_update_issue | |
540 | journal = submit_email('ticket_reply.eml') |
|
540 | journal = submit_email('ticket_reply.eml') | |
541 | assert journal.is_a?(Journal) |
|
541 | assert journal.is_a?(Journal) | |
542 | assert_equal User.find_by_login('jsmith'), journal.user |
|
542 | assert_equal User.find_by_login('jsmith'), journal.user | |
543 | assert_equal Issue.find(2), journal.journalized |
|
543 | assert_equal Issue.find(2), journal.journalized | |
544 | assert_match /This is reply/, journal.notes |
|
544 | assert_match /This is reply/, journal.notes | |
545 | assert_equal false, journal.private_notes |
|
545 | assert_equal false, journal.private_notes | |
546 | assert_equal 'Feature request', journal.issue.tracker.name |
|
546 | assert_equal 'Feature request', journal.issue.tracker.name | |
547 | end |
|
547 | end | |
548 |
|
548 | |||
549 | def test_update_issue_with_attribute_changes |
|
549 | def test_update_issue_with_attribute_changes | |
550 | # This email contains: 'Status: Resolved' |
|
550 | # This email contains: 'Status: Resolved' | |
551 | journal = submit_email('ticket_reply_with_status.eml') |
|
551 | journal = submit_email('ticket_reply_with_status.eml') | |
552 | assert journal.is_a?(Journal) |
|
552 | assert journal.is_a?(Journal) | |
553 | issue = Issue.find(journal.issue.id) |
|
553 | issue = Issue.find(journal.issue.id) | |
554 | assert_equal User.find_by_login('jsmith'), journal.user |
|
554 | assert_equal User.find_by_login('jsmith'), journal.user | |
555 | assert_equal Issue.find(2), journal.journalized |
|
555 | assert_equal Issue.find(2), journal.journalized | |
556 | assert_match /This is reply/, journal.notes |
|
556 | assert_match /This is reply/, journal.notes | |
557 | assert_equal 'Feature request', journal.issue.tracker.name |
|
557 | assert_equal 'Feature request', journal.issue.tracker.name | |
558 | assert_equal IssueStatus.find_by_name("Resolved"), issue.status |
|
558 | assert_equal IssueStatus.find_by_name("Resolved"), issue.status | |
559 | assert_equal '2010-01-01', issue.start_date.to_s |
|
559 | assert_equal '2010-01-01', issue.start_date.to_s | |
560 | assert_equal '2010-12-31', issue.due_date.to_s |
|
560 | assert_equal '2010-12-31', issue.due_date.to_s | |
561 | assert_equal User.find_by_login('jsmith'), issue.assigned_to |
|
561 | assert_equal User.find_by_login('jsmith'), issue.assigned_to | |
562 | assert_equal "52.6", issue.custom_value_for(CustomField.find_by_name('Float field')).value |
|
562 | assert_equal "52.6", issue.custom_value_for(CustomField.find_by_name('Float field')).value | |
563 | # keywords should be removed from the email body |
|
563 | # keywords should be removed from the email body | |
564 | assert !journal.notes.match(/^Status:/i) |
|
564 | assert !journal.notes.match(/^Status:/i) | |
565 | assert !journal.notes.match(/^Start Date:/i) |
|
565 | assert !journal.notes.match(/^Start Date:/i) | |
566 | end |
|
566 | end | |
567 |
|
567 | |||
568 | def test_update_issue_with_attachment |
|
568 | def test_update_issue_with_attachment | |
569 | assert_difference 'Journal.count' do |
|
569 | assert_difference 'Journal.count' do | |
570 | assert_difference 'JournalDetail.count' do |
|
570 | assert_difference 'JournalDetail.count' do | |
571 | assert_difference 'Attachment.count' do |
|
571 | assert_difference 'Attachment.count' do | |
572 | assert_no_difference 'Issue.count' do |
|
572 | assert_no_difference 'Issue.count' do | |
573 | journal = submit_email('ticket_with_attachment.eml') do |raw| |
|
573 | journal = submit_email('ticket_with_attachment.eml') do |raw| | |
574 | raw.gsub! /^Subject: .*$/, 'Subject: Re: [Cookbook - Feature #2] (New) Add ingredients categories' |
|
574 | raw.gsub! /^Subject: .*$/, 'Subject: Re: [Cookbook - Feature #2] (New) Add ingredients categories' | |
575 | end |
|
575 | end | |
576 | end |
|
576 | end | |
577 | end |
|
577 | end | |
578 | end |
|
578 | end | |
579 | end |
|
579 | end | |
580 | journal = Journal.first(:order => 'id DESC') |
|
580 | journal = Journal.first(:order => 'id DESC') | |
581 | assert_equal Issue.find(2), journal.journalized |
|
581 | assert_equal Issue.find(2), journal.journalized | |
582 | assert_equal 1, journal.details.size |
|
582 | assert_equal 1, journal.details.size | |
583 |
|
583 | |||
584 | detail = journal.details.first |
|
584 | detail = journal.details.first | |
585 | assert_equal 'attachment', detail.property |
|
585 | assert_equal 'attachment', detail.property | |
586 | assert_equal 'Paella.jpg', detail.value |
|
586 | assert_equal 'Paella.jpg', detail.value | |
587 | end |
|
587 | end | |
588 |
|
588 | |||
589 | def test_update_issue_should_send_email_notification |
|
589 | def test_update_issue_should_send_email_notification | |
590 | ActionMailer::Base.deliveries.clear |
|
590 | ActionMailer::Base.deliveries.clear | |
591 | journal = submit_email('ticket_reply.eml') |
|
591 | journal = submit_email('ticket_reply.eml') | |
592 | assert journal.is_a?(Journal) |
|
592 | assert journal.is_a?(Journal) | |
593 | assert_equal 1, ActionMailer::Base.deliveries.size |
|
593 | assert_equal 1, ActionMailer::Base.deliveries.size | |
594 | end |
|
594 | end | |
595 |
|
595 | |||
596 | def test_update_issue_should_not_set_defaults |
|
596 | def test_update_issue_should_not_set_defaults | |
597 | journal = submit_email( |
|
597 | journal = submit_email( | |
598 | 'ticket_reply.eml', |
|
598 | 'ticket_reply.eml', | |
599 | :issue => {:tracker => 'Support request', :priority => 'High'} |
|
599 | :issue => {:tracker => 'Support request', :priority => 'High'} | |
600 | ) |
|
600 | ) | |
601 | assert journal.is_a?(Journal) |
|
601 | assert journal.is_a?(Journal) | |
602 | assert_match /This is reply/, journal.notes |
|
602 | assert_match /This is reply/, journal.notes | |
603 | assert_equal 'Feature request', journal.issue.tracker.name |
|
603 | assert_equal 'Feature request', journal.issue.tracker.name | |
604 | assert_equal 'Normal', journal.issue.priority.name |
|
604 | assert_equal 'Normal', journal.issue.priority.name | |
605 | end |
|
605 | end | |
606 |
|
606 | |||
607 | def test_replying_to_a_private_note_should_add_reply_as_private |
|
607 | def test_replying_to_a_private_note_should_add_reply_as_private | |
608 | private_journal = Journal.create!(:notes => 'Private notes', :journalized => Issue.find(1), :private_notes => true, :user_id => 2) |
|
608 | private_journal = Journal.create!(:notes => 'Private notes', :journalized => Issue.find(1), :private_notes => true, :user_id => 2) | |
609 |
|
609 | |||
610 | assert_difference 'Journal.count' do |
|
610 | assert_difference 'Journal.count' do | |
611 | journal = submit_email('ticket_reply.eml') do |email| |
|
611 | journal = submit_email('ticket_reply.eml') do |email| | |
612 | email.sub! %r{^In-Reply-To:.*$}, "In-Reply-To: <redmine.journal-#{private_journal.id}.20060719210421@osiris>" |
|
612 | email.sub! %r{^In-Reply-To:.*$}, "In-Reply-To: <redmine.journal-#{private_journal.id}.20060719210421@osiris>" | |
613 | end |
|
613 | end | |
614 |
|
614 | |||
615 | assert_kind_of Journal, journal |
|
615 | assert_kind_of Journal, journal | |
616 | assert_match /This is reply/, journal.notes |
|
616 | assert_match /This is reply/, journal.notes | |
617 | assert_equal true, journal.private_notes |
|
617 | assert_equal true, journal.private_notes | |
618 | end |
|
618 | end | |
619 | end |
|
619 | end | |
620 |
|
620 | |||
621 | def test_reply_to_a_message |
|
621 | def test_reply_to_a_message | |
622 | m = submit_email('message_reply.eml') |
|
622 | m = submit_email('message_reply.eml') | |
623 | assert m.is_a?(Message) |
|
623 | assert m.is_a?(Message) | |
624 | assert !m.new_record? |
|
624 | assert !m.new_record? | |
625 | m.reload |
|
625 | m.reload | |
626 | assert_equal 'Reply via email', m.subject |
|
626 | assert_equal 'Reply via email', m.subject | |
627 | # The email replies to message #2 which is part of the thread of message #1 |
|
627 | # The email replies to message #2 which is part of the thread of message #1 | |
628 | assert_equal Message.find(1), m.parent |
|
628 | assert_equal Message.find(1), m.parent | |
629 | end |
|
629 | end | |
630 |
|
630 | |||
631 | def test_reply_to_a_message_by_subject |
|
631 | def test_reply_to_a_message_by_subject | |
632 | m = submit_email('message_reply_by_subject.eml') |
|
632 | m = submit_email('message_reply_by_subject.eml') | |
633 | assert m.is_a?(Message) |
|
633 | assert m.is_a?(Message) | |
634 | assert !m.new_record? |
|
634 | assert !m.new_record? | |
635 | m.reload |
|
635 | m.reload | |
636 | assert_equal 'Reply to the first post', m.subject |
|
636 | assert_equal 'Reply to the first post', m.subject | |
637 | assert_equal Message.find(1), m.parent |
|
637 | assert_equal Message.find(1), m.parent | |
638 | end |
|
638 | end | |
639 |
|
639 | |||
640 | def test_should_strip_tags_of_html_only_emails |
|
640 | def test_should_strip_tags_of_html_only_emails | |
641 | issue = submit_email('ticket_html_only.eml', :issue => {:project => 'ecookbook'}) |
|
641 | issue = submit_email('ticket_html_only.eml', :issue => {:project => 'ecookbook'}) | |
642 | assert issue.is_a?(Issue) |
|
642 | assert issue.is_a?(Issue) | |
643 | assert !issue.new_record? |
|
643 | assert !issue.new_record? | |
644 | issue.reload |
|
644 | issue.reload | |
645 | assert_equal 'HTML email', issue.subject |
|
645 | assert_equal 'HTML email', issue.subject | |
646 | assert_equal 'This is a html-only email.', issue.description |
|
646 | assert_equal 'This is a html-only email.', issue.description | |
647 | end |
|
647 | end | |
648 |
|
648 | |||
649 | context "truncate emails based on the Setting" do |
|
649 | test "truncate emails with no setting should add the entire email into the issue" do | |
650 | context "with no setting" do |
|
650 | with_settings :mail_handler_body_delimiters => '' do | |
651 | setup do |
|
|||
652 | Setting.mail_handler_body_delimiters = '' |
|
|||
653 | end |
|
|||
654 |
|
||||
655 | should "add the entire email into the issue" do |
|
|||
656 |
|
|
651 | issue = submit_email('ticket_on_given_project.eml') | |
657 |
|
|
652 | assert_issue_created(issue) | |
658 |
|
|
653 | assert issue.description.include?('---') | |
659 |
|
|
654 | assert issue.description.include?('This paragraph is after the delimiter') | |
660 |
|
|
655 | end | |
661 |
|
|
656 | end | |
662 |
|
657 | |||
663 | context "with a single string" do |
|
658 | test "truncate emails with a single string should truncate the email at the delimiter for the issue" do | |
664 | setup do |
|
659 | with_settings :mail_handler_body_delimiters => '---' do | |
665 | Setting.mail_handler_body_delimiters = '---' |
|
|||
666 | end |
|
|||
667 | should "truncate the email at the delimiter for the issue" do |
|
|||
668 |
|
|
660 | issue = submit_email('ticket_on_given_project.eml') | |
669 |
|
|
661 | assert_issue_created(issue) | |
670 |
|
|
662 | assert issue.description.include?('This paragraph is before delimiters') | |
671 |
|
|
663 | assert issue.description.include?('--- This line starts with a delimiter') | |
672 |
|
|
664 | assert !issue.description.match(/^---$/) | |
673 |
|
|
665 | assert !issue.description.include?('This paragraph is after the delimiter') | |
674 |
|
|
666 | end | |
675 |
|
|
667 | end | |
676 |
|
668 | |||
677 | context "with a single quoted reply (e.g. reply to a Redmine email notification)" do |
|
669 | test "truncate emails with a single quoted reply should truncate the email at the delimiter with the quoted reply symbols (>)" do | |
678 | setup do |
|
670 | with_settings :mail_handler_body_delimiters => '--- Reply above. Do not remove this line. ---' do | |
679 | Setting.mail_handler_body_delimiters = '--- Reply above. Do not remove this line. ---' |
|
|||
680 | end |
|
|||
681 | should "truncate the email at the delimiter with the quoted reply symbols (>)" do |
|
|||
682 |
|
|
671 | journal = submit_email('issue_update_with_quoted_reply_above.eml') | |
683 |
|
|
672 | assert journal.is_a?(Journal) | |
684 |
|
|
673 | assert journal.notes.include?('An update to the issue by the sender.') | |
685 |
|
|
674 | assert !journal.notes.match(Regexp.escape("--- Reply above. Do not remove this line. ---")) | |
686 |
|
|
675 | assert !journal.notes.include?('Looks like the JSON api for projects was missed.') | |
687 |
|
|
676 | end | |
688 |
|
|
677 | end | |
689 |
|
678 | |||
690 | context "with multiple quoted replies (e.g. reply to a reply of a Redmine email notification)" do |
|
679 | test "truncate emails with multiple quoted replies should truncate the email at the delimiter with the quoted reply symbols (>)" do | |
691 | setup do |
|
680 | with_settings :mail_handler_body_delimiters => '--- Reply above. Do not remove this line. ---' do | |
692 | Setting.mail_handler_body_delimiters = '--- Reply above. Do not remove this line. ---' |
|
|||
693 | end |
|
|||
694 | should "truncate the email at the delimiter with the quoted reply symbols (>)" do |
|
|||
695 |
|
|
681 | journal = submit_email('issue_update_with_multiple_quoted_reply_above.eml') | |
696 |
|
|
682 | assert journal.is_a?(Journal) | |
697 |
|
|
683 | assert journal.notes.include?('An update to the issue by the sender.') | |
698 |
|
|
684 | assert !journal.notes.match(Regexp.escape("--- Reply above. Do not remove this line. ---")) | |
699 |
|
|
685 | assert !journal.notes.include?('Looks like the JSON api for projects was missed.') | |
700 |
|
|
686 | end | |
701 |
|
|
687 | end | |
702 |
|
688 | |||
703 | context "with multiple strings" do |
|
689 | test "truncate emails with multiple strings should truncate the email at the first delimiter found (BREAK)" do | |
704 | setup do |
|
690 | with_settings :mail_handler_body_delimiters => "---\nBREAK" do | |
705 | Setting.mail_handler_body_delimiters = "---\nBREAK" |
|
|||
706 | end |
|
|||
707 | should "truncate the email at the first delimiter found (BREAK)" do |
|
|||
708 |
|
|
691 | issue = submit_email('ticket_on_given_project.eml') | |
709 |
|
|
692 | assert_issue_created(issue) | |
710 |
|
|
693 | assert issue.description.include?('This paragraph is before delimiters') | |
711 |
|
|
694 | assert !issue.description.include?('BREAK') | |
712 |
|
|
695 | assert !issue.description.include?('This paragraph is between delimiters') | |
713 |
|
|
696 | assert !issue.description.match(/^---$/) | |
714 |
|
|
697 | assert !issue.description.include?('This paragraph is after the delimiter') | |
715 |
|
|
698 | end | |
716 |
|
|
699 | end | |
717 | end |
|
|||
718 |
|
700 | |||
719 | def test_email_with_long_subject_line |
|
701 | def test_email_with_long_subject_line | |
720 | issue = submit_email('ticket_with_long_subject.eml') |
|
702 | issue = submit_email('ticket_with_long_subject.eml') | |
721 | assert issue.is_a?(Issue) |
|
703 | assert issue.is_a?(Issue) | |
722 | assert_equal issue.subject, 'New ticket on a given project with a very long subject line which exceeds 255 chars and should not be ignored but chopped off. And if the subject line is still not long enough, we just add more text. And more text. Wow, this is really annoying. Especially, if you have nothing to say...'[0,255] |
|
704 | assert_equal issue.subject, 'New ticket on a given project with a very long subject line which exceeds 255 chars and should not be ignored but chopped off. And if the subject line is still not long enough, we just add more text. And more text. Wow, this is really annoying. Especially, if you have nothing to say...'[0,255] | |
723 | end |
|
705 | end | |
724 |
|
706 | |||
725 | def test_new_user_from_attributes_should_return_valid_user |
|
707 | def test_new_user_from_attributes_should_return_valid_user | |
726 | to_test = { |
|
708 | to_test = { | |
727 | # [address, name] => [login, firstname, lastname] |
|
709 | # [address, name] => [login, firstname, lastname] | |
728 | ['jsmith@example.net', nil] => ['jsmith@example.net', 'jsmith', '-'], |
|
710 | ['jsmith@example.net', nil] => ['jsmith@example.net', 'jsmith', '-'], | |
729 | ['jsmith@example.net', 'John'] => ['jsmith@example.net', 'John', '-'], |
|
711 | ['jsmith@example.net', 'John'] => ['jsmith@example.net', 'John', '-'], | |
730 | ['jsmith@example.net', 'John Smith'] => ['jsmith@example.net', 'John', 'Smith'], |
|
712 | ['jsmith@example.net', 'John Smith'] => ['jsmith@example.net', 'John', 'Smith'], | |
731 | ['jsmith@example.net', 'John Paul Smith'] => ['jsmith@example.net', 'John', 'Paul Smith'], |
|
713 | ['jsmith@example.net', 'John Paul Smith'] => ['jsmith@example.net', 'John', 'Paul Smith'], | |
732 | ['jsmith@example.net', 'AVeryLongFirstnameThatExceedsTheMaximumLength Smith'] => ['jsmith@example.net', 'AVeryLongFirstnameThatExceedsT', 'Smith'], |
|
714 | ['jsmith@example.net', 'AVeryLongFirstnameThatExceedsTheMaximumLength Smith'] => ['jsmith@example.net', 'AVeryLongFirstnameThatExceedsT', 'Smith'], | |
733 | ['jsmith@example.net', 'John AVeryLongLastnameThatExceedsTheMaximumLength'] => ['jsmith@example.net', 'John', 'AVeryLongLastnameThatExceedsTh'] |
|
715 | ['jsmith@example.net', 'John AVeryLongLastnameThatExceedsTheMaximumLength'] => ['jsmith@example.net', 'John', 'AVeryLongLastnameThatExceedsTh'] | |
734 | } |
|
716 | } | |
735 |
|
717 | |||
736 | to_test.each do |attrs, expected| |
|
718 | to_test.each do |attrs, expected| | |
737 | user = MailHandler.new_user_from_attributes(attrs.first, attrs.last) |
|
719 | user = MailHandler.new_user_from_attributes(attrs.first, attrs.last) | |
738 |
|
720 | |||
739 | assert user.valid?, user.errors.full_messages.to_s |
|
721 | assert user.valid?, user.errors.full_messages.to_s | |
740 | assert_equal attrs.first, user.mail |
|
722 | assert_equal attrs.first, user.mail | |
741 | assert_equal expected[0], user.login |
|
723 | assert_equal expected[0], user.login | |
742 | assert_equal expected[1], user.firstname |
|
724 | assert_equal expected[1], user.firstname | |
743 | assert_equal expected[2], user.lastname |
|
725 | assert_equal expected[2], user.lastname | |
744 | end |
|
726 | end | |
745 | end |
|
727 | end | |
746 |
|
728 | |||
747 | def test_new_user_from_attributes_should_respect_minimum_password_length |
|
729 | def test_new_user_from_attributes_should_respect_minimum_password_length | |
748 | with_settings :password_min_length => 15 do |
|
730 | with_settings :password_min_length => 15 do | |
749 | user = MailHandler.new_user_from_attributes('jsmith@example.net') |
|
731 | user = MailHandler.new_user_from_attributes('jsmith@example.net') | |
750 | assert user.valid? |
|
732 | assert user.valid? | |
751 | assert user.password.length >= 15 |
|
733 | assert user.password.length >= 15 | |
752 | end |
|
734 | end | |
753 | end |
|
735 | end | |
754 |
|
736 | |||
755 | def test_new_user_from_attributes_should_use_default_login_if_invalid |
|
737 | def test_new_user_from_attributes_should_use_default_login_if_invalid | |
756 | user = MailHandler.new_user_from_attributes('foo+bar@example.net') |
|
738 | user = MailHandler.new_user_from_attributes('foo+bar@example.net') | |
757 | assert user.valid? |
|
739 | assert user.valid? | |
758 | assert user.login =~ /^user[a-f0-9]+$/ |
|
740 | assert user.login =~ /^user[a-f0-9]+$/ | |
759 | assert_equal 'foo+bar@example.net', user.mail |
|
741 | assert_equal 'foo+bar@example.net', user.mail | |
760 | end |
|
742 | end | |
761 |
|
743 | |||
762 | def test_new_user_with_utf8_encoded_fullname_should_be_decoded |
|
744 | def test_new_user_with_utf8_encoded_fullname_should_be_decoded | |
763 | assert_difference 'User.count' do |
|
745 | assert_difference 'User.count' do | |
764 | issue = submit_email( |
|
746 | issue = submit_email( | |
765 | 'fullname_of_sender_as_utf8_encoded.eml', |
|
747 | 'fullname_of_sender_as_utf8_encoded.eml', | |
766 | :issue => {:project => 'ecookbook'}, |
|
748 | :issue => {:project => 'ecookbook'}, | |
767 | :unknown_user => 'create' |
|
749 | :unknown_user => 'create' | |
768 | ) |
|
750 | ) | |
769 | end |
|
751 | end | |
770 |
|
752 | |||
771 | user = User.first(:order => 'id DESC') |
|
753 | user = User.first(:order => 'id DESC') | |
772 | assert_equal "foo@example.org", user.mail |
|
754 | assert_equal "foo@example.org", user.mail | |
773 | str1 = "\xc3\x84\xc3\xa4" |
|
755 | str1 = "\xc3\x84\xc3\xa4" | |
774 | str2 = "\xc3\x96\xc3\xb6" |
|
756 | str2 = "\xc3\x96\xc3\xb6" | |
775 | str1.force_encoding('UTF-8') if str1.respond_to?(:force_encoding) |
|
757 | str1.force_encoding('UTF-8') if str1.respond_to?(:force_encoding) | |
776 | str2.force_encoding('UTF-8') if str2.respond_to?(:force_encoding) |
|
758 | str2.force_encoding('UTF-8') if str2.respond_to?(:force_encoding) | |
777 | assert_equal str1, user.firstname |
|
759 | assert_equal str1, user.firstname | |
778 | assert_equal str2, user.lastname |
|
760 | assert_equal str2, user.lastname | |
779 | end |
|
761 | end | |
780 |
|
762 | |||
781 | private |
|
763 | private | |
782 |
|
764 | |||
783 | def submit_email(filename, options={}) |
|
765 | def submit_email(filename, options={}) | |
784 | raw = IO.read(File.join(FIXTURES_PATH, filename)) |
|
766 | raw = IO.read(File.join(FIXTURES_PATH, filename)) | |
785 | yield raw if block_given? |
|
767 | yield raw if block_given? | |
786 | MailHandler.receive(raw, options) |
|
768 | MailHandler.receive(raw, options) | |
787 | end |
|
769 | end | |
788 |
|
770 | |||
789 | def assert_issue_created(issue) |
|
771 | def assert_issue_created(issue) | |
790 | assert issue.is_a?(Issue) |
|
772 | assert issue.is_a?(Issue) | |
791 | assert !issue.new_record? |
|
773 | assert !issue.new_record? | |
792 | issue.reload |
|
774 | issue.reload | |
793 | end |
|
775 | end | |
794 | end |
|
776 | end |
@@ -1,618 +1,614 | |||||
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 MailerTest < ActiveSupport::TestCase |
|
20 | class MailerTest < ActiveSupport::TestCase | |
21 | include Redmine::I18n |
|
21 | include Redmine::I18n | |
22 | include ActionDispatch::Assertions::SelectorAssertions |
|
22 | include ActionDispatch::Assertions::SelectorAssertions | |
23 | fixtures :projects, :enabled_modules, :issues, :users, :members, |
|
23 | fixtures :projects, :enabled_modules, :issues, :users, :members, | |
24 | :member_roles, :roles, :documents, :attachments, :news, |
|
24 | :member_roles, :roles, :documents, :attachments, :news, | |
25 | :tokens, :journals, :journal_details, :changesets, |
|
25 | :tokens, :journals, :journal_details, :changesets, | |
26 | :trackers, :projects_trackers, |
|
26 | :trackers, :projects_trackers, | |
27 | :issue_statuses, :enumerations, :messages, :boards, :repositories, |
|
27 | :issue_statuses, :enumerations, :messages, :boards, :repositories, | |
28 | :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions, |
|
28 | :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions, | |
29 | :versions, |
|
29 | :versions, | |
30 | :comments |
|
30 | :comments | |
31 |
|
31 | |||
32 | def setup |
|
32 | def setup | |
33 | ActionMailer::Base.deliveries.clear |
|
33 | ActionMailer::Base.deliveries.clear | |
34 | Setting.host_name = 'mydomain.foo' |
|
34 | Setting.host_name = 'mydomain.foo' | |
35 | Setting.protocol = 'http' |
|
35 | Setting.protocol = 'http' | |
36 | Setting.plain_text_mail = '0' |
|
36 | Setting.plain_text_mail = '0' | |
37 | end |
|
37 | end | |
38 |
|
38 | |||
39 | def test_generated_links_in_emails |
|
39 | def test_generated_links_in_emails | |
40 | Setting.default_language = 'en' |
|
40 | Setting.default_language = 'en' | |
41 | Setting.host_name = 'mydomain.foo' |
|
41 | Setting.host_name = 'mydomain.foo' | |
42 | Setting.protocol = 'https' |
|
42 | Setting.protocol = 'https' | |
43 |
|
43 | |||
44 | journal = Journal.find(3) |
|
44 | journal = Journal.find(3) | |
45 | assert Mailer.issue_edit(journal).deliver |
|
45 | assert Mailer.issue_edit(journal).deliver | |
46 |
|
46 | |||
47 | mail = last_email |
|
47 | mail = last_email | |
48 | assert_not_nil mail |
|
48 | assert_not_nil mail | |
49 |
|
49 | |||
50 | assert_select_email do |
|
50 | assert_select_email do | |
51 | # link to the main ticket |
|
51 | # link to the main ticket | |
52 | assert_select 'a[href=?]', |
|
52 | assert_select 'a[href=?]', | |
53 | 'https://mydomain.foo/issues/2#change-3', |
|
53 | 'https://mydomain.foo/issues/2#change-3', | |
54 | :text => 'Feature request #2: Add ingredients categories' |
|
54 | :text => 'Feature request #2: Add ingredients categories' | |
55 | # link to a referenced ticket |
|
55 | # link to a referenced ticket | |
56 | assert_select 'a[href=?][title=?]', |
|
56 | assert_select 'a[href=?][title=?]', | |
57 | 'https://mydomain.foo/issues/1', |
|
57 | 'https://mydomain.foo/issues/1', | |
58 | 'Can't print recipes (New)', |
|
58 | 'Can't print recipes (New)', | |
59 | :text => '#1' |
|
59 | :text => '#1' | |
60 | # link to a changeset |
|
60 | # link to a changeset | |
61 | assert_select 'a[href=?][title=?]', |
|
61 | assert_select 'a[href=?][title=?]', | |
62 | 'https://mydomain.foo/projects/ecookbook/repository/revisions/2', |
|
62 | 'https://mydomain.foo/projects/ecookbook/repository/revisions/2', | |
63 | 'This commit fixes #1, #2 and references #1 & #3', |
|
63 | 'This commit fixes #1, #2 and references #1 & #3', | |
64 | :text => 'r2' |
|
64 | :text => 'r2' | |
65 | # link to a description diff |
|
65 | # link to a description diff | |
66 | assert_select 'a[href=?][title=?]', |
|
66 | assert_select 'a[href=?][title=?]', | |
67 | 'https://mydomain.foo/journals/diff/3?detail_id=4', |
|
67 | 'https://mydomain.foo/journals/diff/3?detail_id=4', | |
68 | 'View differences', |
|
68 | 'View differences', | |
69 | :text => 'diff' |
|
69 | :text => 'diff' | |
70 | # link to an attachment |
|
70 | # link to an attachment | |
71 | assert_select 'a[href=?]', |
|
71 | assert_select 'a[href=?]', | |
72 | 'https://mydomain.foo/attachments/download/4/source.rb', |
|
72 | 'https://mydomain.foo/attachments/download/4/source.rb', | |
73 | :text => 'source.rb' |
|
73 | :text => 'source.rb' | |
74 | end |
|
74 | end | |
75 | end |
|
75 | end | |
76 |
|
76 | |||
77 | def test_generated_links_with_prefix |
|
77 | def test_generated_links_with_prefix | |
78 | Setting.default_language = 'en' |
|
78 | Setting.default_language = 'en' | |
79 | relative_url_root = Redmine::Utils.relative_url_root |
|
79 | relative_url_root = Redmine::Utils.relative_url_root | |
80 | Setting.host_name = 'mydomain.foo/rdm' |
|
80 | Setting.host_name = 'mydomain.foo/rdm' | |
81 | Setting.protocol = 'http' |
|
81 | Setting.protocol = 'http' | |
82 |
|
82 | |||
83 | journal = Journal.find(3) |
|
83 | journal = Journal.find(3) | |
84 | assert Mailer.issue_edit(journal).deliver |
|
84 | assert Mailer.issue_edit(journal).deliver | |
85 |
|
85 | |||
86 | mail = last_email |
|
86 | mail = last_email | |
87 | assert_not_nil mail |
|
87 | assert_not_nil mail | |
88 |
|
88 | |||
89 | assert_select_email do |
|
89 | assert_select_email do | |
90 | # link to the main ticket |
|
90 | # link to the main ticket | |
91 | assert_select 'a[href=?]', |
|
91 | assert_select 'a[href=?]', | |
92 | 'http://mydomain.foo/rdm/issues/2#change-3', |
|
92 | 'http://mydomain.foo/rdm/issues/2#change-3', | |
93 | :text => 'Feature request #2: Add ingredients categories' |
|
93 | :text => 'Feature request #2: Add ingredients categories' | |
94 | # link to a referenced ticket |
|
94 | # link to a referenced ticket | |
95 | assert_select 'a[href=?][title=?]', |
|
95 | assert_select 'a[href=?][title=?]', | |
96 | 'http://mydomain.foo/rdm/issues/1', |
|
96 | 'http://mydomain.foo/rdm/issues/1', | |
97 | 'Can't print recipes (New)', |
|
97 | 'Can't print recipes (New)', | |
98 | :text => '#1' |
|
98 | :text => '#1' | |
99 | # link to a changeset |
|
99 | # link to a changeset | |
100 | assert_select 'a[href=?][title=?]', |
|
100 | assert_select 'a[href=?][title=?]', | |
101 | 'http://mydomain.foo/rdm/projects/ecookbook/repository/revisions/2', |
|
101 | 'http://mydomain.foo/rdm/projects/ecookbook/repository/revisions/2', | |
102 | 'This commit fixes #1, #2 and references #1 & #3', |
|
102 | 'This commit fixes #1, #2 and references #1 & #3', | |
103 | :text => 'r2' |
|
103 | :text => 'r2' | |
104 | # link to a description diff |
|
104 | # link to a description diff | |
105 | assert_select 'a[href=?][title=?]', |
|
105 | assert_select 'a[href=?][title=?]', | |
106 | 'http://mydomain.foo/rdm/journals/diff/3?detail_id=4', |
|
106 | 'http://mydomain.foo/rdm/journals/diff/3?detail_id=4', | |
107 | 'View differences', |
|
107 | 'View differences', | |
108 | :text => 'diff' |
|
108 | :text => 'diff' | |
109 | # link to an attachment |
|
109 | # link to an attachment | |
110 | assert_select 'a[href=?]', |
|
110 | assert_select 'a[href=?]', | |
111 | 'http://mydomain.foo/rdm/attachments/download/4/source.rb', |
|
111 | 'http://mydomain.foo/rdm/attachments/download/4/source.rb', | |
112 | :text => 'source.rb' |
|
112 | :text => 'source.rb' | |
113 | end |
|
113 | end | |
114 | end |
|
114 | end | |
115 |
|
115 | |||
116 | def test_generated_links_with_prefix_and_no_relative_url_root |
|
116 | def test_generated_links_with_prefix_and_no_relative_url_root | |
117 | Setting.default_language = 'en' |
|
117 | Setting.default_language = 'en' | |
118 | relative_url_root = Redmine::Utils.relative_url_root |
|
118 | relative_url_root = Redmine::Utils.relative_url_root | |
119 | Setting.host_name = 'mydomain.foo/rdm' |
|
119 | Setting.host_name = 'mydomain.foo/rdm' | |
120 | Setting.protocol = 'http' |
|
120 | Setting.protocol = 'http' | |
121 | Redmine::Utils.relative_url_root = nil |
|
121 | Redmine::Utils.relative_url_root = nil | |
122 |
|
122 | |||
123 | journal = Journal.find(3) |
|
123 | journal = Journal.find(3) | |
124 | assert Mailer.issue_edit(journal).deliver |
|
124 | assert Mailer.issue_edit(journal).deliver | |
125 |
|
125 | |||
126 | mail = last_email |
|
126 | mail = last_email | |
127 | assert_not_nil mail |
|
127 | assert_not_nil mail | |
128 |
|
128 | |||
129 | assert_select_email do |
|
129 | assert_select_email do | |
130 | # link to the main ticket |
|
130 | # link to the main ticket | |
131 | assert_select 'a[href=?]', |
|
131 | assert_select 'a[href=?]', | |
132 | 'http://mydomain.foo/rdm/issues/2#change-3', |
|
132 | 'http://mydomain.foo/rdm/issues/2#change-3', | |
133 | :text => 'Feature request #2: Add ingredients categories' |
|
133 | :text => 'Feature request #2: Add ingredients categories' | |
134 | # link to a referenced ticket |
|
134 | # link to a referenced ticket | |
135 | assert_select 'a[href=?][title=?]', |
|
135 | assert_select 'a[href=?][title=?]', | |
136 | 'http://mydomain.foo/rdm/issues/1', |
|
136 | 'http://mydomain.foo/rdm/issues/1', | |
137 | 'Can't print recipes (New)', |
|
137 | 'Can't print recipes (New)', | |
138 | :text => '#1' |
|
138 | :text => '#1' | |
139 | # link to a changeset |
|
139 | # link to a changeset | |
140 | assert_select 'a[href=?][title=?]', |
|
140 | assert_select 'a[href=?][title=?]', | |
141 | 'http://mydomain.foo/rdm/projects/ecookbook/repository/revisions/2', |
|
141 | 'http://mydomain.foo/rdm/projects/ecookbook/repository/revisions/2', | |
142 | 'This commit fixes #1, #2 and references #1 & #3', |
|
142 | 'This commit fixes #1, #2 and references #1 & #3', | |
143 | :text => 'r2' |
|
143 | :text => 'r2' | |
144 | # link to a description diff |
|
144 | # link to a description diff | |
145 | assert_select 'a[href=?][title=?]', |
|
145 | assert_select 'a[href=?][title=?]', | |
146 | 'http://mydomain.foo/rdm/journals/diff/3?detail_id=4', |
|
146 | 'http://mydomain.foo/rdm/journals/diff/3?detail_id=4', | |
147 | 'View differences', |
|
147 | 'View differences', | |
148 | :text => 'diff' |
|
148 | :text => 'diff' | |
149 | # link to an attachment |
|
149 | # link to an attachment | |
150 | assert_select 'a[href=?]', |
|
150 | assert_select 'a[href=?]', | |
151 | 'http://mydomain.foo/rdm/attachments/download/4/source.rb', |
|
151 | 'http://mydomain.foo/rdm/attachments/download/4/source.rb', | |
152 | :text => 'source.rb' |
|
152 | :text => 'source.rb' | |
153 | end |
|
153 | end | |
154 | ensure |
|
154 | ensure | |
155 | # restore it |
|
155 | # restore it | |
156 | Redmine::Utils.relative_url_root = relative_url_root |
|
156 | Redmine::Utils.relative_url_root = relative_url_root | |
157 | end |
|
157 | end | |
158 |
|
158 | |||
159 | def test_email_headers |
|
159 | def test_email_headers | |
160 | issue = Issue.find(1) |
|
160 | issue = Issue.find(1) | |
161 | Mailer.issue_add(issue).deliver |
|
161 | Mailer.issue_add(issue).deliver | |
162 | mail = last_email |
|
162 | mail = last_email | |
163 | assert_not_nil mail |
|
163 | assert_not_nil mail | |
164 | assert_equal 'OOF', mail.header['X-Auto-Response-Suppress'].to_s |
|
164 | assert_equal 'OOF', mail.header['X-Auto-Response-Suppress'].to_s | |
165 | assert_equal 'auto-generated', mail.header['Auto-Submitted'].to_s |
|
165 | assert_equal 'auto-generated', mail.header['Auto-Submitted'].to_s | |
166 | assert_equal '<redmine.example.net>', mail.header['List-Id'].to_s |
|
166 | assert_equal '<redmine.example.net>', mail.header['List-Id'].to_s | |
167 | end |
|
167 | end | |
168 |
|
168 | |||
169 | def test_email_headers_should_include_sender |
|
169 | def test_email_headers_should_include_sender | |
170 | issue = Issue.find(1) |
|
170 | issue = Issue.find(1) | |
171 | Mailer.issue_add(issue).deliver |
|
171 | Mailer.issue_add(issue).deliver | |
172 | mail = last_email |
|
172 | mail = last_email | |
173 | assert_equal issue.author.login, mail.header['X-Redmine-Sender'].to_s |
|
173 | assert_equal issue.author.login, mail.header['X-Redmine-Sender'].to_s | |
174 | end |
|
174 | end | |
175 |
|
175 | |||
176 | def test_plain_text_mail |
|
176 | def test_plain_text_mail | |
177 | Setting.plain_text_mail = 1 |
|
177 | Setting.plain_text_mail = 1 | |
178 | journal = Journal.find(2) |
|
178 | journal = Journal.find(2) | |
179 | Mailer.issue_edit(journal).deliver |
|
179 | Mailer.issue_edit(journal).deliver | |
180 | mail = last_email |
|
180 | mail = last_email | |
181 | assert_equal "text/plain; charset=UTF-8", mail.content_type |
|
181 | assert_equal "text/plain; charset=UTF-8", mail.content_type | |
182 | assert_equal 0, mail.parts.size |
|
182 | assert_equal 0, mail.parts.size | |
183 | assert !mail.encoded.include?('href') |
|
183 | assert !mail.encoded.include?('href') | |
184 | end |
|
184 | end | |
185 |
|
185 | |||
186 | def test_html_mail |
|
186 | def test_html_mail | |
187 | Setting.plain_text_mail = 0 |
|
187 | Setting.plain_text_mail = 0 | |
188 | journal = Journal.find(2) |
|
188 | journal = Journal.find(2) | |
189 | Mailer.issue_edit(journal).deliver |
|
189 | Mailer.issue_edit(journal).deliver | |
190 | mail = last_email |
|
190 | mail = last_email | |
191 | assert_equal 2, mail.parts.size |
|
191 | assert_equal 2, mail.parts.size | |
192 | assert mail.encoded.include?('href') |
|
192 | assert mail.encoded.include?('href') | |
193 | end |
|
193 | end | |
194 |
|
194 | |||
195 | def test_from_header |
|
195 | def test_from_header | |
196 | with_settings :mail_from => 'redmine@example.net' do |
|
196 | with_settings :mail_from => 'redmine@example.net' do | |
197 | Mailer.test_email(User.find(1)).deliver |
|
197 | Mailer.test_email(User.find(1)).deliver | |
198 | end |
|
198 | end | |
199 | mail = last_email |
|
199 | mail = last_email | |
200 | assert_equal 'redmine@example.net', mail.from_addrs.first |
|
200 | assert_equal 'redmine@example.net', mail.from_addrs.first | |
201 | end |
|
201 | end | |
202 |
|
202 | |||
203 | def test_from_header_with_phrase |
|
203 | def test_from_header_with_phrase | |
204 | with_settings :mail_from => 'Redmine app <redmine@example.net>' do |
|
204 | with_settings :mail_from => 'Redmine app <redmine@example.net>' do | |
205 | Mailer.test_email(User.find(1)).deliver |
|
205 | Mailer.test_email(User.find(1)).deliver | |
206 | end |
|
206 | end | |
207 | mail = last_email |
|
207 | mail = last_email | |
208 | assert_equal 'redmine@example.net', mail.from_addrs.first |
|
208 | assert_equal 'redmine@example.net', mail.from_addrs.first | |
209 | assert_equal 'Redmine app <redmine@example.net>', mail.header['From'].to_s |
|
209 | assert_equal 'Redmine app <redmine@example.net>', mail.header['From'].to_s | |
210 | end |
|
210 | end | |
211 |
|
211 | |||
212 | def test_should_not_send_email_without_recipient |
|
212 | def test_should_not_send_email_without_recipient | |
213 | news = News.first |
|
213 | news = News.first | |
214 | user = news.author |
|
214 | user = news.author | |
215 | # Remove members except news author |
|
215 | # Remove members except news author | |
216 | news.project.memberships.each {|m| m.destroy unless m.user == user} |
|
216 | news.project.memberships.each {|m| m.destroy unless m.user == user} | |
217 |
|
217 | |||
218 | user.pref[:no_self_notified] = false |
|
218 | user.pref[:no_self_notified] = false | |
219 | user.pref.save |
|
219 | user.pref.save | |
220 | User.current = user |
|
220 | User.current = user | |
221 | Mailer.news_added(news.reload).deliver |
|
221 | Mailer.news_added(news.reload).deliver | |
222 | assert_equal 1, last_email.bcc.size |
|
222 | assert_equal 1, last_email.bcc.size | |
223 |
|
223 | |||
224 | # nobody to notify |
|
224 | # nobody to notify | |
225 | user.pref[:no_self_notified] = true |
|
225 | user.pref[:no_self_notified] = true | |
226 | user.pref.save |
|
226 | user.pref.save | |
227 | User.current = user |
|
227 | User.current = user | |
228 | ActionMailer::Base.deliveries.clear |
|
228 | ActionMailer::Base.deliveries.clear | |
229 | Mailer.news_added(news.reload).deliver |
|
229 | Mailer.news_added(news.reload).deliver | |
230 | assert ActionMailer::Base.deliveries.empty? |
|
230 | assert ActionMailer::Base.deliveries.empty? | |
231 | end |
|
231 | end | |
232 |
|
232 | |||
233 | def test_issue_add_message_id |
|
233 | def test_issue_add_message_id | |
234 | issue = Issue.find(1) |
|
234 | issue = Issue.find(1) | |
235 | Mailer.issue_add(issue).deliver |
|
235 | Mailer.issue_add(issue).deliver | |
236 | mail = last_email |
|
236 | mail = last_email | |
237 | assert_equal Mailer.message_id_for(issue), mail.message_id |
|
237 | assert_equal Mailer.message_id_for(issue), mail.message_id | |
238 | assert_nil mail.references |
|
238 | assert_nil mail.references | |
239 | end |
|
239 | end | |
240 |
|
240 | |||
241 | def test_issue_edit_message_id |
|
241 | def test_issue_edit_message_id | |
242 | journal = Journal.find(1) |
|
242 | journal = Journal.find(1) | |
243 | Mailer.issue_edit(journal).deliver |
|
243 | Mailer.issue_edit(journal).deliver | |
244 | mail = last_email |
|
244 | mail = last_email | |
245 | assert_equal Mailer.message_id_for(journal), mail.message_id |
|
245 | assert_equal Mailer.message_id_for(journal), mail.message_id | |
246 | assert_include Mailer.message_id_for(journal.issue), mail.references |
|
246 | assert_include Mailer.message_id_for(journal.issue), mail.references | |
247 | assert_select_email do |
|
247 | assert_select_email do | |
248 | # link to the update |
|
248 | # link to the update | |
249 | assert_select "a[href=?]", |
|
249 | assert_select "a[href=?]", | |
250 | "http://mydomain.foo/issues/#{journal.journalized_id}#change-#{journal.id}" |
|
250 | "http://mydomain.foo/issues/#{journal.journalized_id}#change-#{journal.id}" | |
251 | end |
|
251 | end | |
252 | end |
|
252 | end | |
253 |
|
253 | |||
254 | def test_message_posted_message_id |
|
254 | def test_message_posted_message_id | |
255 | message = Message.find(1) |
|
255 | message = Message.find(1) | |
256 | Mailer.message_posted(message).deliver |
|
256 | Mailer.message_posted(message).deliver | |
257 | mail = last_email |
|
257 | mail = last_email | |
258 | assert_equal Mailer.message_id_for(message), mail.message_id |
|
258 | assert_equal Mailer.message_id_for(message), mail.message_id | |
259 | assert_nil mail.references |
|
259 | assert_nil mail.references | |
260 | assert_select_email do |
|
260 | assert_select_email do | |
261 | # link to the message |
|
261 | # link to the message | |
262 | assert_select "a[href=?]", |
|
262 | assert_select "a[href=?]", | |
263 | "http://mydomain.foo/boards/#{message.board.id}/topics/#{message.id}", |
|
263 | "http://mydomain.foo/boards/#{message.board.id}/topics/#{message.id}", | |
264 | :text => message.subject |
|
264 | :text => message.subject | |
265 | end |
|
265 | end | |
266 | end |
|
266 | end | |
267 |
|
267 | |||
268 | def test_reply_posted_message_id |
|
268 | def test_reply_posted_message_id | |
269 | message = Message.find(3) |
|
269 | message = Message.find(3) | |
270 | Mailer.message_posted(message).deliver |
|
270 | Mailer.message_posted(message).deliver | |
271 | mail = last_email |
|
271 | mail = last_email | |
272 | assert_equal Mailer.message_id_for(message), mail.message_id |
|
272 | assert_equal Mailer.message_id_for(message), mail.message_id | |
273 | assert_include Mailer.message_id_for(message.parent), mail.references |
|
273 | assert_include Mailer.message_id_for(message.parent), mail.references | |
274 | assert_select_email do |
|
274 | assert_select_email do | |
275 | # link to the reply |
|
275 | # link to the reply | |
276 | assert_select "a[href=?]", |
|
276 | assert_select "a[href=?]", | |
277 | "http://mydomain.foo/boards/#{message.board.id}/topics/#{message.root.id}?r=#{message.id}#message-#{message.id}", |
|
277 | "http://mydomain.foo/boards/#{message.board.id}/topics/#{message.root.id}?r=#{message.id}#message-#{message.id}", | |
278 | :text => message.subject |
|
278 | :text => message.subject | |
279 | end |
|
279 | end | |
280 | end |
|
280 | end | |
281 |
|
281 | |||
282 | context("#issue_add") do |
|
282 | test "#issue_add should notify project members" do | |
283 | setup do |
|
283 | issue = Issue.find(1) | |
284 | ActionMailer::Base.deliveries.clear |
|
284 | assert Mailer.issue_add(issue).deliver | |
285 | Setting.bcc_recipients = '1' |
|
|||
286 | @issue = Issue.find(1) |
|
|||
287 | end |
|
|||
288 |
|
||||
289 | should "notify project members" do |
|
|||
290 | assert Mailer.issue_add(@issue).deliver |
|
|||
291 |
|
|
285 | assert last_email.bcc.include?('dlopper@somenet.foo') | |
292 |
|
|
286 | end | |
293 |
|
287 | |||
294 |
|
|
288 | test "#issue_add should not notify project members that are not allow to view the issue" do | |
|
289 | issue = Issue.find(1) | |||
295 |
|
|
290 | Role.find(2).remove_permission!(:view_issues) | |
296 |
|
|
291 | assert Mailer.issue_add(issue).deliver | |
297 |
|
|
292 | assert !last_email.bcc.include?('dlopper@somenet.foo') | |
298 |
|
|
293 | end | |
299 |
|
294 | |||
300 |
|
|
295 | test "#issue_add should notify issue watchers" do | |
|
296 | issue = Issue.find(1) | |||
301 |
|
|
297 | user = User.find(9) | |
302 |
|
|
298 | # minimal email notification options | |
303 |
|
|
299 | user.pref[:no_self_notified] = '1' | |
304 |
|
|
300 | user.pref.save | |
305 |
|
|
301 | user.mail_notification = false | |
306 |
|
|
302 | user.save | |
307 |
|
303 | |||
308 |
|
|
304 | Watcher.create!(:watchable => issue, :user => user) | |
309 |
|
|
305 | assert Mailer.issue_add(issue).deliver | |
310 |
|
|
306 | assert last_email.bcc.include?(user.mail) | |
311 |
|
|
307 | end | |
312 |
|
308 | |||
313 |
|
|
309 | test "#issue_add should not notify watchers not allowed to view the issue" do | |
|
310 | issue = Issue.find(1) | |||
314 |
|
|
311 | user = User.find(9) | |
315 |
|
|
312 | Watcher.create!(:watchable => issue, :user => user) | |
316 |
|
|
313 | Role.non_member.remove_permission!(:view_issues) | |
317 |
|
|
314 | assert Mailer.issue_add(issue).deliver | |
318 |
|
|
315 | assert !last_email.bcc.include?(user.mail) | |
319 |
|
|
316 | end | |
320 | end |
|
|||
321 |
|
317 | |||
322 | # test mailer methods for each language |
|
318 | # test mailer methods for each language | |
323 | def test_issue_add |
|
319 | def test_issue_add | |
324 | issue = Issue.find(1) |
|
320 | issue = Issue.find(1) | |
325 | valid_languages.each do |lang| |
|
321 | valid_languages.each do |lang| | |
326 | Setting.default_language = lang.to_s |
|
322 | Setting.default_language = lang.to_s | |
327 | assert Mailer.issue_add(issue).deliver |
|
323 | assert Mailer.issue_add(issue).deliver | |
328 | end |
|
324 | end | |
329 | end |
|
325 | end | |
330 |
|
326 | |||
331 | def test_issue_edit |
|
327 | def test_issue_edit | |
332 | journal = Journal.find(1) |
|
328 | journal = Journal.find(1) | |
333 | valid_languages.each do |lang| |
|
329 | valid_languages.each do |lang| | |
334 | Setting.default_language = lang.to_s |
|
330 | Setting.default_language = lang.to_s | |
335 | assert Mailer.issue_edit(journal).deliver |
|
331 | assert Mailer.issue_edit(journal).deliver | |
336 | end |
|
332 | end | |
337 | end |
|
333 | end | |
338 |
|
334 | |||
339 | def test_issue_edit_should_send_private_notes_to_users_with_permission_only |
|
335 | def test_issue_edit_should_send_private_notes_to_users_with_permission_only | |
340 | journal = Journal.find(1) |
|
336 | journal = Journal.find(1) | |
341 | journal.private_notes = true |
|
337 | journal.private_notes = true | |
342 | journal.save! |
|
338 | journal.save! | |
343 |
|
339 | |||
344 | Role.find(2).add_permission! :view_private_notes |
|
340 | Role.find(2).add_permission! :view_private_notes | |
345 | Mailer.issue_edit(journal).deliver |
|
341 | Mailer.issue_edit(journal).deliver | |
346 | assert_equal %w(dlopper@somenet.foo jsmith@somenet.foo), ActionMailer::Base.deliveries.last.bcc.sort |
|
342 | assert_equal %w(dlopper@somenet.foo jsmith@somenet.foo), ActionMailer::Base.deliveries.last.bcc.sort | |
347 |
|
343 | |||
348 | Role.find(2).remove_permission! :view_private_notes |
|
344 | Role.find(2).remove_permission! :view_private_notes | |
349 | Mailer.issue_edit(journal).deliver |
|
345 | Mailer.issue_edit(journal).deliver | |
350 | assert_equal %w(jsmith@somenet.foo), ActionMailer::Base.deliveries.last.bcc.sort |
|
346 | assert_equal %w(jsmith@somenet.foo), ActionMailer::Base.deliveries.last.bcc.sort | |
351 | end |
|
347 | end | |
352 |
|
348 | |||
353 | def test_issue_edit_should_send_private_notes_to_watchers_with_permission_only |
|
349 | def test_issue_edit_should_send_private_notes_to_watchers_with_permission_only | |
354 | Issue.find(1).set_watcher(User.find_by_login('someone')) |
|
350 | Issue.find(1).set_watcher(User.find_by_login('someone')) | |
355 | journal = Journal.find(1) |
|
351 | journal = Journal.find(1) | |
356 | journal.private_notes = true |
|
352 | journal.private_notes = true | |
357 | journal.save! |
|
353 | journal.save! | |
358 |
|
354 | |||
359 | Role.non_member.add_permission! :view_private_notes |
|
355 | Role.non_member.add_permission! :view_private_notes | |
360 | Mailer.issue_edit(journal).deliver |
|
356 | Mailer.issue_edit(journal).deliver | |
361 | assert_include 'someone@foo.bar', ActionMailer::Base.deliveries.last.bcc.sort |
|
357 | assert_include 'someone@foo.bar', ActionMailer::Base.deliveries.last.bcc.sort | |
362 |
|
358 | |||
363 | Role.non_member.remove_permission! :view_private_notes |
|
359 | Role.non_member.remove_permission! :view_private_notes | |
364 | Mailer.issue_edit(journal).deliver |
|
360 | Mailer.issue_edit(journal).deliver | |
365 | assert_not_include 'someone@foo.bar', ActionMailer::Base.deliveries.last.bcc.sort |
|
361 | assert_not_include 'someone@foo.bar', ActionMailer::Base.deliveries.last.bcc.sort | |
366 | end |
|
362 | end | |
367 |
|
363 | |||
368 | def test_document_added |
|
364 | def test_document_added | |
369 | document = Document.find(1) |
|
365 | document = Document.find(1) | |
370 | valid_languages.each do |lang| |
|
366 | valid_languages.each do |lang| | |
371 | Setting.default_language = lang.to_s |
|
367 | Setting.default_language = lang.to_s | |
372 | assert Mailer.document_added(document).deliver |
|
368 | assert Mailer.document_added(document).deliver | |
373 | end |
|
369 | end | |
374 | end |
|
370 | end | |
375 |
|
371 | |||
376 | def test_attachments_added |
|
372 | def test_attachments_added | |
377 | attachements = [ Attachment.find_by_container_type('Document') ] |
|
373 | attachements = [ Attachment.find_by_container_type('Document') ] | |
378 | valid_languages.each do |lang| |
|
374 | valid_languages.each do |lang| | |
379 | Setting.default_language = lang.to_s |
|
375 | Setting.default_language = lang.to_s | |
380 | assert Mailer.attachments_added(attachements).deliver |
|
376 | assert Mailer.attachments_added(attachements).deliver | |
381 | end |
|
377 | end | |
382 | end |
|
378 | end | |
383 |
|
379 | |||
384 | def test_version_file_added |
|
380 | def test_version_file_added | |
385 | attachements = [ Attachment.find_by_container_type('Version') ] |
|
381 | attachements = [ Attachment.find_by_container_type('Version') ] | |
386 | assert Mailer.attachments_added(attachements).deliver |
|
382 | assert Mailer.attachments_added(attachements).deliver | |
387 | assert_not_nil last_email.bcc |
|
383 | assert_not_nil last_email.bcc | |
388 | assert last_email.bcc.any? |
|
384 | assert last_email.bcc.any? | |
389 | assert_select_email do |
|
385 | assert_select_email do | |
390 | assert_select "a[href=?]", "http://mydomain.foo/projects/ecookbook/files" |
|
386 | assert_select "a[href=?]", "http://mydomain.foo/projects/ecookbook/files" | |
391 | end |
|
387 | end | |
392 | end |
|
388 | end | |
393 |
|
389 | |||
394 | def test_project_file_added |
|
390 | def test_project_file_added | |
395 | attachements = [ Attachment.find_by_container_type('Project') ] |
|
391 | attachements = [ Attachment.find_by_container_type('Project') ] | |
396 | assert Mailer.attachments_added(attachements).deliver |
|
392 | assert Mailer.attachments_added(attachements).deliver | |
397 | assert_not_nil last_email.bcc |
|
393 | assert_not_nil last_email.bcc | |
398 | assert last_email.bcc.any? |
|
394 | assert last_email.bcc.any? | |
399 | assert_select_email do |
|
395 | assert_select_email do | |
400 | assert_select "a[href=?]", "http://mydomain.foo/projects/ecookbook/files" |
|
396 | assert_select "a[href=?]", "http://mydomain.foo/projects/ecookbook/files" | |
401 | end |
|
397 | end | |
402 | end |
|
398 | end | |
403 |
|
399 | |||
404 | def test_news_added |
|
400 | def test_news_added | |
405 | news = News.first |
|
401 | news = News.first | |
406 | valid_languages.each do |lang| |
|
402 | valid_languages.each do |lang| | |
407 | Setting.default_language = lang.to_s |
|
403 | Setting.default_language = lang.to_s | |
408 | assert Mailer.news_added(news).deliver |
|
404 | assert Mailer.news_added(news).deliver | |
409 | end |
|
405 | end | |
410 | end |
|
406 | end | |
411 |
|
407 | |||
412 | def test_news_comment_added |
|
408 | def test_news_comment_added | |
413 | comment = Comment.find(2) |
|
409 | comment = Comment.find(2) | |
414 | valid_languages.each do |lang| |
|
410 | valid_languages.each do |lang| | |
415 | Setting.default_language = lang.to_s |
|
411 | Setting.default_language = lang.to_s | |
416 | assert Mailer.news_comment_added(comment).deliver |
|
412 | assert Mailer.news_comment_added(comment).deliver | |
417 | end |
|
413 | end | |
418 | end |
|
414 | end | |
419 |
|
415 | |||
420 | def test_message_posted |
|
416 | def test_message_posted | |
421 | message = Message.first |
|
417 | message = Message.first | |
422 | recipients = ([message.root] + message.root.children).collect {|m| m.author.mail if m.author} |
|
418 | recipients = ([message.root] + message.root.children).collect {|m| m.author.mail if m.author} | |
423 | recipients = recipients.compact.uniq |
|
419 | recipients = recipients.compact.uniq | |
424 | valid_languages.each do |lang| |
|
420 | valid_languages.each do |lang| | |
425 | Setting.default_language = lang.to_s |
|
421 | Setting.default_language = lang.to_s | |
426 | assert Mailer.message_posted(message).deliver |
|
422 | assert Mailer.message_posted(message).deliver | |
427 | end |
|
423 | end | |
428 | end |
|
424 | end | |
429 |
|
425 | |||
430 | def test_wiki_content_added |
|
426 | def test_wiki_content_added | |
431 | content = WikiContent.find(1) |
|
427 | content = WikiContent.find(1) | |
432 | valid_languages.each do |lang| |
|
428 | valid_languages.each do |lang| | |
433 | Setting.default_language = lang.to_s |
|
429 | Setting.default_language = lang.to_s | |
434 | assert_difference 'ActionMailer::Base.deliveries.size' do |
|
430 | assert_difference 'ActionMailer::Base.deliveries.size' do | |
435 | assert Mailer.wiki_content_added(content).deliver |
|
431 | assert Mailer.wiki_content_added(content).deliver | |
436 | assert_select_email do |
|
432 | assert_select_email do | |
437 | assert_select 'a[href=?]', |
|
433 | assert_select 'a[href=?]', | |
438 | 'http://mydomain.foo/projects/ecookbook/wiki/CookBook_documentation', |
|
434 | 'http://mydomain.foo/projects/ecookbook/wiki/CookBook_documentation', | |
439 | :text => 'CookBook documentation' |
|
435 | :text => 'CookBook documentation' | |
440 | end |
|
436 | end | |
441 | end |
|
437 | end | |
442 | end |
|
438 | end | |
443 | end |
|
439 | end | |
444 |
|
440 | |||
445 | def test_wiki_content_updated |
|
441 | def test_wiki_content_updated | |
446 | content = WikiContent.find(1) |
|
442 | content = WikiContent.find(1) | |
447 | valid_languages.each do |lang| |
|
443 | valid_languages.each do |lang| | |
448 | Setting.default_language = lang.to_s |
|
444 | Setting.default_language = lang.to_s | |
449 | assert_difference 'ActionMailer::Base.deliveries.size' do |
|
445 | assert_difference 'ActionMailer::Base.deliveries.size' do | |
450 | assert Mailer.wiki_content_updated(content).deliver |
|
446 | assert Mailer.wiki_content_updated(content).deliver | |
451 | assert_select_email do |
|
447 | assert_select_email do | |
452 | assert_select 'a[href=?]', |
|
448 | assert_select 'a[href=?]', | |
453 | 'http://mydomain.foo/projects/ecookbook/wiki/CookBook_documentation', |
|
449 | 'http://mydomain.foo/projects/ecookbook/wiki/CookBook_documentation', | |
454 | :text => 'CookBook documentation' |
|
450 | :text => 'CookBook documentation' | |
455 | end |
|
451 | end | |
456 | end |
|
452 | end | |
457 | end |
|
453 | end | |
458 | end |
|
454 | end | |
459 |
|
455 | |||
460 | def test_account_information |
|
456 | def test_account_information | |
461 | user = User.find(2) |
|
457 | user = User.find(2) | |
462 | valid_languages.each do |lang| |
|
458 | valid_languages.each do |lang| | |
463 | user.update_attribute :language, lang.to_s |
|
459 | user.update_attribute :language, lang.to_s | |
464 | user.reload |
|
460 | user.reload | |
465 | assert Mailer.account_information(user, 'pAsswORd').deliver |
|
461 | assert Mailer.account_information(user, 'pAsswORd').deliver | |
466 | end |
|
462 | end | |
467 | end |
|
463 | end | |
468 |
|
464 | |||
469 | def test_lost_password |
|
465 | def test_lost_password | |
470 | token = Token.find(2) |
|
466 | token = Token.find(2) | |
471 | valid_languages.each do |lang| |
|
467 | valid_languages.each do |lang| | |
472 | token.user.update_attribute :language, lang.to_s |
|
468 | token.user.update_attribute :language, lang.to_s | |
473 | token.reload |
|
469 | token.reload | |
474 | assert Mailer.lost_password(token).deliver |
|
470 | assert Mailer.lost_password(token).deliver | |
475 | end |
|
471 | end | |
476 | end |
|
472 | end | |
477 |
|
473 | |||
478 | def test_register |
|
474 | def test_register | |
479 | token = Token.find(1) |
|
475 | token = Token.find(1) | |
480 | Setting.host_name = 'redmine.foo' |
|
476 | Setting.host_name = 'redmine.foo' | |
481 | Setting.protocol = 'https' |
|
477 | Setting.protocol = 'https' | |
482 |
|
478 | |||
483 | valid_languages.each do |lang| |
|
479 | valid_languages.each do |lang| | |
484 | token.user.update_attribute :language, lang.to_s |
|
480 | token.user.update_attribute :language, lang.to_s | |
485 | token.reload |
|
481 | token.reload | |
486 | ActionMailer::Base.deliveries.clear |
|
482 | ActionMailer::Base.deliveries.clear | |
487 | assert Mailer.register(token).deliver |
|
483 | assert Mailer.register(token).deliver | |
488 | mail = last_email |
|
484 | mail = last_email | |
489 | assert_select_email do |
|
485 | assert_select_email do | |
490 | assert_select "a[href=?]", |
|
486 | assert_select "a[href=?]", | |
491 | "https://redmine.foo/account/activate?token=#{token.value}", |
|
487 | "https://redmine.foo/account/activate?token=#{token.value}", | |
492 | :text => "https://redmine.foo/account/activate?token=#{token.value}" |
|
488 | :text => "https://redmine.foo/account/activate?token=#{token.value}" | |
493 | end |
|
489 | end | |
494 | end |
|
490 | end | |
495 | end |
|
491 | end | |
496 |
|
492 | |||
497 | def test_test |
|
493 | def test_test | |
498 | user = User.find(1) |
|
494 | user = User.find(1) | |
499 | valid_languages.each do |lang| |
|
495 | valid_languages.each do |lang| | |
500 | user.update_attribute :language, lang.to_s |
|
496 | user.update_attribute :language, lang.to_s | |
501 | assert Mailer.test_email(user).deliver |
|
497 | assert Mailer.test_email(user).deliver | |
502 | end |
|
498 | end | |
503 | end |
|
499 | end | |
504 |
|
500 | |||
505 | def test_reminders |
|
501 | def test_reminders | |
506 | Mailer.reminders(:days => 42) |
|
502 | Mailer.reminders(:days => 42) | |
507 | assert_equal 1, ActionMailer::Base.deliveries.size |
|
503 | assert_equal 1, ActionMailer::Base.deliveries.size | |
508 | mail = last_email |
|
504 | mail = last_email | |
509 | assert mail.bcc.include?('dlopper@somenet.foo') |
|
505 | assert mail.bcc.include?('dlopper@somenet.foo') | |
510 | assert_mail_body_match 'Bug #3: Error 281 when updating a recipe', mail |
|
506 | assert_mail_body_match 'Bug #3: Error 281 when updating a recipe', mail | |
511 | assert_equal '1 issue(s) due in the next 42 days', mail.subject |
|
507 | assert_equal '1 issue(s) due in the next 42 days', mail.subject | |
512 | end |
|
508 | end | |
513 |
|
509 | |||
514 | def test_reminders_should_not_include_closed_issues |
|
510 | def test_reminders_should_not_include_closed_issues | |
515 | with_settings :default_language => 'en' do |
|
511 | with_settings :default_language => 'en' do | |
516 | Issue.create!(:project_id => 1, :tracker_id => 1, :status_id => 5, |
|
512 | Issue.create!(:project_id => 1, :tracker_id => 1, :status_id => 5, | |
517 | :subject => 'Closed issue', :assigned_to_id => 3, |
|
513 | :subject => 'Closed issue', :assigned_to_id => 3, | |
518 | :due_date => 5.days.from_now, |
|
514 | :due_date => 5.days.from_now, | |
519 | :author_id => 2) |
|
515 | :author_id => 2) | |
520 | ActionMailer::Base.deliveries.clear |
|
516 | ActionMailer::Base.deliveries.clear | |
521 |
|
517 | |||
522 | Mailer.reminders(:days => 42) |
|
518 | Mailer.reminders(:days => 42) | |
523 | assert_equal 1, ActionMailer::Base.deliveries.size |
|
519 | assert_equal 1, ActionMailer::Base.deliveries.size | |
524 | mail = last_email |
|
520 | mail = last_email | |
525 | assert mail.bcc.include?('dlopper@somenet.foo') |
|
521 | assert mail.bcc.include?('dlopper@somenet.foo') | |
526 | assert_mail_body_no_match 'Closed issue', mail |
|
522 | assert_mail_body_no_match 'Closed issue', mail | |
527 | end |
|
523 | end | |
528 | end |
|
524 | end | |
529 |
|
525 | |||
530 | def test_reminders_for_users |
|
526 | def test_reminders_for_users | |
531 | Mailer.reminders(:days => 42, :users => ['5']) |
|
527 | Mailer.reminders(:days => 42, :users => ['5']) | |
532 | assert_equal 0, ActionMailer::Base.deliveries.size # No mail for dlopper |
|
528 | assert_equal 0, ActionMailer::Base.deliveries.size # No mail for dlopper | |
533 | Mailer.reminders(:days => 42, :users => ['3']) |
|
529 | Mailer.reminders(:days => 42, :users => ['3']) | |
534 | assert_equal 1, ActionMailer::Base.deliveries.size # No mail for dlopper |
|
530 | assert_equal 1, ActionMailer::Base.deliveries.size # No mail for dlopper | |
535 | mail = last_email |
|
531 | mail = last_email | |
536 | assert mail.bcc.include?('dlopper@somenet.foo') |
|
532 | assert mail.bcc.include?('dlopper@somenet.foo') | |
537 | assert_mail_body_match 'Bug #3: Error 281 when updating a recipe', mail |
|
533 | assert_mail_body_match 'Bug #3: Error 281 when updating a recipe', mail | |
538 | end |
|
534 | end | |
539 |
|
535 | |||
540 | def test_reminder_should_include_issues_assigned_to_groups |
|
536 | def test_reminder_should_include_issues_assigned_to_groups | |
541 | with_settings :default_language => 'en' do |
|
537 | with_settings :default_language => 'en' do | |
542 | group = Group.generate! |
|
538 | group = Group.generate! | |
543 | group.users << User.find(2) |
|
539 | group.users << User.find(2) | |
544 | group.users << User.find(3) |
|
540 | group.users << User.find(3) | |
545 |
|
541 | |||
546 | Issue.create!(:project_id => 1, :tracker_id => 1, :status_id => 1, |
|
542 | Issue.create!(:project_id => 1, :tracker_id => 1, :status_id => 1, | |
547 | :subject => 'Assigned to group', :assigned_to => group, |
|
543 | :subject => 'Assigned to group', :assigned_to => group, | |
548 | :due_date => 5.days.from_now, |
|
544 | :due_date => 5.days.from_now, | |
549 | :author_id => 2) |
|
545 | :author_id => 2) | |
550 | ActionMailer::Base.deliveries.clear |
|
546 | ActionMailer::Base.deliveries.clear | |
551 |
|
547 | |||
552 | Mailer.reminders(:days => 7) |
|
548 | Mailer.reminders(:days => 7) | |
553 | assert_equal 2, ActionMailer::Base.deliveries.size |
|
549 | assert_equal 2, ActionMailer::Base.deliveries.size | |
554 | assert_equal %w(dlopper@somenet.foo jsmith@somenet.foo), ActionMailer::Base.deliveries.map(&:bcc).flatten.sort |
|
550 | assert_equal %w(dlopper@somenet.foo jsmith@somenet.foo), ActionMailer::Base.deliveries.map(&:bcc).flatten.sort | |
555 | ActionMailer::Base.deliveries.each do |mail| |
|
551 | ActionMailer::Base.deliveries.each do |mail| | |
556 | assert_mail_body_match 'Assigned to group', mail |
|
552 | assert_mail_body_match 'Assigned to group', mail | |
557 | end |
|
553 | end | |
558 | end |
|
554 | end | |
559 | end |
|
555 | end | |
560 |
|
556 | |||
561 | def test_mailer_should_not_change_locale |
|
557 | def test_mailer_should_not_change_locale | |
562 | Setting.default_language = 'en' |
|
558 | Setting.default_language = 'en' | |
563 | # Set current language to italian |
|
559 | # Set current language to italian | |
564 | set_language_if_valid 'it' |
|
560 | set_language_if_valid 'it' | |
565 | # Send an email to a french user |
|
561 | # Send an email to a french user | |
566 | user = User.find(1) |
|
562 | user = User.find(1) | |
567 | user.language = 'fr' |
|
563 | user.language = 'fr' | |
568 | Mailer.account_activated(user).deliver |
|
564 | Mailer.account_activated(user).deliver | |
569 | mail = last_email |
|
565 | mail = last_email | |
570 | assert_mail_body_match 'Votre compte', mail |
|
566 | assert_mail_body_match 'Votre compte', mail | |
571 |
|
567 | |||
572 | assert_equal :it, current_language |
|
568 | assert_equal :it, current_language | |
573 | end |
|
569 | end | |
574 |
|
570 | |||
575 | def test_with_deliveries_off |
|
571 | def test_with_deliveries_off | |
576 | Mailer.with_deliveries false do |
|
572 | Mailer.with_deliveries false do | |
577 | Mailer.test_email(User.find(1)).deliver |
|
573 | Mailer.test_email(User.find(1)).deliver | |
578 | end |
|
574 | end | |
579 | assert ActionMailer::Base.deliveries.empty? |
|
575 | assert ActionMailer::Base.deliveries.empty? | |
580 | # should restore perform_deliveries |
|
576 | # should restore perform_deliveries | |
581 | assert ActionMailer::Base.perform_deliveries |
|
577 | assert ActionMailer::Base.perform_deliveries | |
582 | end |
|
578 | end | |
583 |
|
579 | |||
584 | def test_layout_should_include_the_emails_header |
|
580 | def test_layout_should_include_the_emails_header | |
585 | with_settings :emails_header => "*Header content*" do |
|
581 | with_settings :emails_header => "*Header content*" do | |
586 | assert Mailer.test_email(User.find(1)).deliver |
|
582 | assert Mailer.test_email(User.find(1)).deliver | |
587 | assert_select_email do |
|
583 | assert_select_email do | |
588 | assert_select ".header" do |
|
584 | assert_select ".header" do | |
589 | assert_select "strong", :text => "Header content" |
|
585 | assert_select "strong", :text => "Header content" | |
590 | end |
|
586 | end | |
591 | end |
|
587 | end | |
592 | end |
|
588 | end | |
593 | end |
|
589 | end | |
594 |
|
590 | |||
595 | def test_should_escape_html_templates_only |
|
591 | def test_should_escape_html_templates_only | |
596 | Issue.generate!(:project_id => 1, :tracker_id => 1, :subject => 'Subject with a <tag>') |
|
592 | Issue.generate!(:project_id => 1, :tracker_id => 1, :subject => 'Subject with a <tag>') | |
597 | mail = last_email |
|
593 | mail = last_email | |
598 | assert_equal 2, mail.parts.size |
|
594 | assert_equal 2, mail.parts.size | |
599 | assert_include '<tag>', text_part.body.encoded |
|
595 | assert_include '<tag>', text_part.body.encoded | |
600 | assert_include '<tag>', html_part.body.encoded |
|
596 | assert_include '<tag>', html_part.body.encoded | |
601 | end |
|
597 | end | |
602 |
|
598 | |||
603 | private |
|
599 | private | |
604 |
|
600 | |||
605 | def last_email |
|
601 | def last_email | |
606 | mail = ActionMailer::Base.deliveries.last |
|
602 | mail = ActionMailer::Base.deliveries.last | |
607 | assert_not_nil mail |
|
603 | assert_not_nil mail | |
608 |
|
604 | |||
609 | end |
|
605 | end | |
610 |
|
606 | |||
611 | def text_part |
|
607 | def text_part | |
612 | last_email.parts.detect {|part| part.content_type.include?('text/plain')} |
|
608 | last_email.parts.detect {|part| part.content_type.include?('text/plain')} | |
613 | end |
|
609 | end | |
614 |
|
610 | |||
615 | def html_part |
|
611 | def html_part | |
616 | last_email.parts.detect {|part| part.content_type.include?('text/html')} |
|
612 | last_email.parts.detect {|part| part.content_type.include?('text/html')} | |
617 | end |
|
613 | end | |
618 | end |
|
614 | end |
@@ -1,132 +1,114 | |||||
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 PrincipalTest < ActiveSupport::TestCase |
|
22 | class PrincipalTest < ActiveSupport::TestCase | |
23 | fixtures :users, :projects, :members, :member_roles |
|
23 | fixtures :users, :projects, :members, :member_roles | |
24 |
|
24 | |||
25 | def test_active_scope_should_return_groups_and_active_users |
|
25 | def test_active_scope_should_return_groups_and_active_users | |
26 | result = Principal.active.all |
|
26 | result = Principal.active.all | |
27 | assert_include Group.first, result |
|
27 | assert_include Group.first, result | |
28 | assert_not_nil result.detect {|p| p.is_a?(User)} |
|
28 | assert_not_nil result.detect {|p| p.is_a?(User)} | |
29 | assert_nil result.detect {|p| p.is_a?(User) && !p.active?} |
|
29 | assert_nil result.detect {|p| p.is_a?(User) && !p.active?} | |
30 | assert_nil result.detect {|p| p.is_a?(AnonymousUser)} |
|
30 | assert_nil result.detect {|p| p.is_a?(AnonymousUser)} | |
31 | end |
|
31 | end | |
32 |
|
32 | |||
33 | def test_member_of_scope_should_return_the_union_of_all_members |
|
33 | def test_member_of_scope_should_return_the_union_of_all_members | |
34 | projects = Project.find_all_by_id(1, 2) |
|
34 | projects = Project.find_all_by_id(1, 2) | |
35 | assert_equal projects.map(&:principals).flatten.sort, Principal.member_of(projects).sort |
|
35 | assert_equal projects.map(&:principals).flatten.sort, Principal.member_of(projects).sort | |
36 | end |
|
36 | end | |
37 |
|
37 | |||
38 | def test_member_of_scope_should_be_empty_for_no_projects |
|
38 | def test_member_of_scope_should_be_empty_for_no_projects | |
39 | assert_equal [], Principal.member_of([]).sort |
|
39 | assert_equal [], Principal.member_of([]).sort | |
40 | end |
|
40 | end | |
41 |
|
41 | |||
42 | def test_not_member_of_scope_should_return_users_that_have_no_memberships |
|
42 | def test_not_member_of_scope_should_return_users_that_have_no_memberships | |
43 | projects = Project.find_all_by_id(1, 2) |
|
43 | projects = Project.find_all_by_id(1, 2) | |
44 | expected = (Principal.all - projects.map(&:memberships).flatten.map(&:principal)).sort |
|
44 | expected = (Principal.all - projects.map(&:memberships).flatten.map(&:principal)).sort | |
45 | assert_equal expected, Principal.not_member_of(projects).sort |
|
45 | assert_equal expected, Principal.not_member_of(projects).sort | |
46 | end |
|
46 | end | |
47 |
|
47 | |||
48 | def test_not_member_of_scope_should_be_empty_for_no_projects |
|
48 | def test_not_member_of_scope_should_be_empty_for_no_projects | |
49 | assert_equal [], Principal.not_member_of([]).sort |
|
49 | assert_equal [], Principal.not_member_of([]).sort | |
50 | end |
|
50 | end | |
51 |
|
51 | |||
52 | def test_sorted_scope_should_sort_users_before_groups |
|
52 | def test_sorted_scope_should_sort_users_before_groups | |
53 | scope = Principal.where("type <> ?", 'AnonymousUser') |
|
53 | scope = Principal.where("type <> ?", 'AnonymousUser') | |
54 | expected_order = scope.all.sort do |a, b| |
|
54 | expected_order = scope.all.sort do |a, b| | |
55 | if a.is_a?(User) && b.is_a?(Group) |
|
55 | if a.is_a?(User) && b.is_a?(Group) | |
56 | -1 |
|
56 | -1 | |
57 | elsif a.is_a?(Group) && b.is_a?(User) |
|
57 | elsif a.is_a?(Group) && b.is_a?(User) | |
58 | 1 |
|
58 | 1 | |
59 | else |
|
59 | else | |
60 | a.name.downcase <=> b.name.downcase |
|
60 | a.name.downcase <=> b.name.downcase | |
61 | end |
|
61 | end | |
62 | end |
|
62 | end | |
63 | assert_equal expected_order.map(&:name).map(&:downcase), scope.sorted.all.map(&:name).map(&:downcase) |
|
63 | assert_equal expected_order.map(&:name).map(&:downcase), scope.sorted.all.map(&:name).map(&:downcase) | |
64 | end |
|
64 | end | |
65 |
|
65 | |||
66 | context "#like" do |
|
66 | test "like scope should search login" do | |
67 | setup do |
|
67 | results = Principal.like('jsmi') | |
68 | Principal.create!(:login => 'login') |
|
|||
69 | Principal.create!(:login => 'login2') |
|
|||
70 |
|
68 | |||
71 | Principal.create!(:firstname => 'firstname') |
|
69 | assert results.any? | |
72 | Principal.create!(:firstname => 'firstname2') |
|
70 | assert results.all? {|u| u.login.match(/jsmi/i) } | |
73 |
|
||||
74 | Principal.create!(:lastname => 'lastname') |
|
|||
75 | Principal.create!(:lastname => 'lastname2') |
|
|||
76 |
|
||||
77 | Principal.create!(:mail => 'mail@example.com') |
|
|||
78 | Principal.create!(:mail => 'mail2@example.com') |
|
|||
79 |
|
||||
80 | @palmer = Principal.create!(:firstname => 'David', :lastname => 'Palmer') |
|
|||
81 |
|
|
71 | end | |
82 |
|
72 | |||
83 |
|
|
73 | test "like scope should search firstname" do | |
84 |
|
|
74 | results = Principal.like('john') | |
85 |
|
75 | |||
86 |
|
|
76 | assert results.any? | |
87 |
|
|
77 | assert results.all? {|u| u.firstname.match(/john/i) } | |
88 |
|
|
78 | end | |
89 |
|
79 | |||
90 |
|
|
80 | test "like scope should search lastname" do | |
91 |
|
|
81 | results = Principal.like('smi') | |
92 |
|
82 | |||
93 |
|
|
83 | assert results.any? | |
94 |
|
|
84 | assert results.all? {|u| u.lastname.match(/smi/i) } | |
95 |
|
|
85 | end | |
96 |
|
86 | |||
97 |
|
|
87 | test "like scope should search mail" do | |
98 |
|
|
88 | results = Principal.like('somenet') | |
99 |
|
89 | |||
100 |
|
|
90 | assert results.any? | |
101 |
|
|
91 | assert results.all? {|u| u.mail.match(/somenet/i) } | |
102 |
|
|
92 | end | |
103 |
|
93 | |||
104 | should "search mail" do |
|
94 | test "like scope should search firstname and lastname" do | |
105 |
|
|
95 | results = Principal.like('john smi') | |
106 |
|
||||
107 | assert_equal 2, results.count |
|
|||
108 | assert results.all? {|u| u.mail.match(/mail/) } |
|
|||
109 | end |
|
|||
110 |
|
||||
111 | should "search firstname and lastname" do |
|
|||
112 | results = Principal.like('david palm') |
|
|||
113 |
|
96 | |||
114 |
|
|
97 | assert_equal 1, results.count | |
115 |
|
|
98 | assert_equal User.find(2), results.first | |
116 |
|
|
99 | end | |
117 |
|
100 | |||
118 |
|
|
101 | test "like scope should search lastname and firstname" do | |
119 |
|
|
102 | results = Principal.like('smith joh') | |
120 |
|
103 | |||
121 |
|
|
104 | assert_equal 1, results.count | |
122 |
|
|
105 | assert_equal User.find(2), results.first | |
123 | end |
|
|||
124 | end |
|
106 | end | |
125 |
|
107 | |||
126 | def test_like_scope_with_cyrillic_name |
|
108 | def test_like_scope_with_cyrillic_name | |
127 | user = User.generate!(:firstname => 'Π‘ΠΎΠ±ΠΎΠ»Π΅Π²', :lastname => 'ΠΠ΅Π½ΠΈΡ') |
|
109 | user = User.generate!(:firstname => 'Π‘ΠΎΠ±ΠΎΠ»Π΅Π²', :lastname => 'ΠΠ΅Π½ΠΈΡ') | |
128 | results = Principal.like('Π‘ΠΎΠ±ΠΎ') |
|
110 | results = Principal.like('Π‘ΠΎΠ±ΠΎ') | |
129 | assert_equal 1, results.count |
|
111 | assert_equal 1, results.count | |
130 | assert_equal user, results.first |
|
112 | assert_equal user, results.first | |
131 | end |
|
113 | end | |
132 | end |
|
114 | end |
@@ -1,1212 +1,1207 | |||||
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 ProjectTest < ActiveSupport::TestCase |
|
20 | class ProjectTest < ActiveSupport::TestCase | |
21 | fixtures :projects, :trackers, :issue_statuses, :issues, |
|
21 | fixtures :projects, :trackers, :issue_statuses, :issues, | |
22 | :journals, :journal_details, |
|
22 | :journals, :journal_details, | |
23 | :enumerations, :users, :issue_categories, |
|
23 | :enumerations, :users, :issue_categories, | |
24 | :projects_trackers, |
|
24 | :projects_trackers, | |
25 | :custom_fields, |
|
25 | :custom_fields, | |
26 | :custom_fields_projects, |
|
26 | :custom_fields_projects, | |
27 | :custom_fields_trackers, |
|
27 | :custom_fields_trackers, | |
28 | :custom_values, |
|
28 | :custom_values, | |
29 | :roles, |
|
29 | :roles, | |
30 | :member_roles, |
|
30 | :member_roles, | |
31 | :members, |
|
31 | :members, | |
32 | :enabled_modules, |
|
32 | :enabled_modules, | |
33 | :workflows, |
|
33 | :workflows, | |
34 | :versions, |
|
34 | :versions, | |
35 | :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions, |
|
35 | :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions, | |
36 | :groups_users, |
|
36 | :groups_users, | |
37 | :boards, :messages, |
|
37 | :boards, :messages, | |
38 | :repositories, |
|
38 | :repositories, | |
39 | :news, :comments, |
|
39 | :news, :comments, | |
40 | :documents |
|
40 | :documents | |
41 |
|
41 | |||
42 | def setup |
|
42 | def setup | |
43 | @ecookbook = Project.find(1) |
|
43 | @ecookbook = Project.find(1) | |
44 | @ecookbook_sub1 = Project.find(3) |
|
44 | @ecookbook_sub1 = Project.find(3) | |
45 | set_tmp_attachments_directory |
|
45 | set_tmp_attachments_directory | |
46 | User.current = nil |
|
46 | User.current = nil | |
47 | end |
|
47 | end | |
48 |
|
48 | |||
49 | def test_truth |
|
49 | def test_truth | |
50 | assert_kind_of Project, @ecookbook |
|
50 | assert_kind_of Project, @ecookbook | |
51 | assert_equal "eCookbook", @ecookbook.name |
|
51 | assert_equal "eCookbook", @ecookbook.name | |
52 | end |
|
52 | end | |
53 |
|
53 | |||
54 | def test_default_attributes |
|
54 | def test_default_attributes | |
55 | with_settings :default_projects_public => '1' do |
|
55 | with_settings :default_projects_public => '1' do | |
56 | assert_equal true, Project.new.is_public |
|
56 | assert_equal true, Project.new.is_public | |
57 | assert_equal false, Project.new(:is_public => false).is_public |
|
57 | assert_equal false, Project.new(:is_public => false).is_public | |
58 | end |
|
58 | end | |
59 |
|
59 | |||
60 | with_settings :default_projects_public => '0' do |
|
60 | with_settings :default_projects_public => '0' do | |
61 | assert_equal false, Project.new.is_public |
|
61 | assert_equal false, Project.new.is_public | |
62 | assert_equal true, Project.new(:is_public => true).is_public |
|
62 | assert_equal true, Project.new(:is_public => true).is_public | |
63 | end |
|
63 | end | |
64 |
|
64 | |||
65 | with_settings :sequential_project_identifiers => '1' do |
|
65 | with_settings :sequential_project_identifiers => '1' do | |
66 | assert !Project.new.identifier.blank? |
|
66 | assert !Project.new.identifier.blank? | |
67 | assert Project.new(:identifier => '').identifier.blank? |
|
67 | assert Project.new(:identifier => '').identifier.blank? | |
68 | end |
|
68 | end | |
69 |
|
69 | |||
70 | with_settings :sequential_project_identifiers => '0' do |
|
70 | with_settings :sequential_project_identifiers => '0' do | |
71 | assert Project.new.identifier.blank? |
|
71 | assert Project.new.identifier.blank? | |
72 | assert !Project.new(:identifier => 'test').blank? |
|
72 | assert !Project.new(:identifier => 'test').blank? | |
73 | end |
|
73 | end | |
74 |
|
74 | |||
75 | with_settings :default_projects_modules => ['issue_tracking', 'repository'] do |
|
75 | with_settings :default_projects_modules => ['issue_tracking', 'repository'] do | |
76 | assert_equal ['issue_tracking', 'repository'], Project.new.enabled_module_names |
|
76 | assert_equal ['issue_tracking', 'repository'], Project.new.enabled_module_names | |
77 | end |
|
77 | end | |
78 |
|
78 | |||
79 | assert_equal Tracker.all.sort, Project.new.trackers.sort |
|
79 | assert_equal Tracker.all.sort, Project.new.trackers.sort | |
80 | assert_equal Tracker.find(1, 3).sort, Project.new(:tracker_ids => [1, 3]).trackers.sort |
|
80 | assert_equal Tracker.find(1, 3).sort, Project.new(:tracker_ids => [1, 3]).trackers.sort | |
81 | end |
|
81 | end | |
82 |
|
82 | |||
83 | def test_update |
|
83 | def test_update | |
84 | assert_equal "eCookbook", @ecookbook.name |
|
84 | assert_equal "eCookbook", @ecookbook.name | |
85 | @ecookbook.name = "eCook" |
|
85 | @ecookbook.name = "eCook" | |
86 | assert @ecookbook.save, @ecookbook.errors.full_messages.join("; ") |
|
86 | assert @ecookbook.save, @ecookbook.errors.full_messages.join("; ") | |
87 | @ecookbook.reload |
|
87 | @ecookbook.reload | |
88 | assert_equal "eCook", @ecookbook.name |
|
88 | assert_equal "eCook", @ecookbook.name | |
89 | end |
|
89 | end | |
90 |
|
90 | |||
91 | def test_validate_identifier |
|
91 | def test_validate_identifier | |
92 | to_test = {"abc" => true, |
|
92 | to_test = {"abc" => true, | |
93 | "ab12" => true, |
|
93 | "ab12" => true, | |
94 | "ab-12" => true, |
|
94 | "ab-12" => true, | |
95 | "ab_12" => true, |
|
95 | "ab_12" => true, | |
96 | "12" => false, |
|
96 | "12" => false, | |
97 | "new" => false} |
|
97 | "new" => false} | |
98 |
|
98 | |||
99 | to_test.each do |identifier, valid| |
|
99 | to_test.each do |identifier, valid| | |
100 | p = Project.new |
|
100 | p = Project.new | |
101 | p.identifier = identifier |
|
101 | p.identifier = identifier | |
102 | p.valid? |
|
102 | p.valid? | |
103 | if valid |
|
103 | if valid | |
104 | assert p.errors['identifier'].blank?, "identifier #{identifier} was not valid" |
|
104 | assert p.errors['identifier'].blank?, "identifier #{identifier} was not valid" | |
105 | else |
|
105 | else | |
106 | assert p.errors['identifier'].present?, "identifier #{identifier} was valid" |
|
106 | assert p.errors['identifier'].present?, "identifier #{identifier} was valid" | |
107 | end |
|
107 | end | |
108 | end |
|
108 | end | |
109 | end |
|
109 | end | |
110 |
|
110 | |||
111 | def test_identifier_should_not_be_frozen_for_a_new_project |
|
111 | def test_identifier_should_not_be_frozen_for_a_new_project | |
112 | assert_equal false, Project.new.identifier_frozen? |
|
112 | assert_equal false, Project.new.identifier_frozen? | |
113 | end |
|
113 | end | |
114 |
|
114 | |||
115 | def test_identifier_should_not_be_frozen_for_a_saved_project_with_blank_identifier |
|
115 | def test_identifier_should_not_be_frozen_for_a_saved_project_with_blank_identifier | |
116 | Project.update_all(["identifier = ''"], "id = 1") |
|
116 | Project.update_all(["identifier = ''"], "id = 1") | |
117 |
|
117 | |||
118 | assert_equal false, Project.find(1).identifier_frozen? |
|
118 | assert_equal false, Project.find(1).identifier_frozen? | |
119 | end |
|
119 | end | |
120 |
|
120 | |||
121 | def test_identifier_should_be_frozen_for_a_saved_project_with_valid_identifier |
|
121 | def test_identifier_should_be_frozen_for_a_saved_project_with_valid_identifier | |
122 | assert_equal true, Project.find(1).identifier_frozen? |
|
122 | assert_equal true, Project.find(1).identifier_frozen? | |
123 | end |
|
123 | end | |
124 |
|
124 | |||
125 | def test_members_should_be_active_users |
|
125 | def test_members_should_be_active_users | |
126 | Project.all.each do |project| |
|
126 | Project.all.each do |project| | |
127 | assert_nil project.members.detect {|m| !(m.user.is_a?(User) && m.user.active?) } |
|
127 | assert_nil project.members.detect {|m| !(m.user.is_a?(User) && m.user.active?) } | |
128 | end |
|
128 | end | |
129 | end |
|
129 | end | |
130 |
|
130 | |||
131 | def test_users_should_be_active_users |
|
131 | def test_users_should_be_active_users | |
132 | Project.all.each do |project| |
|
132 | Project.all.each do |project| | |
133 | assert_nil project.users.detect {|u| !(u.is_a?(User) && u.active?) } |
|
133 | assert_nil project.users.detect {|u| !(u.is_a?(User) && u.active?) } | |
134 | end |
|
134 | end | |
135 | end |
|
135 | end | |
136 |
|
136 | |||
137 | def test_open_scope_on_issues_association |
|
137 | def test_open_scope_on_issues_association | |
138 | assert_kind_of Issue, Project.find(1).issues.open.first |
|
138 | assert_kind_of Issue, Project.find(1).issues.open.first | |
139 | end |
|
139 | end | |
140 |
|
140 | |||
141 | def test_archive |
|
141 | def test_archive | |
142 | user = @ecookbook.members.first.user |
|
142 | user = @ecookbook.members.first.user | |
143 | @ecookbook.archive |
|
143 | @ecookbook.archive | |
144 | @ecookbook.reload |
|
144 | @ecookbook.reload | |
145 |
|
145 | |||
146 | assert !@ecookbook.active? |
|
146 | assert !@ecookbook.active? | |
147 | assert @ecookbook.archived? |
|
147 | assert @ecookbook.archived? | |
148 | assert !user.projects.include?(@ecookbook) |
|
148 | assert !user.projects.include?(@ecookbook) | |
149 | # Subproject are also archived |
|
149 | # Subproject are also archived | |
150 | assert !@ecookbook.children.empty? |
|
150 | assert !@ecookbook.children.empty? | |
151 | assert @ecookbook.descendants.active.empty? |
|
151 | assert @ecookbook.descendants.active.empty? | |
152 | end |
|
152 | end | |
153 |
|
153 | |||
154 | def test_archive_should_fail_if_versions_are_used_by_non_descendant_projects |
|
154 | def test_archive_should_fail_if_versions_are_used_by_non_descendant_projects | |
155 | # Assign an issue of a project to a version of a child project |
|
155 | # Assign an issue of a project to a version of a child project | |
156 | Issue.find(4).update_attribute :fixed_version_id, 4 |
|
156 | Issue.find(4).update_attribute :fixed_version_id, 4 | |
157 |
|
157 | |||
158 | assert_no_difference "Project.count(:all, :conditions => 'status = #{Project::STATUS_ARCHIVED}')" do |
|
158 | assert_no_difference "Project.count(:all, :conditions => 'status = #{Project::STATUS_ARCHIVED}')" do | |
159 | assert_equal false, @ecookbook.archive |
|
159 | assert_equal false, @ecookbook.archive | |
160 | end |
|
160 | end | |
161 | @ecookbook.reload |
|
161 | @ecookbook.reload | |
162 | assert @ecookbook.active? |
|
162 | assert @ecookbook.active? | |
163 | end |
|
163 | end | |
164 |
|
164 | |||
165 | def test_unarchive |
|
165 | def test_unarchive | |
166 | user = @ecookbook.members.first.user |
|
166 | user = @ecookbook.members.first.user | |
167 | @ecookbook.archive |
|
167 | @ecookbook.archive | |
168 | # A subproject of an archived project can not be unarchived |
|
168 | # A subproject of an archived project can not be unarchived | |
169 | assert !@ecookbook_sub1.unarchive |
|
169 | assert !@ecookbook_sub1.unarchive | |
170 |
|
170 | |||
171 | # Unarchive project |
|
171 | # Unarchive project | |
172 | assert @ecookbook.unarchive |
|
172 | assert @ecookbook.unarchive | |
173 | @ecookbook.reload |
|
173 | @ecookbook.reload | |
174 | assert @ecookbook.active? |
|
174 | assert @ecookbook.active? | |
175 | assert !@ecookbook.archived? |
|
175 | assert !@ecookbook.archived? | |
176 | assert user.projects.include?(@ecookbook) |
|
176 | assert user.projects.include?(@ecookbook) | |
177 | # Subproject can now be unarchived |
|
177 | # Subproject can now be unarchived | |
178 | @ecookbook_sub1.reload |
|
178 | @ecookbook_sub1.reload | |
179 | assert @ecookbook_sub1.unarchive |
|
179 | assert @ecookbook_sub1.unarchive | |
180 | end |
|
180 | end | |
181 |
|
181 | |||
182 | def test_destroy |
|
182 | def test_destroy | |
183 | # 2 active members |
|
183 | # 2 active members | |
184 | assert_equal 2, @ecookbook.members.size |
|
184 | assert_equal 2, @ecookbook.members.size | |
185 | # and 1 is locked |
|
185 | # and 1 is locked | |
186 | assert_equal 3, Member.where('project_id = ?', @ecookbook.id).all.size |
|
186 | assert_equal 3, Member.where('project_id = ?', @ecookbook.id).all.size | |
187 | # some boards |
|
187 | # some boards | |
188 | assert @ecookbook.boards.any? |
|
188 | assert @ecookbook.boards.any? | |
189 |
|
189 | |||
190 | @ecookbook.destroy |
|
190 | @ecookbook.destroy | |
191 | # make sure that the project non longer exists |
|
191 | # make sure that the project non longer exists | |
192 | assert_raise(ActiveRecord::RecordNotFound) { Project.find(@ecookbook.id) } |
|
192 | assert_raise(ActiveRecord::RecordNotFound) { Project.find(@ecookbook.id) } | |
193 | # make sure related data was removed |
|
193 | # make sure related data was removed | |
194 | assert_nil Member.first(:conditions => {:project_id => @ecookbook.id}) |
|
194 | assert_nil Member.first(:conditions => {:project_id => @ecookbook.id}) | |
195 | assert_nil Board.first(:conditions => {:project_id => @ecookbook.id}) |
|
195 | assert_nil Board.first(:conditions => {:project_id => @ecookbook.id}) | |
196 | assert_nil Issue.first(:conditions => {:project_id => @ecookbook.id}) |
|
196 | assert_nil Issue.first(:conditions => {:project_id => @ecookbook.id}) | |
197 | end |
|
197 | end | |
198 |
|
198 | |||
199 | def test_destroy_should_destroy_subtasks |
|
199 | def test_destroy_should_destroy_subtasks | |
200 | issues = (0..2).to_a.map {Issue.create!(:project_id => 1, :tracker_id => 1, :author_id => 1, :subject => 'test')} |
|
200 | issues = (0..2).to_a.map {Issue.create!(:project_id => 1, :tracker_id => 1, :author_id => 1, :subject => 'test')} | |
201 | issues[0].update_attribute :parent_issue_id, issues[1].id |
|
201 | issues[0].update_attribute :parent_issue_id, issues[1].id | |
202 | issues[2].update_attribute :parent_issue_id, issues[1].id |
|
202 | issues[2].update_attribute :parent_issue_id, issues[1].id | |
203 | assert_equal 2, issues[1].children.count |
|
203 | assert_equal 2, issues[1].children.count | |
204 |
|
204 | |||
205 | assert_nothing_raised do |
|
205 | assert_nothing_raised do | |
206 | Project.find(1).destroy |
|
206 | Project.find(1).destroy | |
207 | end |
|
207 | end | |
208 | assert Issue.find_all_by_id(issues.map(&:id)).empty? |
|
208 | assert Issue.find_all_by_id(issues.map(&:id)).empty? | |
209 | end |
|
209 | end | |
210 |
|
210 | |||
211 | def test_destroying_root_projects_should_clear_data |
|
211 | def test_destroying_root_projects_should_clear_data | |
212 | Project.roots.each do |root| |
|
212 | Project.roots.each do |root| | |
213 | root.destroy |
|
213 | root.destroy | |
214 | end |
|
214 | end | |
215 |
|
215 | |||
216 | assert_equal 0, Project.count, "Projects were not deleted: #{Project.all.inspect}" |
|
216 | assert_equal 0, Project.count, "Projects were not deleted: #{Project.all.inspect}" | |
217 | assert_equal 0, Member.count, "Members were not deleted: #{Member.all.inspect}" |
|
217 | assert_equal 0, Member.count, "Members were not deleted: #{Member.all.inspect}" | |
218 | assert_equal 0, MemberRole.count |
|
218 | assert_equal 0, MemberRole.count | |
219 | assert_equal 0, Issue.count |
|
219 | assert_equal 0, Issue.count | |
220 | assert_equal 0, Journal.count |
|
220 | assert_equal 0, Journal.count | |
221 | assert_equal 0, JournalDetail.count |
|
221 | assert_equal 0, JournalDetail.count | |
222 | assert_equal 0, Attachment.count, "Attachments were not deleted: #{Attachment.all.inspect}" |
|
222 | assert_equal 0, Attachment.count, "Attachments were not deleted: #{Attachment.all.inspect}" | |
223 | assert_equal 0, EnabledModule.count |
|
223 | assert_equal 0, EnabledModule.count | |
224 | assert_equal 0, IssueCategory.count |
|
224 | assert_equal 0, IssueCategory.count | |
225 | assert_equal 0, IssueRelation.count |
|
225 | assert_equal 0, IssueRelation.count | |
226 | assert_equal 0, Board.count |
|
226 | assert_equal 0, Board.count | |
227 | assert_equal 0, Message.count |
|
227 | assert_equal 0, Message.count | |
228 | assert_equal 0, News.count |
|
228 | assert_equal 0, News.count | |
229 | assert_equal 0, Query.count(:conditions => "project_id IS NOT NULL") |
|
229 | assert_equal 0, Query.count(:conditions => "project_id IS NOT NULL") | |
230 | assert_equal 0, Repository.count |
|
230 | assert_equal 0, Repository.count | |
231 | assert_equal 0, Changeset.count |
|
231 | assert_equal 0, Changeset.count | |
232 | assert_equal 0, Change.count |
|
232 | assert_equal 0, Change.count | |
233 | assert_equal 0, Comment.count |
|
233 | assert_equal 0, Comment.count | |
234 | assert_equal 0, TimeEntry.count |
|
234 | assert_equal 0, TimeEntry.count | |
235 | assert_equal 0, Version.count |
|
235 | assert_equal 0, Version.count | |
236 | assert_equal 0, Watcher.count |
|
236 | assert_equal 0, Watcher.count | |
237 | assert_equal 0, Wiki.count |
|
237 | assert_equal 0, Wiki.count | |
238 | assert_equal 0, WikiPage.count |
|
238 | assert_equal 0, WikiPage.count | |
239 | assert_equal 0, WikiContent.count |
|
239 | assert_equal 0, WikiContent.count | |
240 | assert_equal 0, WikiContent::Version.count |
|
240 | assert_equal 0, WikiContent::Version.count | |
241 | assert_equal 0, Project.connection.select_all("SELECT * FROM projects_trackers").size |
|
241 | assert_equal 0, Project.connection.select_all("SELECT * FROM projects_trackers").size | |
242 | assert_equal 0, Project.connection.select_all("SELECT * FROM custom_fields_projects").size |
|
242 | assert_equal 0, Project.connection.select_all("SELECT * FROM custom_fields_projects").size | |
243 | assert_equal 0, CustomValue.count(:conditions => {:customized_type => ['Project', 'Issue', 'TimeEntry', 'Version']}) |
|
243 | assert_equal 0, CustomValue.count(:conditions => {:customized_type => ['Project', 'Issue', 'TimeEntry', 'Version']}) | |
244 | end |
|
244 | end | |
245 |
|
245 | |||
246 | def test_move_an_orphan_project_to_a_root_project |
|
246 | def test_move_an_orphan_project_to_a_root_project | |
247 | sub = Project.find(2) |
|
247 | sub = Project.find(2) | |
248 | sub.set_parent! @ecookbook |
|
248 | sub.set_parent! @ecookbook | |
249 | assert_equal @ecookbook.id, sub.parent.id |
|
249 | assert_equal @ecookbook.id, sub.parent.id | |
250 | @ecookbook.reload |
|
250 | @ecookbook.reload | |
251 | assert_equal 4, @ecookbook.children.size |
|
251 | assert_equal 4, @ecookbook.children.size | |
252 | end |
|
252 | end | |
253 |
|
253 | |||
254 | def test_move_an_orphan_project_to_a_subproject |
|
254 | def test_move_an_orphan_project_to_a_subproject | |
255 | sub = Project.find(2) |
|
255 | sub = Project.find(2) | |
256 | assert sub.set_parent!(@ecookbook_sub1) |
|
256 | assert sub.set_parent!(@ecookbook_sub1) | |
257 | end |
|
257 | end | |
258 |
|
258 | |||
259 | def test_move_a_root_project_to_a_project |
|
259 | def test_move_a_root_project_to_a_project | |
260 | sub = @ecookbook |
|
260 | sub = @ecookbook | |
261 | assert sub.set_parent!(Project.find(2)) |
|
261 | assert sub.set_parent!(Project.find(2)) | |
262 | end |
|
262 | end | |
263 |
|
263 | |||
264 | def test_should_not_move_a_project_to_its_children |
|
264 | def test_should_not_move_a_project_to_its_children | |
265 | sub = @ecookbook |
|
265 | sub = @ecookbook | |
266 | assert !(sub.set_parent!(Project.find(3))) |
|
266 | assert !(sub.set_parent!(Project.find(3))) | |
267 | end |
|
267 | end | |
268 |
|
268 | |||
269 | def test_set_parent_should_add_roots_in_alphabetical_order |
|
269 | def test_set_parent_should_add_roots_in_alphabetical_order | |
270 | ProjectCustomField.delete_all |
|
270 | ProjectCustomField.delete_all | |
271 | Project.delete_all |
|
271 | Project.delete_all | |
272 | Project.create!(:name => 'Project C', :identifier => 'project-c').set_parent!(nil) |
|
272 | Project.create!(:name => 'Project C', :identifier => 'project-c').set_parent!(nil) | |
273 | Project.create!(:name => 'Project B', :identifier => 'project-b').set_parent!(nil) |
|
273 | Project.create!(:name => 'Project B', :identifier => 'project-b').set_parent!(nil) | |
274 | Project.create!(:name => 'Project D', :identifier => 'project-d').set_parent!(nil) |
|
274 | Project.create!(:name => 'Project D', :identifier => 'project-d').set_parent!(nil) | |
275 | Project.create!(:name => 'Project A', :identifier => 'project-a').set_parent!(nil) |
|
275 | Project.create!(:name => 'Project A', :identifier => 'project-a').set_parent!(nil) | |
276 |
|
276 | |||
277 | assert_equal 4, Project.count |
|
277 | assert_equal 4, Project.count | |
278 | assert_equal Project.all.sort_by(&:name), Project.all.sort_by(&:lft) |
|
278 | assert_equal Project.all.sort_by(&:name), Project.all.sort_by(&:lft) | |
279 | end |
|
279 | end | |
280 |
|
280 | |||
281 | def test_set_parent_should_add_children_in_alphabetical_order |
|
281 | def test_set_parent_should_add_children_in_alphabetical_order | |
282 | ProjectCustomField.delete_all |
|
282 | ProjectCustomField.delete_all | |
283 | parent = Project.create!(:name => 'Parent', :identifier => 'parent') |
|
283 | parent = Project.create!(:name => 'Parent', :identifier => 'parent') | |
284 | Project.create!(:name => 'Project C', :identifier => 'project-c').set_parent!(parent) |
|
284 | Project.create!(:name => 'Project C', :identifier => 'project-c').set_parent!(parent) | |
285 | Project.create!(:name => 'Project B', :identifier => 'project-b').set_parent!(parent) |
|
285 | Project.create!(:name => 'Project B', :identifier => 'project-b').set_parent!(parent) | |
286 | Project.create!(:name => 'Project D', :identifier => 'project-d').set_parent!(parent) |
|
286 | Project.create!(:name => 'Project D', :identifier => 'project-d').set_parent!(parent) | |
287 | Project.create!(:name => 'Project A', :identifier => 'project-a').set_parent!(parent) |
|
287 | Project.create!(:name => 'Project A', :identifier => 'project-a').set_parent!(parent) | |
288 |
|
288 | |||
289 | parent.reload |
|
289 | parent.reload | |
290 | assert_equal 4, parent.children.size |
|
290 | assert_equal 4, parent.children.size | |
291 | assert_equal parent.children.all.sort_by(&:name), parent.children.all |
|
291 | assert_equal parent.children.all.sort_by(&:name), parent.children.all | |
292 | end |
|
292 | end | |
293 |
|
293 | |||
294 | def test_set_parent_should_update_issue_fixed_version_associations_when_a_fixed_version_is_moved_out_of_the_hierarchy |
|
294 | def test_set_parent_should_update_issue_fixed_version_associations_when_a_fixed_version_is_moved_out_of_the_hierarchy | |
295 | # Parent issue with a hierarchy project's fixed version |
|
295 | # Parent issue with a hierarchy project's fixed version | |
296 | parent_issue = Issue.find(1) |
|
296 | parent_issue = Issue.find(1) | |
297 | parent_issue.update_attribute(:fixed_version_id, 4) |
|
297 | parent_issue.update_attribute(:fixed_version_id, 4) | |
298 | parent_issue.reload |
|
298 | parent_issue.reload | |
299 | assert_equal 4, parent_issue.fixed_version_id |
|
299 | assert_equal 4, parent_issue.fixed_version_id | |
300 |
|
300 | |||
301 | # Should keep fixed versions for the issues |
|
301 | # Should keep fixed versions for the issues | |
302 | issue_with_local_fixed_version = Issue.find(5) |
|
302 | issue_with_local_fixed_version = Issue.find(5) | |
303 | issue_with_local_fixed_version.update_attribute(:fixed_version_id, 4) |
|
303 | issue_with_local_fixed_version.update_attribute(:fixed_version_id, 4) | |
304 | issue_with_local_fixed_version.reload |
|
304 | issue_with_local_fixed_version.reload | |
305 | assert_equal 4, issue_with_local_fixed_version.fixed_version_id |
|
305 | assert_equal 4, issue_with_local_fixed_version.fixed_version_id | |
306 |
|
306 | |||
307 | # Local issue with hierarchy fixed_version |
|
307 | # Local issue with hierarchy fixed_version | |
308 | issue_with_hierarchy_fixed_version = Issue.find(13) |
|
308 | issue_with_hierarchy_fixed_version = Issue.find(13) | |
309 | issue_with_hierarchy_fixed_version.update_attribute(:fixed_version_id, 6) |
|
309 | issue_with_hierarchy_fixed_version.update_attribute(:fixed_version_id, 6) | |
310 | issue_with_hierarchy_fixed_version.reload |
|
310 | issue_with_hierarchy_fixed_version.reload | |
311 | assert_equal 6, issue_with_hierarchy_fixed_version.fixed_version_id |
|
311 | assert_equal 6, issue_with_hierarchy_fixed_version.fixed_version_id | |
312 |
|
312 | |||
313 | # Move project out of the issue's hierarchy |
|
313 | # Move project out of the issue's hierarchy | |
314 | moved_project = Project.find(3) |
|
314 | moved_project = Project.find(3) | |
315 | moved_project.set_parent!(Project.find(2)) |
|
315 | moved_project.set_parent!(Project.find(2)) | |
316 | parent_issue.reload |
|
316 | parent_issue.reload | |
317 | issue_with_local_fixed_version.reload |
|
317 | issue_with_local_fixed_version.reload | |
318 | issue_with_hierarchy_fixed_version.reload |
|
318 | issue_with_hierarchy_fixed_version.reload | |
319 |
|
319 | |||
320 | assert_equal 4, issue_with_local_fixed_version.fixed_version_id, "Fixed version was not keep on an issue local to the moved project" |
|
320 | assert_equal 4, issue_with_local_fixed_version.fixed_version_id, "Fixed version was not keep on an issue local to the moved project" | |
321 | assert_equal nil, issue_with_hierarchy_fixed_version.fixed_version_id, "Fixed version is still set after moving the Project out of the hierarchy where the version is defined in" |
|
321 | assert_equal nil, issue_with_hierarchy_fixed_version.fixed_version_id, "Fixed version is still set after moving the Project out of the hierarchy where the version is defined in" | |
322 | assert_equal nil, parent_issue.fixed_version_id, "Fixed version is still set after moving the Version out of the hierarchy for the issue." |
|
322 | assert_equal nil, parent_issue.fixed_version_id, "Fixed version is still set after moving the Version out of the hierarchy for the issue." | |
323 | end |
|
323 | end | |
324 |
|
324 | |||
325 | def test_parent |
|
325 | def test_parent | |
326 | p = Project.find(6).parent |
|
326 | p = Project.find(6).parent | |
327 | assert p.is_a?(Project) |
|
327 | assert p.is_a?(Project) | |
328 | assert_equal 5, p.id |
|
328 | assert_equal 5, p.id | |
329 | end |
|
329 | end | |
330 |
|
330 | |||
331 | def test_ancestors |
|
331 | def test_ancestors | |
332 | a = Project.find(6).ancestors |
|
332 | a = Project.find(6).ancestors | |
333 | assert a.first.is_a?(Project) |
|
333 | assert a.first.is_a?(Project) | |
334 | assert_equal [1, 5], a.collect(&:id) |
|
334 | assert_equal [1, 5], a.collect(&:id) | |
335 | end |
|
335 | end | |
336 |
|
336 | |||
337 | def test_root |
|
337 | def test_root | |
338 | r = Project.find(6).root |
|
338 | r = Project.find(6).root | |
339 | assert r.is_a?(Project) |
|
339 | assert r.is_a?(Project) | |
340 | assert_equal 1, r.id |
|
340 | assert_equal 1, r.id | |
341 | end |
|
341 | end | |
342 |
|
342 | |||
343 | def test_children |
|
343 | def test_children | |
344 | c = Project.find(1).children |
|
344 | c = Project.find(1).children | |
345 | assert c.first.is_a?(Project) |
|
345 | assert c.first.is_a?(Project) | |
346 | assert_equal [5, 3, 4], c.collect(&:id) |
|
346 | assert_equal [5, 3, 4], c.collect(&:id) | |
347 | end |
|
347 | end | |
348 |
|
348 | |||
349 | def test_descendants |
|
349 | def test_descendants | |
350 | d = Project.find(1).descendants |
|
350 | d = Project.find(1).descendants | |
351 | assert d.first.is_a?(Project) |
|
351 | assert d.first.is_a?(Project) | |
352 | assert_equal [5, 6, 3, 4], d.collect(&:id) |
|
352 | assert_equal [5, 6, 3, 4], d.collect(&:id) | |
353 | end |
|
353 | end | |
354 |
|
354 | |||
355 | def test_allowed_parents_should_be_empty_for_non_member_user |
|
355 | def test_allowed_parents_should_be_empty_for_non_member_user | |
356 | Role.non_member.add_permission!(:add_project) |
|
356 | Role.non_member.add_permission!(:add_project) | |
357 | user = User.find(9) |
|
357 | user = User.find(9) | |
358 | assert user.memberships.empty? |
|
358 | assert user.memberships.empty? | |
359 | User.current = user |
|
359 | User.current = user | |
360 | assert Project.new.allowed_parents.compact.empty? |
|
360 | assert Project.new.allowed_parents.compact.empty? | |
361 | end |
|
361 | end | |
362 |
|
362 | |||
363 | def test_allowed_parents_with_add_subprojects_permission |
|
363 | def test_allowed_parents_with_add_subprojects_permission | |
364 | Role.find(1).remove_permission!(:add_project) |
|
364 | Role.find(1).remove_permission!(:add_project) | |
365 | Role.find(1).add_permission!(:add_subprojects) |
|
365 | Role.find(1).add_permission!(:add_subprojects) | |
366 | User.current = User.find(2) |
|
366 | User.current = User.find(2) | |
367 | # new project |
|
367 | # new project | |
368 | assert !Project.new.allowed_parents.include?(nil) |
|
368 | assert !Project.new.allowed_parents.include?(nil) | |
369 | assert Project.new.allowed_parents.include?(Project.find(1)) |
|
369 | assert Project.new.allowed_parents.include?(Project.find(1)) | |
370 | # existing root project |
|
370 | # existing root project | |
371 | assert Project.find(1).allowed_parents.include?(nil) |
|
371 | assert Project.find(1).allowed_parents.include?(nil) | |
372 | # existing child |
|
372 | # existing child | |
373 | assert Project.find(3).allowed_parents.include?(Project.find(1)) |
|
373 | assert Project.find(3).allowed_parents.include?(Project.find(1)) | |
374 | assert !Project.find(3).allowed_parents.include?(nil) |
|
374 | assert !Project.find(3).allowed_parents.include?(nil) | |
375 | end |
|
375 | end | |
376 |
|
376 | |||
377 | def test_allowed_parents_with_add_project_permission |
|
377 | def test_allowed_parents_with_add_project_permission | |
378 | Role.find(1).add_permission!(:add_project) |
|
378 | Role.find(1).add_permission!(:add_project) | |
379 | Role.find(1).remove_permission!(:add_subprojects) |
|
379 | Role.find(1).remove_permission!(:add_subprojects) | |
380 | User.current = User.find(2) |
|
380 | User.current = User.find(2) | |
381 | # new project |
|
381 | # new project | |
382 | assert Project.new.allowed_parents.include?(nil) |
|
382 | assert Project.new.allowed_parents.include?(nil) | |
383 | assert !Project.new.allowed_parents.include?(Project.find(1)) |
|
383 | assert !Project.new.allowed_parents.include?(Project.find(1)) | |
384 | # existing root project |
|
384 | # existing root project | |
385 | assert Project.find(1).allowed_parents.include?(nil) |
|
385 | assert Project.find(1).allowed_parents.include?(nil) | |
386 | # existing child |
|
386 | # existing child | |
387 | assert Project.find(3).allowed_parents.include?(Project.find(1)) |
|
387 | assert Project.find(3).allowed_parents.include?(Project.find(1)) | |
388 | assert Project.find(3).allowed_parents.include?(nil) |
|
388 | assert Project.find(3).allowed_parents.include?(nil) | |
389 | end |
|
389 | end | |
390 |
|
390 | |||
391 | def test_allowed_parents_with_add_project_and_subprojects_permission |
|
391 | def test_allowed_parents_with_add_project_and_subprojects_permission | |
392 | Role.find(1).add_permission!(:add_project) |
|
392 | Role.find(1).add_permission!(:add_project) | |
393 | Role.find(1).add_permission!(:add_subprojects) |
|
393 | Role.find(1).add_permission!(:add_subprojects) | |
394 | User.current = User.find(2) |
|
394 | User.current = User.find(2) | |
395 | # new project |
|
395 | # new project | |
396 | assert Project.new.allowed_parents.include?(nil) |
|
396 | assert Project.new.allowed_parents.include?(nil) | |
397 | assert Project.new.allowed_parents.include?(Project.find(1)) |
|
397 | assert Project.new.allowed_parents.include?(Project.find(1)) | |
398 | # existing root project |
|
398 | # existing root project | |
399 | assert Project.find(1).allowed_parents.include?(nil) |
|
399 | assert Project.find(1).allowed_parents.include?(nil) | |
400 | # existing child |
|
400 | # existing child | |
401 | assert Project.find(3).allowed_parents.include?(Project.find(1)) |
|
401 | assert Project.find(3).allowed_parents.include?(Project.find(1)) | |
402 | assert Project.find(3).allowed_parents.include?(nil) |
|
402 | assert Project.find(3).allowed_parents.include?(nil) | |
403 | end |
|
403 | end | |
404 |
|
404 | |||
405 | def test_users_by_role |
|
405 | def test_users_by_role | |
406 | users_by_role = Project.find(1).users_by_role |
|
406 | users_by_role = Project.find(1).users_by_role | |
407 | assert_kind_of Hash, users_by_role |
|
407 | assert_kind_of Hash, users_by_role | |
408 | role = Role.find(1) |
|
408 | role = Role.find(1) | |
409 | assert_kind_of Array, users_by_role[role] |
|
409 | assert_kind_of Array, users_by_role[role] | |
410 | assert users_by_role[role].include?(User.find(2)) |
|
410 | assert users_by_role[role].include?(User.find(2)) | |
411 | end |
|
411 | end | |
412 |
|
412 | |||
413 | def test_rolled_up_trackers |
|
413 | def test_rolled_up_trackers | |
414 | parent = Project.find(1) |
|
414 | parent = Project.find(1) | |
415 | parent.trackers = Tracker.find([1,2]) |
|
415 | parent.trackers = Tracker.find([1,2]) | |
416 | child = parent.children.find(3) |
|
416 | child = parent.children.find(3) | |
417 |
|
417 | |||
418 | assert_equal [1, 2], parent.tracker_ids |
|
418 | assert_equal [1, 2], parent.tracker_ids | |
419 | assert_equal [2, 3], child.trackers.collect(&:id) |
|
419 | assert_equal [2, 3], child.trackers.collect(&:id) | |
420 |
|
420 | |||
421 | assert_kind_of Tracker, parent.rolled_up_trackers.first |
|
421 | assert_kind_of Tracker, parent.rolled_up_trackers.first | |
422 | assert_equal Tracker.find(1), parent.rolled_up_trackers.first |
|
422 | assert_equal Tracker.find(1), parent.rolled_up_trackers.first | |
423 |
|
423 | |||
424 | assert_equal [1, 2, 3], parent.rolled_up_trackers.collect(&:id) |
|
424 | assert_equal [1, 2, 3], parent.rolled_up_trackers.collect(&:id) | |
425 | assert_equal [2, 3], child.rolled_up_trackers.collect(&:id) |
|
425 | assert_equal [2, 3], child.rolled_up_trackers.collect(&:id) | |
426 | end |
|
426 | end | |
427 |
|
427 | |||
428 | def test_rolled_up_trackers_should_ignore_archived_subprojects |
|
428 | def test_rolled_up_trackers_should_ignore_archived_subprojects | |
429 | parent = Project.find(1) |
|
429 | parent = Project.find(1) | |
430 | parent.trackers = Tracker.find([1,2]) |
|
430 | parent.trackers = Tracker.find([1,2]) | |
431 | child = parent.children.find(3) |
|
431 | child = parent.children.find(3) | |
432 | child.trackers = Tracker.find([1,3]) |
|
432 | child.trackers = Tracker.find([1,3]) | |
433 | parent.children.each(&:archive) |
|
433 | parent.children.each(&:archive) | |
434 |
|
434 | |||
435 | assert_equal [1,2], parent.rolled_up_trackers.collect(&:id) |
|
435 | assert_equal [1,2], parent.rolled_up_trackers.collect(&:id) | |
436 | end |
|
436 | end | |
437 |
|
437 | |||
438 | context "#rolled_up_versions" do |
|
438 | test "#rolled_up_versions should include the versions for the current project" do | |
439 | setup do |
|
439 | project = Project.generate! | |
440 | @project = Project.generate! |
|
440 | parent_version_1 = Version.generate!(:project => project) | |
441 |
|
|
441 | parent_version_2 = Version.generate!(:project => project) | |
442 | @parent_version_2 = Version.generate!(:project => @project) |
|
442 | assert_same_elements [parent_version_1, parent_version_2], project.rolled_up_versions | |
443 | end |
|
|||
444 |
|
||||
445 | should "include the versions for the current project" do |
|
|||
446 | assert_same_elements [@parent_version_1, @parent_version_2], @project.rolled_up_versions |
|
|||
447 |
|
|
443 | end | |
448 |
|
444 | |||
449 |
|
|
445 | test "#rolled_up_versions should include versions for a subproject" do | |
450 |
|
|
446 | project = Project.generate! | |
451 | @subproject.set_parent!(@project) |
|
447 | parent_version_1 = Version.generate!(:project => project) | |
452 |
|
|
448 | parent_version_2 = Version.generate!(:project => project) | |
|
449 | subproject = Project.generate_with_parent!(project) | |||
|
450 | subproject_version = Version.generate!(:project => subproject) | |||
453 |
|
451 | |||
454 |
|
|
452 | assert_same_elements [ | |
455 |
|
|
453 | parent_version_1, | |
456 |
|
|
454 | parent_version_2, | |
457 |
|
|
455 | subproject_version | |
458 |
|
|
456 | ], project.rolled_up_versions | |
459 |
|
|
457 | end | |
460 |
|
458 | |||
461 |
|
|
459 | test "#rolled_up_versions should include versions for a sub-subproject" do | |
462 |
|
|
460 | project = Project.generate! | |
463 | @subproject.set_parent!(@project) |
|
461 | parent_version_1 = Version.generate!(:project => project) | |
464 | @sub_subproject = Project.generate! |
|
462 | parent_version_2 = Version.generate!(:project => project) | |
465 |
|
|
463 | subproject = Project.generate_with_parent!(project) | |
466 |
|
|
464 | sub_subproject = Project.generate_with_parent!(subproject) | |
467 |
|
465 | sub_subproject_version = Version.generate!(:project => sub_subproject) | ||
468 |
|
|
466 | project.reload | |
469 |
|
467 | |||
470 |
|
|
468 | assert_same_elements [ | |
471 |
|
|
469 | parent_version_1, | |
472 |
|
|
470 | parent_version_2, | |
473 |
|
|
471 | sub_subproject_version | |
474 |
|
|
472 | ], project.rolled_up_versions | |
475 |
|
|
473 | end | |
476 |
|
474 | |||
477 |
|
|
475 | test "#rolled_up_versions should only check active projects" do | |
478 |
|
|
476 | project = Project.generate! | |
479 | @subproject.set_parent!(@project) |
|
477 | parent_version_1 = Version.generate!(:project => project) | |
480 |
|
|
478 | parent_version_2 = Version.generate!(:project => project) | |
481 | assert @subproject.archive |
|
479 | subproject = Project.generate_with_parent!(project) | |
482 |
|
480 | subproject_version = Version.generate!(:project => subproject) | ||
483 |
|
|
481 | assert subproject.archive | |
|
482 | project.reload | |||
484 |
|
483 | |||
485 |
|
|
484 | assert !subproject.active? | |
486 |
|
|
485 | assert_same_elements [parent_version_1, parent_version_2], project.rolled_up_versions | |
487 | end |
|
|||
488 | end |
|
486 | end | |
489 |
|
487 | |||
490 | def test_shared_versions_none_sharing |
|
488 | def test_shared_versions_none_sharing | |
491 | p = Project.find(5) |
|
489 | p = Project.find(5) | |
492 | v = Version.create!(:name => 'none_sharing', :project => p, :sharing => 'none') |
|
490 | v = Version.create!(:name => 'none_sharing', :project => p, :sharing => 'none') | |
493 | assert p.shared_versions.include?(v) |
|
491 | assert p.shared_versions.include?(v) | |
494 | assert !p.children.first.shared_versions.include?(v) |
|
492 | assert !p.children.first.shared_versions.include?(v) | |
495 | assert !p.root.shared_versions.include?(v) |
|
493 | assert !p.root.shared_versions.include?(v) | |
496 | assert !p.siblings.first.shared_versions.include?(v) |
|
494 | assert !p.siblings.first.shared_versions.include?(v) | |
497 | assert !p.root.siblings.first.shared_versions.include?(v) |
|
495 | assert !p.root.siblings.first.shared_versions.include?(v) | |
498 | end |
|
496 | end | |
499 |
|
497 | |||
500 | def test_shared_versions_descendants_sharing |
|
498 | def test_shared_versions_descendants_sharing | |
501 | p = Project.find(5) |
|
499 | p = Project.find(5) | |
502 | v = Version.create!(:name => 'descendants_sharing', :project => p, :sharing => 'descendants') |
|
500 | v = Version.create!(:name => 'descendants_sharing', :project => p, :sharing => 'descendants') | |
503 | assert p.shared_versions.include?(v) |
|
501 | assert p.shared_versions.include?(v) | |
504 | assert p.children.first.shared_versions.include?(v) |
|
502 | assert p.children.first.shared_versions.include?(v) | |
505 | assert !p.root.shared_versions.include?(v) |
|
503 | assert !p.root.shared_versions.include?(v) | |
506 | assert !p.siblings.first.shared_versions.include?(v) |
|
504 | assert !p.siblings.first.shared_versions.include?(v) | |
507 | assert !p.root.siblings.first.shared_versions.include?(v) |
|
505 | assert !p.root.siblings.first.shared_versions.include?(v) | |
508 | end |
|
506 | end | |
509 |
|
507 | |||
510 | def test_shared_versions_hierarchy_sharing |
|
508 | def test_shared_versions_hierarchy_sharing | |
511 | p = Project.find(5) |
|
509 | p = Project.find(5) | |
512 | v = Version.create!(:name => 'hierarchy_sharing', :project => p, :sharing => 'hierarchy') |
|
510 | v = Version.create!(:name => 'hierarchy_sharing', :project => p, :sharing => 'hierarchy') | |
513 | assert p.shared_versions.include?(v) |
|
511 | assert p.shared_versions.include?(v) | |
514 | assert p.children.first.shared_versions.include?(v) |
|
512 | assert p.children.first.shared_versions.include?(v) | |
515 | assert p.root.shared_versions.include?(v) |
|
513 | assert p.root.shared_versions.include?(v) | |
516 | assert !p.siblings.first.shared_versions.include?(v) |
|
514 | assert !p.siblings.first.shared_versions.include?(v) | |
517 | assert !p.root.siblings.first.shared_versions.include?(v) |
|
515 | assert !p.root.siblings.first.shared_versions.include?(v) | |
518 | end |
|
516 | end | |
519 |
|
517 | |||
520 | def test_shared_versions_tree_sharing |
|
518 | def test_shared_versions_tree_sharing | |
521 | p = Project.find(5) |
|
519 | p = Project.find(5) | |
522 | v = Version.create!(:name => 'tree_sharing', :project => p, :sharing => 'tree') |
|
520 | v = Version.create!(:name => 'tree_sharing', :project => p, :sharing => 'tree') | |
523 | assert p.shared_versions.include?(v) |
|
521 | assert p.shared_versions.include?(v) | |
524 | assert p.children.first.shared_versions.include?(v) |
|
522 | assert p.children.first.shared_versions.include?(v) | |
525 | assert p.root.shared_versions.include?(v) |
|
523 | assert p.root.shared_versions.include?(v) | |
526 | assert p.siblings.first.shared_versions.include?(v) |
|
524 | assert p.siblings.first.shared_versions.include?(v) | |
527 | assert !p.root.siblings.first.shared_versions.include?(v) |
|
525 | assert !p.root.siblings.first.shared_versions.include?(v) | |
528 | end |
|
526 | end | |
529 |
|
527 | |||
530 | def test_shared_versions_system_sharing |
|
528 | def test_shared_versions_system_sharing | |
531 | p = Project.find(5) |
|
529 | p = Project.find(5) | |
532 | v = Version.create!(:name => 'system_sharing', :project => p, :sharing => 'system') |
|
530 | v = Version.create!(:name => 'system_sharing', :project => p, :sharing => 'system') | |
533 | assert p.shared_versions.include?(v) |
|
531 | assert p.shared_versions.include?(v) | |
534 | assert p.children.first.shared_versions.include?(v) |
|
532 | assert p.children.first.shared_versions.include?(v) | |
535 | assert p.root.shared_versions.include?(v) |
|
533 | assert p.root.shared_versions.include?(v) | |
536 | assert p.siblings.first.shared_versions.include?(v) |
|
534 | assert p.siblings.first.shared_versions.include?(v) | |
537 | assert p.root.siblings.first.shared_versions.include?(v) |
|
535 | assert p.root.siblings.first.shared_versions.include?(v) | |
538 | end |
|
536 | end | |
539 |
|
537 | |||
540 | def test_shared_versions |
|
538 | def test_shared_versions | |
541 | parent = Project.find(1) |
|
539 | parent = Project.find(1) | |
542 | child = parent.children.find(3) |
|
540 | child = parent.children.find(3) | |
543 | private_child = parent.children.find(5) |
|
541 | private_child = parent.children.find(5) | |
544 |
|
542 | |||
545 | assert_equal [1,2,3], parent.version_ids.sort |
|
543 | assert_equal [1,2,3], parent.version_ids.sort | |
546 | assert_equal [4], child.version_ids |
|
544 | assert_equal [4], child.version_ids | |
547 | assert_equal [6], private_child.version_ids |
|
545 | assert_equal [6], private_child.version_ids | |
548 | assert_equal [7], Version.find_all_by_sharing('system').collect(&:id) |
|
546 | assert_equal [7], Version.find_all_by_sharing('system').collect(&:id) | |
549 |
|
547 | |||
550 | assert_equal 6, parent.shared_versions.size |
|
548 | assert_equal 6, parent.shared_versions.size | |
551 | parent.shared_versions.each do |version| |
|
549 | parent.shared_versions.each do |version| | |
552 | assert_kind_of Version, version |
|
550 | assert_kind_of Version, version | |
553 | end |
|
551 | end | |
554 |
|
552 | |||
555 | assert_equal [1,2,3,4,6,7], parent.shared_versions.collect(&:id).sort |
|
553 | assert_equal [1,2,3,4,6,7], parent.shared_versions.collect(&:id).sort | |
556 | end |
|
554 | end | |
557 |
|
555 | |||
558 | def test_shared_versions_should_ignore_archived_subprojects |
|
556 | def test_shared_versions_should_ignore_archived_subprojects | |
559 | parent = Project.find(1) |
|
557 | parent = Project.find(1) | |
560 | child = parent.children.find(3) |
|
558 | child = parent.children.find(3) | |
561 | child.archive |
|
559 | child.archive | |
562 | parent.reload |
|
560 | parent.reload | |
563 |
|
561 | |||
564 | assert_equal [1,2,3], parent.version_ids.sort |
|
562 | assert_equal [1,2,3], parent.version_ids.sort | |
565 | assert_equal [4], child.version_ids |
|
563 | assert_equal [4], child.version_ids | |
566 | assert !parent.shared_versions.collect(&:id).include?(4) |
|
564 | assert !parent.shared_versions.collect(&:id).include?(4) | |
567 | end |
|
565 | end | |
568 |
|
566 | |||
569 | def test_shared_versions_visible_to_user |
|
567 | def test_shared_versions_visible_to_user | |
570 | user = User.find(3) |
|
568 | user = User.find(3) | |
571 | parent = Project.find(1) |
|
569 | parent = Project.find(1) | |
572 | child = parent.children.find(5) |
|
570 | child = parent.children.find(5) | |
573 |
|
571 | |||
574 | assert_equal [1,2,3], parent.version_ids.sort |
|
572 | assert_equal [1,2,3], parent.version_ids.sort | |
575 | assert_equal [6], child.version_ids |
|
573 | assert_equal [6], child.version_ids | |
576 |
|
574 | |||
577 | versions = parent.shared_versions.visible(user) |
|
575 | versions = parent.shared_versions.visible(user) | |
578 |
|
576 | |||
579 | assert_equal 4, versions.size |
|
577 | assert_equal 4, versions.size | |
580 | versions.each do |version| |
|
578 | versions.each do |version| | |
581 | assert_kind_of Version, version |
|
579 | assert_kind_of Version, version | |
582 | end |
|
580 | end | |
583 |
|
581 | |||
584 | assert !versions.collect(&:id).include?(6) |
|
582 | assert !versions.collect(&:id).include?(6) | |
585 | end |
|
583 | end | |
586 |
|
584 | |||
587 | def test_shared_versions_for_new_project_should_include_system_shared_versions |
|
585 | def test_shared_versions_for_new_project_should_include_system_shared_versions | |
588 | p = Project.find(5) |
|
586 | p = Project.find(5) | |
589 | v = Version.create!(:name => 'system_sharing', :project => p, :sharing => 'system') |
|
587 | v = Version.create!(:name => 'system_sharing', :project => p, :sharing => 'system') | |
590 |
|
588 | |||
591 | assert_include v, Project.new.shared_versions |
|
589 | assert_include v, Project.new.shared_versions | |
592 | end |
|
590 | end | |
593 |
|
591 | |||
594 | def test_next_identifier |
|
592 | def test_next_identifier | |
595 | ProjectCustomField.delete_all |
|
593 | ProjectCustomField.delete_all | |
596 | Project.create!(:name => 'last', :identifier => 'p2008040') |
|
594 | Project.create!(:name => 'last', :identifier => 'p2008040') | |
597 | assert_equal 'p2008041', Project.next_identifier |
|
595 | assert_equal 'p2008041', Project.next_identifier | |
598 | end |
|
596 | end | |
599 |
|
597 | |||
600 | def test_next_identifier_first_project |
|
598 | def test_next_identifier_first_project | |
601 | Project.delete_all |
|
599 | Project.delete_all | |
602 | assert_nil Project.next_identifier |
|
600 | assert_nil Project.next_identifier | |
603 | end |
|
601 | end | |
604 |
|
602 | |||
605 | def test_enabled_module_names |
|
603 | def test_enabled_module_names | |
606 | with_settings :default_projects_modules => ['issue_tracking', 'repository'] do |
|
604 | with_settings :default_projects_modules => ['issue_tracking', 'repository'] do | |
607 | project = Project.new |
|
605 | project = Project.new | |
608 |
|
606 | |||
609 | project.enabled_module_names = %w(issue_tracking news) |
|
607 | project.enabled_module_names = %w(issue_tracking news) | |
610 | assert_equal %w(issue_tracking news), project.enabled_module_names.sort |
|
608 | assert_equal %w(issue_tracking news), project.enabled_module_names.sort | |
611 | end |
|
609 | end | |
612 | end |
|
610 | end | |
613 |
|
611 | |||
614 | context "enabled_modules" do |
|
612 | test "enabled_modules should define module by names and preserve ids" do | |
615 | setup do |
|
|||
616 |
|
|
613 | @project = Project.find(1) | |
617 | end |
|
|||
618 |
|
||||
619 | should "define module by names and preserve ids" do |
|
|||
620 |
|
|
614 | # Remove one module | |
621 |
|
|
615 | modules = @project.enabled_modules.slice(0..-2) | |
622 |
|
|
616 | assert modules.any? | |
623 |
|
|
617 | assert_difference 'EnabledModule.count', -1 do | |
624 |
|
|
618 | @project.enabled_module_names = modules.collect(&:name) | |
625 |
|
|
619 | end | |
626 |
|
|
620 | @project.reload | |
627 |
|
|
621 | # Ids should be preserved | |
628 |
|
|
622 | assert_equal @project.enabled_module_ids.sort, modules.collect(&:id).sort | |
629 |
|
|
623 | end | |
630 |
|
624 | |||
631 |
|
|
625 | test "enabled_modules should enable a module" do | |
|
626 | @project = Project.find(1) | |||
632 |
|
|
627 | @project.enabled_module_names = [] | |
633 |
|
|
628 | @project.reload | |
634 |
|
|
629 | assert_equal [], @project.enabled_module_names | |
635 |
|
|
630 | #with string | |
636 |
|
|
631 | @project.enable_module!("issue_tracking") | |
637 |
|
|
632 | assert_equal ["issue_tracking"], @project.enabled_module_names | |
638 |
|
|
633 | #with symbol | |
639 |
|
|
634 | @project.enable_module!(:gantt) | |
640 |
|
|
635 | assert_equal ["issue_tracking", "gantt"], @project.enabled_module_names | |
641 |
|
|
636 | #don't add a module twice | |
642 |
|
|
637 | @project.enable_module!("issue_tracking") | |
643 |
|
|
638 | assert_equal ["issue_tracking", "gantt"], @project.enabled_module_names | |
644 |
|
|
639 | end | |
645 |
|
640 | |||
646 |
|
|
641 | test "enabled_modules should disable a module" do | |
|
642 | @project = Project.find(1) | |||
647 |
|
|
643 | #with string | |
648 |
|
|
644 | assert @project.enabled_module_names.include?("issue_tracking") | |
649 |
|
|
645 | @project.disable_module!("issue_tracking") | |
650 |
|
|
646 | assert ! @project.reload.enabled_module_names.include?("issue_tracking") | |
651 |
|
|
647 | #with symbol | |
652 |
|
|
648 | assert @project.enabled_module_names.include?("gantt") | |
653 |
|
|
649 | @project.disable_module!(:gantt) | |
654 |
|
|
650 | assert ! @project.reload.enabled_module_names.include?("gantt") | |
655 |
|
|
651 | #with EnabledModule object | |
656 |
|
|
652 | first_module = @project.enabled_modules.first | |
657 |
|
|
653 | @project.disable_module!(first_module) | |
658 |
|
|
654 | assert ! @project.reload.enabled_module_names.include?(first_module.name) | |
659 |
|
|
655 | end | |
660 | end |
|
|||
661 |
|
656 | |||
662 | def test_enabled_module_names_should_not_recreate_enabled_modules |
|
657 | def test_enabled_module_names_should_not_recreate_enabled_modules | |
663 | project = Project.find(1) |
|
658 | project = Project.find(1) | |
664 | # Remove one module |
|
659 | # Remove one module | |
665 | modules = project.enabled_modules.slice(0..-2) |
|
660 | modules = project.enabled_modules.slice(0..-2) | |
666 | assert modules.any? |
|
661 | assert modules.any? | |
667 | assert_difference 'EnabledModule.count', -1 do |
|
662 | assert_difference 'EnabledModule.count', -1 do | |
668 | project.enabled_module_names = modules.collect(&:name) |
|
663 | project.enabled_module_names = modules.collect(&:name) | |
669 | end |
|
664 | end | |
670 | project.reload |
|
665 | project.reload | |
671 | # Ids should be preserved |
|
666 | # Ids should be preserved | |
672 | assert_equal project.enabled_module_ids.sort, modules.collect(&:id).sort |
|
667 | assert_equal project.enabled_module_ids.sort, modules.collect(&:id).sort | |
673 | end |
|
668 | end | |
674 |
|
669 | |||
675 | def test_copy_from_existing_project |
|
670 | def test_copy_from_existing_project | |
676 | source_project = Project.find(1) |
|
671 | source_project = Project.find(1) | |
677 | copied_project = Project.copy_from(1) |
|
672 | copied_project = Project.copy_from(1) | |
678 |
|
673 | |||
679 | assert copied_project |
|
674 | assert copied_project | |
680 | # Cleared attributes |
|
675 | # Cleared attributes | |
681 | assert copied_project.id.blank? |
|
676 | assert copied_project.id.blank? | |
682 | assert copied_project.name.blank? |
|
677 | assert copied_project.name.blank? | |
683 | assert copied_project.identifier.blank? |
|
678 | assert copied_project.identifier.blank? | |
684 |
|
679 | |||
685 | # Duplicated attributes |
|
680 | # Duplicated attributes | |
686 | assert_equal source_project.description, copied_project.description |
|
681 | assert_equal source_project.description, copied_project.description | |
687 | assert_equal source_project.enabled_modules, copied_project.enabled_modules |
|
682 | assert_equal source_project.enabled_modules, copied_project.enabled_modules | |
688 | assert_equal source_project.trackers, copied_project.trackers |
|
683 | assert_equal source_project.trackers, copied_project.trackers | |
689 |
|
684 | |||
690 | # Default attributes |
|
685 | # Default attributes | |
691 | assert_equal 1, copied_project.status |
|
686 | assert_equal 1, copied_project.status | |
692 | end |
|
687 | end | |
693 |
|
688 | |||
694 | def test_activities_should_use_the_system_activities |
|
689 | def test_activities_should_use_the_system_activities | |
695 | project = Project.find(1) |
|
690 | project = Project.find(1) | |
696 | assert_equal project.activities, TimeEntryActivity.where(:active => true).all |
|
691 | assert_equal project.activities, TimeEntryActivity.where(:active => true).all | |
697 | end |
|
692 | end | |
698 |
|
693 | |||
699 |
|
694 | |||
700 | def test_activities_should_use_the_project_specific_activities |
|
695 | def test_activities_should_use_the_project_specific_activities | |
701 | project = Project.find(1) |
|
696 | project = Project.find(1) | |
702 | overridden_activity = TimeEntryActivity.new({:name => "Project", :project => project}) |
|
697 | overridden_activity = TimeEntryActivity.new({:name => "Project", :project => project}) | |
703 | assert overridden_activity.save! |
|
698 | assert overridden_activity.save! | |
704 |
|
699 | |||
705 | assert project.activities.include?(overridden_activity), "Project specific Activity not found" |
|
700 | assert project.activities.include?(overridden_activity), "Project specific Activity not found" | |
706 | end |
|
701 | end | |
707 |
|
702 | |||
708 | def test_activities_should_not_include_the_inactive_project_specific_activities |
|
703 | def test_activities_should_not_include_the_inactive_project_specific_activities | |
709 | project = Project.find(1) |
|
704 | project = Project.find(1) | |
710 | overridden_activity = TimeEntryActivity.new({:name => "Project", :project => project, :parent => TimeEntryActivity.first, :active => false}) |
|
705 | overridden_activity = TimeEntryActivity.new({:name => "Project", :project => project, :parent => TimeEntryActivity.first, :active => false}) | |
711 | assert overridden_activity.save! |
|
706 | assert overridden_activity.save! | |
712 |
|
707 | |||
713 | assert !project.activities.include?(overridden_activity), "Inactive Project specific Activity found" |
|
708 | assert !project.activities.include?(overridden_activity), "Inactive Project specific Activity found" | |
714 | end |
|
709 | end | |
715 |
|
710 | |||
716 | def test_activities_should_not_include_project_specific_activities_from_other_projects |
|
711 | def test_activities_should_not_include_project_specific_activities_from_other_projects | |
717 | project = Project.find(1) |
|
712 | project = Project.find(1) | |
718 | overridden_activity = TimeEntryActivity.new({:name => "Project", :project => Project.find(2)}) |
|
713 | overridden_activity = TimeEntryActivity.new({:name => "Project", :project => Project.find(2)}) | |
719 | assert overridden_activity.save! |
|
714 | assert overridden_activity.save! | |
720 |
|
715 | |||
721 | assert !project.activities.include?(overridden_activity), "Project specific Activity found on a different project" |
|
716 | assert !project.activities.include?(overridden_activity), "Project specific Activity found on a different project" | |
722 | end |
|
717 | end | |
723 |
|
718 | |||
724 | def test_activities_should_handle_nils |
|
719 | def test_activities_should_handle_nils | |
725 | overridden_activity = TimeEntryActivity.new({:name => "Project", :project => Project.find(1), :parent => TimeEntryActivity.first}) |
|
720 | overridden_activity = TimeEntryActivity.new({:name => "Project", :project => Project.find(1), :parent => TimeEntryActivity.first}) | |
726 | TimeEntryActivity.delete_all |
|
721 | TimeEntryActivity.delete_all | |
727 |
|
722 | |||
728 | # No activities |
|
723 | # No activities | |
729 | project = Project.find(1) |
|
724 | project = Project.find(1) | |
730 | assert project.activities.empty? |
|
725 | assert project.activities.empty? | |
731 |
|
726 | |||
732 | # No system, one overridden |
|
727 | # No system, one overridden | |
733 | assert overridden_activity.save! |
|
728 | assert overridden_activity.save! | |
734 | project.reload |
|
729 | project.reload | |
735 | assert_equal [overridden_activity], project.activities |
|
730 | assert_equal [overridden_activity], project.activities | |
736 | end |
|
731 | end | |
737 |
|
732 | |||
738 | def test_activities_should_override_system_activities_with_project_activities |
|
733 | def test_activities_should_override_system_activities_with_project_activities | |
739 | project = Project.find(1) |
|
734 | project = Project.find(1) | |
740 | parent_activity = TimeEntryActivity.first |
|
735 | parent_activity = TimeEntryActivity.first | |
741 | overridden_activity = TimeEntryActivity.new({:name => "Project", :project => project, :parent => parent_activity}) |
|
736 | overridden_activity = TimeEntryActivity.new({:name => "Project", :project => project, :parent => parent_activity}) | |
742 | assert overridden_activity.save! |
|
737 | assert overridden_activity.save! | |
743 |
|
738 | |||
744 | assert project.activities.include?(overridden_activity), "Project specific Activity not found" |
|
739 | assert project.activities.include?(overridden_activity), "Project specific Activity not found" | |
745 | assert !project.activities.include?(parent_activity), "System Activity found when it should have been overridden" |
|
740 | assert !project.activities.include?(parent_activity), "System Activity found when it should have been overridden" | |
746 | end |
|
741 | end | |
747 |
|
742 | |||
748 | def test_activities_should_include_inactive_activities_if_specified |
|
743 | def test_activities_should_include_inactive_activities_if_specified | |
749 | project = Project.find(1) |
|
744 | project = Project.find(1) | |
750 | overridden_activity = TimeEntryActivity.new({:name => "Project", :project => project, :parent => TimeEntryActivity.first, :active => false}) |
|
745 | overridden_activity = TimeEntryActivity.new({:name => "Project", :project => project, :parent => TimeEntryActivity.first, :active => false}) | |
751 | assert overridden_activity.save! |
|
746 | assert overridden_activity.save! | |
752 |
|
747 | |||
753 | assert project.activities(true).include?(overridden_activity), "Inactive Project specific Activity not found" |
|
748 | assert project.activities(true).include?(overridden_activity), "Inactive Project specific Activity not found" | |
754 | end |
|
749 | end | |
755 |
|
750 | |||
756 | test 'activities should not include active System activities if the project has an override that is inactive' do |
|
751 | test 'activities should not include active System activities if the project has an override that is inactive' do | |
757 | project = Project.find(1) |
|
752 | project = Project.find(1) | |
758 | system_activity = TimeEntryActivity.find_by_name('Design') |
|
753 | system_activity = TimeEntryActivity.find_by_name('Design') | |
759 | assert system_activity.active? |
|
754 | assert system_activity.active? | |
760 | overridden_activity = TimeEntryActivity.create!(:name => "Project", :project => project, :parent => system_activity, :active => false) |
|
755 | overridden_activity = TimeEntryActivity.create!(:name => "Project", :project => project, :parent => system_activity, :active => false) | |
761 | assert overridden_activity.save! |
|
756 | assert overridden_activity.save! | |
762 |
|
757 | |||
763 | assert !project.activities.include?(overridden_activity), "Inactive Project specific Activity not found" |
|
758 | assert !project.activities.include?(overridden_activity), "Inactive Project specific Activity not found" | |
764 | assert !project.activities.include?(system_activity), "System activity found when the project has an inactive override" |
|
759 | assert !project.activities.include?(system_activity), "System activity found when the project has an inactive override" | |
765 | end |
|
760 | end | |
766 |
|
761 | |||
767 | def test_close_completed_versions |
|
762 | def test_close_completed_versions | |
768 | Version.update_all("status = 'open'") |
|
763 | Version.update_all("status = 'open'") | |
769 | project = Project.find(1) |
|
764 | project = Project.find(1) | |
770 | assert_not_nil project.versions.detect {|v| v.completed? && v.status == 'open'} |
|
765 | assert_not_nil project.versions.detect {|v| v.completed? && v.status == 'open'} | |
771 | assert_not_nil project.versions.detect {|v| !v.completed? && v.status == 'open'} |
|
766 | assert_not_nil project.versions.detect {|v| !v.completed? && v.status == 'open'} | |
772 | project.close_completed_versions |
|
767 | project.close_completed_versions | |
773 | project.reload |
|
768 | project.reload | |
774 | assert_nil project.versions.detect {|v| v.completed? && v.status != 'closed'} |
|
769 | assert_nil project.versions.detect {|v| v.completed? && v.status != 'closed'} | |
775 | assert_not_nil project.versions.detect {|v| !v.completed? && v.status == 'open'} |
|
770 | assert_not_nil project.versions.detect {|v| !v.completed? && v.status == 'open'} | |
776 | end |
|
771 | end | |
777 |
|
772 | |||
778 | context "Project#copy" do |
|
773 | context "Project#copy" do | |
779 | setup do |
|
774 | setup do | |
780 | ProjectCustomField.destroy_all # Custom values are a mess to isolate in tests |
|
775 | ProjectCustomField.destroy_all # Custom values are a mess to isolate in tests | |
781 | Project.destroy_all :identifier => "copy-test" |
|
776 | Project.destroy_all :identifier => "copy-test" | |
782 | @source_project = Project.find(2) |
|
777 | @source_project = Project.find(2) | |
783 | @project = Project.new(:name => 'Copy Test', :identifier => 'copy-test') |
|
778 | @project = Project.new(:name => 'Copy Test', :identifier => 'copy-test') | |
784 | @project.trackers = @source_project.trackers |
|
779 | @project.trackers = @source_project.trackers | |
785 | @project.enabled_module_names = @source_project.enabled_modules.collect(&:name) |
|
780 | @project.enabled_module_names = @source_project.enabled_modules.collect(&:name) | |
786 | end |
|
781 | end | |
787 |
|
782 | |||
788 | should "copy issues" do |
|
783 | should "copy issues" do | |
789 | @source_project.issues << Issue.generate!(:status => IssueStatus.find_by_name('Closed'), |
|
784 | @source_project.issues << Issue.generate!(:status => IssueStatus.find_by_name('Closed'), | |
790 | :subject => "copy issue status", |
|
785 | :subject => "copy issue status", | |
791 | :tracker_id => 1, |
|
786 | :tracker_id => 1, | |
792 | :assigned_to_id => 2, |
|
787 | :assigned_to_id => 2, | |
793 | :project_id => @source_project.id) |
|
788 | :project_id => @source_project.id) | |
794 | assert @project.valid? |
|
789 | assert @project.valid? | |
795 | assert @project.issues.empty? |
|
790 | assert @project.issues.empty? | |
796 | assert @project.copy(@source_project) |
|
791 | assert @project.copy(@source_project) | |
797 |
|
792 | |||
798 | assert_equal @source_project.issues.size, @project.issues.size |
|
793 | assert_equal @source_project.issues.size, @project.issues.size | |
799 | @project.issues.each do |issue| |
|
794 | @project.issues.each do |issue| | |
800 | assert issue.valid? |
|
795 | assert issue.valid? | |
801 | assert ! issue.assigned_to.blank? |
|
796 | assert ! issue.assigned_to.blank? | |
802 | assert_equal @project, issue.project |
|
797 | assert_equal @project, issue.project | |
803 | end |
|
798 | end | |
804 |
|
799 | |||
805 | copied_issue = @project.issues.first(:conditions => {:subject => "copy issue status"}) |
|
800 | copied_issue = @project.issues.first(:conditions => {:subject => "copy issue status"}) | |
806 | assert copied_issue |
|
801 | assert copied_issue | |
807 | assert copied_issue.status |
|
802 | assert copied_issue.status | |
808 | assert_equal "Closed", copied_issue.status.name |
|
803 | assert_equal "Closed", copied_issue.status.name | |
809 | end |
|
804 | end | |
810 |
|
805 | |||
811 | should "copy issues assigned to a locked version" do |
|
806 | should "copy issues assigned to a locked version" do | |
812 | User.current = User.find(1) |
|
807 | User.current = User.find(1) | |
813 | assigned_version = Version.generate!(:name => "Assigned Issues") |
|
808 | assigned_version = Version.generate!(:name => "Assigned Issues") | |
814 | @source_project.versions << assigned_version |
|
809 | @source_project.versions << assigned_version | |
815 | Issue.generate!(:project => @source_project, |
|
810 | Issue.generate!(:project => @source_project, | |
816 | :fixed_version_id => assigned_version.id, |
|
811 | :fixed_version_id => assigned_version.id, | |
817 | :subject => "copy issues assigned to a locked version") |
|
812 | :subject => "copy issues assigned to a locked version") | |
818 | assigned_version.update_attribute :status, 'locked' |
|
813 | assigned_version.update_attribute :status, 'locked' | |
819 |
|
814 | |||
820 | assert @project.copy(@source_project) |
|
815 | assert @project.copy(@source_project) | |
821 | @project.reload |
|
816 | @project.reload | |
822 | copied_issue = @project.issues.first(:conditions => {:subject => "copy issues assigned to a locked version"}) |
|
817 | copied_issue = @project.issues.first(:conditions => {:subject => "copy issues assigned to a locked version"}) | |
823 |
|
818 | |||
824 | assert copied_issue |
|
819 | assert copied_issue | |
825 | assert copied_issue.fixed_version |
|
820 | assert copied_issue.fixed_version | |
826 | assert_equal "Assigned Issues", copied_issue.fixed_version.name # Same name |
|
821 | assert_equal "Assigned Issues", copied_issue.fixed_version.name # Same name | |
827 | assert_equal 'locked', copied_issue.fixed_version.status |
|
822 | assert_equal 'locked', copied_issue.fixed_version.status | |
828 | end |
|
823 | end | |
829 |
|
824 | |||
830 | should "change the new issues to use the copied version" do |
|
825 | should "change the new issues to use the copied version" do | |
831 | User.current = User.find(1) |
|
826 | User.current = User.find(1) | |
832 | assigned_version = Version.generate!(:name => "Assigned Issues", :status => 'open') |
|
827 | assigned_version = Version.generate!(:name => "Assigned Issues", :status => 'open') | |
833 | @source_project.versions << assigned_version |
|
828 | @source_project.versions << assigned_version | |
834 | assert_equal 3, @source_project.versions.size |
|
829 | assert_equal 3, @source_project.versions.size | |
835 | Issue.generate!(:project => @source_project, |
|
830 | Issue.generate!(:project => @source_project, | |
836 | :fixed_version_id => assigned_version.id, |
|
831 | :fixed_version_id => assigned_version.id, | |
837 | :subject => "change the new issues to use the copied version") |
|
832 | :subject => "change the new issues to use the copied version") | |
838 |
|
833 | |||
839 | assert @project.copy(@source_project) |
|
834 | assert @project.copy(@source_project) | |
840 | @project.reload |
|
835 | @project.reload | |
841 | copied_issue = @project.issues.first(:conditions => {:subject => "change the new issues to use the copied version"}) |
|
836 | copied_issue = @project.issues.first(:conditions => {:subject => "change the new issues to use the copied version"}) | |
842 |
|
837 | |||
843 | assert copied_issue |
|
838 | assert copied_issue | |
844 | assert copied_issue.fixed_version |
|
839 | assert copied_issue.fixed_version | |
845 | assert_equal "Assigned Issues", copied_issue.fixed_version.name # Same name |
|
840 | assert_equal "Assigned Issues", copied_issue.fixed_version.name # Same name | |
846 | assert_not_equal assigned_version.id, copied_issue.fixed_version.id # Different record |
|
841 | assert_not_equal assigned_version.id, copied_issue.fixed_version.id # Different record | |
847 | end |
|
842 | end | |
848 |
|
843 | |||
849 | should "keep target shared versions from other project" do |
|
844 | should "keep target shared versions from other project" do | |
850 | assigned_version = Version.generate!(:name => "Assigned Issues", :status => 'open', :project_id => 1, :sharing => 'system') |
|
845 | assigned_version = Version.generate!(:name => "Assigned Issues", :status => 'open', :project_id => 1, :sharing => 'system') | |
851 | issue = Issue.generate!(:project => @source_project, |
|
846 | issue = Issue.generate!(:project => @source_project, | |
852 | :fixed_version => assigned_version, |
|
847 | :fixed_version => assigned_version, | |
853 | :subject => "keep target shared versions") |
|
848 | :subject => "keep target shared versions") | |
854 |
|
849 | |||
855 | assert @project.copy(@source_project) |
|
850 | assert @project.copy(@source_project) | |
856 | @project.reload |
|
851 | @project.reload | |
857 | copied_issue = @project.issues.first(:conditions => {:subject => "keep target shared versions"}) |
|
852 | copied_issue = @project.issues.first(:conditions => {:subject => "keep target shared versions"}) | |
858 |
|
853 | |||
859 | assert copied_issue |
|
854 | assert copied_issue | |
860 | assert_equal assigned_version, copied_issue.fixed_version |
|
855 | assert_equal assigned_version, copied_issue.fixed_version | |
861 | end |
|
856 | end | |
862 |
|
857 | |||
863 | should "copy issue relations" do |
|
858 | should "copy issue relations" do | |
864 | Setting.cross_project_issue_relations = '1' |
|
859 | Setting.cross_project_issue_relations = '1' | |
865 |
|
860 | |||
866 | second_issue = Issue.generate!(:status_id => 5, |
|
861 | second_issue = Issue.generate!(:status_id => 5, | |
867 | :subject => "copy issue relation", |
|
862 | :subject => "copy issue relation", | |
868 | :tracker_id => 1, |
|
863 | :tracker_id => 1, | |
869 | :assigned_to_id => 2, |
|
864 | :assigned_to_id => 2, | |
870 | :project_id => @source_project.id) |
|
865 | :project_id => @source_project.id) | |
871 | source_relation = IssueRelation.create!(:issue_from => Issue.find(4), |
|
866 | source_relation = IssueRelation.create!(:issue_from => Issue.find(4), | |
872 | :issue_to => second_issue, |
|
867 | :issue_to => second_issue, | |
873 | :relation_type => "relates") |
|
868 | :relation_type => "relates") | |
874 | source_relation_cross_project = IssueRelation.create!(:issue_from => Issue.find(1), |
|
869 | source_relation_cross_project = IssueRelation.create!(:issue_from => Issue.find(1), | |
875 | :issue_to => second_issue, |
|
870 | :issue_to => second_issue, | |
876 | :relation_type => "duplicates") |
|
871 | :relation_type => "duplicates") | |
877 |
|
872 | |||
878 | assert @project.copy(@source_project) |
|
873 | assert @project.copy(@source_project) | |
879 | assert_equal @source_project.issues.count, @project.issues.count |
|
874 | assert_equal @source_project.issues.count, @project.issues.count | |
880 | copied_issue = @project.issues.find_by_subject("Issue on project 2") # Was #4 |
|
875 | copied_issue = @project.issues.find_by_subject("Issue on project 2") # Was #4 | |
881 | copied_second_issue = @project.issues.find_by_subject("copy issue relation") |
|
876 | copied_second_issue = @project.issues.find_by_subject("copy issue relation") | |
882 |
|
877 | |||
883 | # First issue with a relation on project |
|
878 | # First issue with a relation on project | |
884 | assert_equal 1, copied_issue.relations.size, "Relation not copied" |
|
879 | assert_equal 1, copied_issue.relations.size, "Relation not copied" | |
885 | copied_relation = copied_issue.relations.first |
|
880 | copied_relation = copied_issue.relations.first | |
886 | assert_equal "relates", copied_relation.relation_type |
|
881 | assert_equal "relates", copied_relation.relation_type | |
887 | assert_equal copied_second_issue.id, copied_relation.issue_to_id |
|
882 | assert_equal copied_second_issue.id, copied_relation.issue_to_id | |
888 | assert_not_equal source_relation.id, copied_relation.id |
|
883 | assert_not_equal source_relation.id, copied_relation.id | |
889 |
|
884 | |||
890 | # Second issue with a cross project relation |
|
885 | # Second issue with a cross project relation | |
891 | assert_equal 2, copied_second_issue.relations.size, "Relation not copied" |
|
886 | assert_equal 2, copied_second_issue.relations.size, "Relation not copied" | |
892 | copied_relation = copied_second_issue.relations.select {|r| r.relation_type == 'duplicates'}.first |
|
887 | copied_relation = copied_second_issue.relations.select {|r| r.relation_type == 'duplicates'}.first | |
893 | assert_equal "duplicates", copied_relation.relation_type |
|
888 | assert_equal "duplicates", copied_relation.relation_type | |
894 | assert_equal 1, copied_relation.issue_from_id, "Cross project relation not kept" |
|
889 | assert_equal 1, copied_relation.issue_from_id, "Cross project relation not kept" | |
895 | assert_not_equal source_relation_cross_project.id, copied_relation.id |
|
890 | assert_not_equal source_relation_cross_project.id, copied_relation.id | |
896 | end |
|
891 | end | |
897 |
|
892 | |||
898 | should "copy issue attachments" do |
|
893 | should "copy issue attachments" do | |
899 | issue = Issue.generate!(:subject => "copy with attachment", :tracker_id => 1, :project_id => @source_project.id) |
|
894 | issue = Issue.generate!(:subject => "copy with attachment", :tracker_id => 1, :project_id => @source_project.id) | |
900 | Attachment.create!(:container => issue, :file => uploaded_test_file("testfile.txt", "text/plain"), :author_id => 1) |
|
895 | Attachment.create!(:container => issue, :file => uploaded_test_file("testfile.txt", "text/plain"), :author_id => 1) | |
901 | @source_project.issues << issue |
|
896 | @source_project.issues << issue | |
902 | assert @project.copy(@source_project) |
|
897 | assert @project.copy(@source_project) | |
903 |
|
898 | |||
904 | copied_issue = @project.issues.first(:conditions => {:subject => "copy with attachment"}) |
|
899 | copied_issue = @project.issues.first(:conditions => {:subject => "copy with attachment"}) | |
905 | assert_not_nil copied_issue |
|
900 | assert_not_nil copied_issue | |
906 | assert_equal 1, copied_issue.attachments.count, "Attachment not copied" |
|
901 | assert_equal 1, copied_issue.attachments.count, "Attachment not copied" | |
907 | assert_equal "testfile.txt", copied_issue.attachments.first.filename |
|
902 | assert_equal "testfile.txt", copied_issue.attachments.first.filename | |
908 | end |
|
903 | end | |
909 |
|
904 | |||
910 | should "copy memberships" do |
|
905 | should "copy memberships" do | |
911 | assert @project.valid? |
|
906 | assert @project.valid? | |
912 | assert @project.members.empty? |
|
907 | assert @project.members.empty? | |
913 | assert @project.copy(@source_project) |
|
908 | assert @project.copy(@source_project) | |
914 |
|
909 | |||
915 | assert_equal @source_project.memberships.size, @project.memberships.size |
|
910 | assert_equal @source_project.memberships.size, @project.memberships.size | |
916 | @project.memberships.each do |membership| |
|
911 | @project.memberships.each do |membership| | |
917 | assert membership |
|
912 | assert membership | |
918 | assert_equal @project, membership.project |
|
913 | assert_equal @project, membership.project | |
919 | end |
|
914 | end | |
920 | end |
|
915 | end | |
921 |
|
916 | |||
922 | should "copy memberships with groups and additional roles" do |
|
917 | should "copy memberships with groups and additional roles" do | |
923 | group = Group.create!(:lastname => "Copy group") |
|
918 | group = Group.create!(:lastname => "Copy group") | |
924 | user = User.find(7) |
|
919 | user = User.find(7) | |
925 | group.users << user |
|
920 | group.users << user | |
926 | # group role |
|
921 | # group role | |
927 | Member.create!(:project_id => @source_project.id, :principal => group, :role_ids => [2]) |
|
922 | Member.create!(:project_id => @source_project.id, :principal => group, :role_ids => [2]) | |
928 | member = Member.find_by_user_id_and_project_id(user.id, @source_project.id) |
|
923 | member = Member.find_by_user_id_and_project_id(user.id, @source_project.id) | |
929 | # additional role |
|
924 | # additional role | |
930 | member.role_ids = [1] |
|
925 | member.role_ids = [1] | |
931 |
|
926 | |||
932 | assert @project.copy(@source_project) |
|
927 | assert @project.copy(@source_project) | |
933 | member = Member.find_by_user_id_and_project_id(user.id, @project.id) |
|
928 | member = Member.find_by_user_id_and_project_id(user.id, @project.id) | |
934 | assert_not_nil member |
|
929 | assert_not_nil member | |
935 | assert_equal [1, 2], member.role_ids.sort |
|
930 | assert_equal [1, 2], member.role_ids.sort | |
936 | end |
|
931 | end | |
937 |
|
932 | |||
938 | should "copy project specific queries" do |
|
933 | should "copy project specific queries" do | |
939 | assert @project.valid? |
|
934 | assert @project.valid? | |
940 | assert @project.queries.empty? |
|
935 | assert @project.queries.empty? | |
941 | assert @project.copy(@source_project) |
|
936 | assert @project.copy(@source_project) | |
942 |
|
937 | |||
943 | assert_equal @source_project.queries.size, @project.queries.size |
|
938 | assert_equal @source_project.queries.size, @project.queries.size | |
944 | @project.queries.each do |query| |
|
939 | @project.queries.each do |query| | |
945 | assert query |
|
940 | assert query | |
946 | assert_equal @project, query.project |
|
941 | assert_equal @project, query.project | |
947 | end |
|
942 | end | |
948 | assert_equal @source_project.queries.map(&:user_id).sort, @project.queries.map(&:user_id).sort |
|
943 | assert_equal @source_project.queries.map(&:user_id).sort, @project.queries.map(&:user_id).sort | |
949 | end |
|
944 | end | |
950 |
|
945 | |||
951 | should "copy versions" do |
|
946 | should "copy versions" do | |
952 | @source_project.versions << Version.generate! |
|
947 | @source_project.versions << Version.generate! | |
953 | @source_project.versions << Version.generate! |
|
948 | @source_project.versions << Version.generate! | |
954 |
|
949 | |||
955 | assert @project.versions.empty? |
|
950 | assert @project.versions.empty? | |
956 | assert @project.copy(@source_project) |
|
951 | assert @project.copy(@source_project) | |
957 |
|
952 | |||
958 | assert_equal @source_project.versions.size, @project.versions.size |
|
953 | assert_equal @source_project.versions.size, @project.versions.size | |
959 | @project.versions.each do |version| |
|
954 | @project.versions.each do |version| | |
960 | assert version |
|
955 | assert version | |
961 | assert_equal @project, version.project |
|
956 | assert_equal @project, version.project | |
962 | end |
|
957 | end | |
963 | end |
|
958 | end | |
964 |
|
959 | |||
965 | should "copy wiki" do |
|
960 | should "copy wiki" do | |
966 | assert_difference 'Wiki.count' do |
|
961 | assert_difference 'Wiki.count' do | |
967 | assert @project.copy(@source_project) |
|
962 | assert @project.copy(@source_project) | |
968 | end |
|
963 | end | |
969 |
|
964 | |||
970 | assert @project.wiki |
|
965 | assert @project.wiki | |
971 | assert_not_equal @source_project.wiki, @project.wiki |
|
966 | assert_not_equal @source_project.wiki, @project.wiki | |
972 | assert_equal "Start page", @project.wiki.start_page |
|
967 | assert_equal "Start page", @project.wiki.start_page | |
973 | end |
|
968 | end | |
974 |
|
969 | |||
975 | should "copy wiki pages and content with hierarchy" do |
|
970 | should "copy wiki pages and content with hierarchy" do | |
976 | assert_difference 'WikiPage.count', @source_project.wiki.pages.size do |
|
971 | assert_difference 'WikiPage.count', @source_project.wiki.pages.size do | |
977 | assert @project.copy(@source_project) |
|
972 | assert @project.copy(@source_project) | |
978 | end |
|
973 | end | |
979 |
|
974 | |||
980 | assert @project.wiki |
|
975 | assert @project.wiki | |
981 | assert_equal @source_project.wiki.pages.size, @project.wiki.pages.size |
|
976 | assert_equal @source_project.wiki.pages.size, @project.wiki.pages.size | |
982 |
|
977 | |||
983 | @project.wiki.pages.each do |wiki_page| |
|
978 | @project.wiki.pages.each do |wiki_page| | |
984 | assert wiki_page.content |
|
979 | assert wiki_page.content | |
985 | assert !@source_project.wiki.pages.include?(wiki_page) |
|
980 | assert !@source_project.wiki.pages.include?(wiki_page) | |
986 | end |
|
981 | end | |
987 |
|
982 | |||
988 | parent = @project.wiki.find_page('Parent_page') |
|
983 | parent = @project.wiki.find_page('Parent_page') | |
989 | child1 = @project.wiki.find_page('Child_page_1') |
|
984 | child1 = @project.wiki.find_page('Child_page_1') | |
990 | child2 = @project.wiki.find_page('Child_page_2') |
|
985 | child2 = @project.wiki.find_page('Child_page_2') | |
991 | assert_equal parent, child1.parent |
|
986 | assert_equal parent, child1.parent | |
992 | assert_equal parent, child2.parent |
|
987 | assert_equal parent, child2.parent | |
993 | end |
|
988 | end | |
994 |
|
989 | |||
995 | should "copy issue categories" do |
|
990 | should "copy issue categories" do | |
996 | assert @project.copy(@source_project) |
|
991 | assert @project.copy(@source_project) | |
997 |
|
992 | |||
998 | assert_equal 2, @project.issue_categories.size |
|
993 | assert_equal 2, @project.issue_categories.size | |
999 | @project.issue_categories.each do |issue_category| |
|
994 | @project.issue_categories.each do |issue_category| | |
1000 | assert !@source_project.issue_categories.include?(issue_category) |
|
995 | assert !@source_project.issue_categories.include?(issue_category) | |
1001 | end |
|
996 | end | |
1002 | end |
|
997 | end | |
1003 |
|
998 | |||
1004 | should "copy boards" do |
|
999 | should "copy boards" do | |
1005 | assert @project.copy(@source_project) |
|
1000 | assert @project.copy(@source_project) | |
1006 |
|
1001 | |||
1007 | assert_equal 1, @project.boards.size |
|
1002 | assert_equal 1, @project.boards.size | |
1008 | @project.boards.each do |board| |
|
1003 | @project.boards.each do |board| | |
1009 | assert !@source_project.boards.include?(board) |
|
1004 | assert !@source_project.boards.include?(board) | |
1010 | end |
|
1005 | end | |
1011 | end |
|
1006 | end | |
1012 |
|
1007 | |||
1013 | should "change the new issues to use the copied issue categories" do |
|
1008 | should "change the new issues to use the copied issue categories" do | |
1014 | issue = Issue.find(4) |
|
1009 | issue = Issue.find(4) | |
1015 | issue.update_attribute(:category_id, 3) |
|
1010 | issue.update_attribute(:category_id, 3) | |
1016 |
|
1011 | |||
1017 | assert @project.copy(@source_project) |
|
1012 | assert @project.copy(@source_project) | |
1018 |
|
1013 | |||
1019 | @project.issues.each do |issue| |
|
1014 | @project.issues.each do |issue| | |
1020 | assert issue.category |
|
1015 | assert issue.category | |
1021 | assert_equal "Stock management", issue.category.name # Same name |
|
1016 | assert_equal "Stock management", issue.category.name # Same name | |
1022 | assert_not_equal IssueCategory.find(3), issue.category # Different record |
|
1017 | assert_not_equal IssueCategory.find(3), issue.category # Different record | |
1023 | end |
|
1018 | end | |
1024 | end |
|
1019 | end | |
1025 |
|
1020 | |||
1026 | should "limit copy with :only option" do |
|
1021 | should "limit copy with :only option" do | |
1027 | assert @project.members.empty? |
|
1022 | assert @project.members.empty? | |
1028 | assert @project.issue_categories.empty? |
|
1023 | assert @project.issue_categories.empty? | |
1029 | assert @source_project.issues.any? |
|
1024 | assert @source_project.issues.any? | |
1030 |
|
1025 | |||
1031 | assert @project.copy(@source_project, :only => ['members', 'issue_categories']) |
|
1026 | assert @project.copy(@source_project, :only => ['members', 'issue_categories']) | |
1032 |
|
1027 | |||
1033 | assert @project.members.any? |
|
1028 | assert @project.members.any? | |
1034 | assert @project.issue_categories.any? |
|
1029 | assert @project.issue_categories.any? | |
1035 | assert @project.issues.empty? |
|
1030 | assert @project.issues.empty? | |
1036 | end |
|
1031 | end | |
1037 | end |
|
1032 | end | |
1038 |
|
1033 | |||
1039 | def test_copy_should_copy_subtasks |
|
1034 | def test_copy_should_copy_subtasks | |
1040 | source = Project.generate!(:tracker_ids => [1]) |
|
1035 | source = Project.generate!(:tracker_ids => [1]) | |
1041 | issue = Issue.generate_with_descendants!(:project => source) |
|
1036 | issue = Issue.generate_with_descendants!(:project => source) | |
1042 | project = Project.new(:name => 'Copy', :identifier => 'copy', :tracker_ids => [1]) |
|
1037 | project = Project.new(:name => 'Copy', :identifier => 'copy', :tracker_ids => [1]) | |
1043 |
|
1038 | |||
1044 | assert_difference 'Project.count' do |
|
1039 | assert_difference 'Project.count' do | |
1045 | assert_difference 'Issue.count', 1+issue.descendants.count do |
|
1040 | assert_difference 'Issue.count', 1+issue.descendants.count do | |
1046 | assert project.copy(source.reload) |
|
1041 | assert project.copy(source.reload) | |
1047 | end |
|
1042 | end | |
1048 | end |
|
1043 | end | |
1049 | copy = Issue.where(:parent_id => nil).order("id DESC").first |
|
1044 | copy = Issue.where(:parent_id => nil).order("id DESC").first | |
1050 | assert_equal project, copy.project |
|
1045 | assert_equal project, copy.project | |
1051 | assert_equal issue.descendants.count, copy.descendants.count |
|
1046 | assert_equal issue.descendants.count, copy.descendants.count | |
1052 | child_copy = copy.children.detect {|c| c.subject == 'Child1'} |
|
1047 | child_copy = copy.children.detect {|c| c.subject == 'Child1'} | |
1053 | assert child_copy.descendants.any? |
|
1048 | assert child_copy.descendants.any? | |
1054 | end |
|
1049 | end | |
1055 |
|
1050 | |||
1056 | context "#start_date" do |
|
1051 | context "#start_date" do | |
1057 | setup do |
|
1052 | setup do | |
1058 | ProjectCustomField.destroy_all # Custom values are a mess to isolate in tests |
|
1053 | ProjectCustomField.destroy_all # Custom values are a mess to isolate in tests | |
1059 | @project = Project.generate!(:identifier => 'test0') |
|
1054 | @project = Project.generate!(:identifier => 'test0') | |
1060 | @project.trackers << Tracker.generate! |
|
1055 | @project.trackers << Tracker.generate! | |
1061 | end |
|
1056 | end | |
1062 |
|
1057 | |||
1063 | should "be nil if there are no issues on the project" do |
|
1058 | should "be nil if there are no issues on the project" do | |
1064 | assert_nil @project.start_date |
|
1059 | assert_nil @project.start_date | |
1065 | end |
|
1060 | end | |
1066 |
|
1061 | |||
1067 | should "be tested when issues have no start date" |
|
1062 | should "be tested when issues have no start date" | |
1068 |
|
1063 | |||
1069 | should "be the earliest start date of it's issues" do |
|
1064 | should "be the earliest start date of it's issues" do | |
1070 | early = 7.days.ago.to_date |
|
1065 | early = 7.days.ago.to_date | |
1071 | Issue.generate!(:project => @project, :start_date => Date.today) |
|
1066 | Issue.generate!(:project => @project, :start_date => Date.today) | |
1072 | Issue.generate!(:project => @project, :start_date => early) |
|
1067 | Issue.generate!(:project => @project, :start_date => early) | |
1073 |
|
1068 | |||
1074 | assert_equal early, @project.start_date |
|
1069 | assert_equal early, @project.start_date | |
1075 | end |
|
1070 | end | |
1076 |
|
1071 | |||
1077 | end |
|
1072 | end | |
1078 |
|
1073 | |||
1079 | context "#due_date" do |
|
1074 | context "#due_date" do | |
1080 | setup do |
|
1075 | setup do | |
1081 | ProjectCustomField.destroy_all # Custom values are a mess to isolate in tests |
|
1076 | ProjectCustomField.destroy_all # Custom values are a mess to isolate in tests | |
1082 | @project = Project.generate!(:identifier => 'test0') |
|
1077 | @project = Project.generate!(:identifier => 'test0') | |
1083 | @project.trackers << Tracker.generate! |
|
1078 | @project.trackers << Tracker.generate! | |
1084 | end |
|
1079 | end | |
1085 |
|
1080 | |||
1086 | should "be nil if there are no issues on the project" do |
|
1081 | should "be nil if there are no issues on the project" do | |
1087 | assert_nil @project.due_date |
|
1082 | assert_nil @project.due_date | |
1088 | end |
|
1083 | end | |
1089 |
|
1084 | |||
1090 | should "be tested when issues have no due date" |
|
1085 | should "be tested when issues have no due date" | |
1091 |
|
1086 | |||
1092 | should "be the latest due date of it's issues" do |
|
1087 | should "be the latest due date of it's issues" do | |
1093 | future = 7.days.from_now.to_date |
|
1088 | future = 7.days.from_now.to_date | |
1094 | Issue.generate!(:project => @project, :due_date => future) |
|
1089 | Issue.generate!(:project => @project, :due_date => future) | |
1095 | Issue.generate!(:project => @project, :due_date => Date.today) |
|
1090 | Issue.generate!(:project => @project, :due_date => Date.today) | |
1096 |
|
1091 | |||
1097 | assert_equal future, @project.due_date |
|
1092 | assert_equal future, @project.due_date | |
1098 | end |
|
1093 | end | |
1099 |
|
1094 | |||
1100 | should "be the latest due date of it's versions" do |
|
1095 | should "be the latest due date of it's versions" do | |
1101 | future = 7.days.from_now.to_date |
|
1096 | future = 7.days.from_now.to_date | |
1102 | @project.versions << Version.generate!(:effective_date => future) |
|
1097 | @project.versions << Version.generate!(:effective_date => future) | |
1103 | @project.versions << Version.generate!(:effective_date => Date.today) |
|
1098 | @project.versions << Version.generate!(:effective_date => Date.today) | |
1104 |
|
1099 | |||
1105 |
|
1100 | |||
1106 | assert_equal future, @project.due_date |
|
1101 | assert_equal future, @project.due_date | |
1107 |
|
1102 | |||
1108 | end |
|
1103 | end | |
1109 |
|
1104 | |||
1110 | should "pick the latest date from it's issues and versions" do |
|
1105 | should "pick the latest date from it's issues and versions" do | |
1111 | future = 7.days.from_now.to_date |
|
1106 | future = 7.days.from_now.to_date | |
1112 | far_future = 14.days.from_now.to_date |
|
1107 | far_future = 14.days.from_now.to_date | |
1113 | Issue.generate!(:project => @project, :due_date => far_future) |
|
1108 | Issue.generate!(:project => @project, :due_date => far_future) | |
1114 | @project.versions << Version.generate!(:effective_date => future) |
|
1109 | @project.versions << Version.generate!(:effective_date => future) | |
1115 |
|
1110 | |||
1116 | assert_equal far_future, @project.due_date |
|
1111 | assert_equal far_future, @project.due_date | |
1117 | end |
|
1112 | end | |
1118 |
|
1113 | |||
1119 | end |
|
1114 | end | |
1120 |
|
1115 | |||
1121 | context "Project#completed_percent" do |
|
1116 | context "Project#completed_percent" do | |
1122 | setup do |
|
1117 | setup do | |
1123 | ProjectCustomField.destroy_all # Custom values are a mess to isolate in tests |
|
1118 | ProjectCustomField.destroy_all # Custom values are a mess to isolate in tests | |
1124 | @project = Project.generate!(:identifier => 'test0') |
|
1119 | @project = Project.generate!(:identifier => 'test0') | |
1125 | @project.trackers << Tracker.generate! |
|
1120 | @project.trackers << Tracker.generate! | |
1126 | end |
|
1121 | end | |
1127 |
|
1122 | |||
1128 | context "no versions" do |
|
1123 | context "no versions" do | |
1129 | should "be 100" do |
|
1124 | should "be 100" do | |
1130 | assert_equal 100, @project.completed_percent |
|
1125 | assert_equal 100, @project.completed_percent | |
1131 | end |
|
1126 | end | |
1132 | end |
|
1127 | end | |
1133 |
|
1128 | |||
1134 | context "with versions" do |
|
1129 | context "with versions" do | |
1135 | should "return 0 if the versions have no issues" do |
|
1130 | should "return 0 if the versions have no issues" do | |
1136 | Version.generate!(:project => @project) |
|
1131 | Version.generate!(:project => @project) | |
1137 | Version.generate!(:project => @project) |
|
1132 | Version.generate!(:project => @project) | |
1138 |
|
1133 | |||
1139 | assert_equal 0, @project.completed_percent |
|
1134 | assert_equal 0, @project.completed_percent | |
1140 | end |
|
1135 | end | |
1141 |
|
1136 | |||
1142 | should "return 100 if the version has only closed issues" do |
|
1137 | should "return 100 if the version has only closed issues" do | |
1143 | v1 = Version.generate!(:project => @project) |
|
1138 | v1 = Version.generate!(:project => @project) | |
1144 | Issue.generate!(:project => @project, :status => IssueStatus.find_by_name('Closed'), :fixed_version => v1) |
|
1139 | Issue.generate!(:project => @project, :status => IssueStatus.find_by_name('Closed'), :fixed_version => v1) | |
1145 | v2 = Version.generate!(:project => @project) |
|
1140 | v2 = Version.generate!(:project => @project) | |
1146 | Issue.generate!(:project => @project, :status => IssueStatus.find_by_name('Closed'), :fixed_version => v2) |
|
1141 | Issue.generate!(:project => @project, :status => IssueStatus.find_by_name('Closed'), :fixed_version => v2) | |
1147 |
|
1142 | |||
1148 | assert_equal 100, @project.completed_percent |
|
1143 | assert_equal 100, @project.completed_percent | |
1149 | end |
|
1144 | end | |
1150 |
|
1145 | |||
1151 | should "return the averaged completed percent of the versions (not weighted)" do |
|
1146 | should "return the averaged completed percent of the versions (not weighted)" do | |
1152 | v1 = Version.generate!(:project => @project) |
|
1147 | v1 = Version.generate!(:project => @project) | |
1153 | Issue.generate!(:project => @project, :status => IssueStatus.find_by_name('New'), :estimated_hours => 10, :done_ratio => 50, :fixed_version => v1) |
|
1148 | Issue.generate!(:project => @project, :status => IssueStatus.find_by_name('New'), :estimated_hours => 10, :done_ratio => 50, :fixed_version => v1) | |
1154 | v2 = Version.generate!(:project => @project) |
|
1149 | v2 = Version.generate!(:project => @project) | |
1155 | Issue.generate!(:project => @project, :status => IssueStatus.find_by_name('New'), :estimated_hours => 10, :done_ratio => 50, :fixed_version => v2) |
|
1150 | Issue.generate!(:project => @project, :status => IssueStatus.find_by_name('New'), :estimated_hours => 10, :done_ratio => 50, :fixed_version => v2) | |
1156 |
|
1151 | |||
1157 | assert_equal 50, @project.completed_percent |
|
1152 | assert_equal 50, @project.completed_percent | |
1158 | end |
|
1153 | end | |
1159 |
|
1154 | |||
1160 | end |
|
1155 | end | |
1161 | end |
|
1156 | end | |
1162 |
|
1157 | |||
1163 | context "#notified_users" do |
|
1158 | context "#notified_users" do | |
1164 | setup do |
|
1159 | setup do | |
1165 | @project = Project.generate! |
|
1160 | @project = Project.generate! | |
1166 | @role = Role.generate! |
|
1161 | @role = Role.generate! | |
1167 |
|
1162 | |||
1168 | @user_with_membership_notification = User.generate!(:mail_notification => 'selected') |
|
1163 | @user_with_membership_notification = User.generate!(:mail_notification => 'selected') | |
1169 | Member.create!(:project => @project, :roles => [@role], :principal => @user_with_membership_notification, :mail_notification => true) |
|
1164 | Member.create!(:project => @project, :roles => [@role], :principal => @user_with_membership_notification, :mail_notification => true) | |
1170 |
|
1165 | |||
1171 | @all_events_user = User.generate!(:mail_notification => 'all') |
|
1166 | @all_events_user = User.generate!(:mail_notification => 'all') | |
1172 | Member.create!(:project => @project, :roles => [@role], :principal => @all_events_user) |
|
1167 | Member.create!(:project => @project, :roles => [@role], :principal => @all_events_user) | |
1173 |
|
1168 | |||
1174 | @no_events_user = User.generate!(:mail_notification => 'none') |
|
1169 | @no_events_user = User.generate!(:mail_notification => 'none') | |
1175 | Member.create!(:project => @project, :roles => [@role], :principal => @no_events_user) |
|
1170 | Member.create!(:project => @project, :roles => [@role], :principal => @no_events_user) | |
1176 |
|
1171 | |||
1177 | @only_my_events_user = User.generate!(:mail_notification => 'only_my_events') |
|
1172 | @only_my_events_user = User.generate!(:mail_notification => 'only_my_events') | |
1178 | Member.create!(:project => @project, :roles => [@role], :principal => @only_my_events_user) |
|
1173 | Member.create!(:project => @project, :roles => [@role], :principal => @only_my_events_user) | |
1179 |
|
1174 | |||
1180 | @only_assigned_user = User.generate!(:mail_notification => 'only_assigned') |
|
1175 | @only_assigned_user = User.generate!(:mail_notification => 'only_assigned') | |
1181 | Member.create!(:project => @project, :roles => [@role], :principal => @only_assigned_user) |
|
1176 | Member.create!(:project => @project, :roles => [@role], :principal => @only_assigned_user) | |
1182 |
|
1177 | |||
1183 | @only_owned_user = User.generate!(:mail_notification => 'only_owner') |
|
1178 | @only_owned_user = User.generate!(:mail_notification => 'only_owner') | |
1184 | Member.create!(:project => @project, :roles => [@role], :principal => @only_owned_user) |
|
1179 | Member.create!(:project => @project, :roles => [@role], :principal => @only_owned_user) | |
1185 | end |
|
1180 | end | |
1186 |
|
1181 | |||
1187 | should "include members with a mail notification" do |
|
1182 | should "include members with a mail notification" do | |
1188 | assert @project.notified_users.include?(@user_with_membership_notification) |
|
1183 | assert @project.notified_users.include?(@user_with_membership_notification) | |
1189 | end |
|
1184 | end | |
1190 |
|
1185 | |||
1191 | should "include users with the 'all' notification option" do |
|
1186 | should "include users with the 'all' notification option" do | |
1192 | assert @project.notified_users.include?(@all_events_user) |
|
1187 | assert @project.notified_users.include?(@all_events_user) | |
1193 | end |
|
1188 | end | |
1194 |
|
1189 | |||
1195 | should "not include users with the 'none' notification option" do |
|
1190 | should "not include users with the 'none' notification option" do | |
1196 | assert !@project.notified_users.include?(@no_events_user) |
|
1191 | assert !@project.notified_users.include?(@no_events_user) | |
1197 | end |
|
1192 | end | |
1198 |
|
1193 | |||
1199 | should "not include users with the 'only_my_events' notification option" do |
|
1194 | should "not include users with the 'only_my_events' notification option" do | |
1200 | assert !@project.notified_users.include?(@only_my_events_user) |
|
1195 | assert !@project.notified_users.include?(@only_my_events_user) | |
1201 | end |
|
1196 | end | |
1202 |
|
1197 | |||
1203 | should "not include users with the 'only_assigned' notification option" do |
|
1198 | should "not include users with the 'only_assigned' notification option" do | |
1204 | assert !@project.notified_users.include?(@only_assigned_user) |
|
1199 | assert !@project.notified_users.include?(@only_assigned_user) | |
1205 | end |
|
1200 | end | |
1206 |
|
1201 | |||
1207 | should "not include users with the 'only_owner' notification option" do |
|
1202 | should "not include users with the 'only_owner' notification option" do | |
1208 | assert !@project.notified_users.include?(@only_owned_user) |
|
1203 | assert !@project.notified_users.include?(@only_owned_user) | |
1209 | end |
|
1204 | end | |
1210 | end |
|
1205 | end | |
1211 |
|
1206 | |||
1212 | end |
|
1207 | end |
General Comments 0
You need to be logged in to leave comments.
Login now