##// END OF EJS Templates
reset Attachment.storage_path at the end of attachment tests...
Toshi MARUYAMA -
r7791:be29227c12da
parent child
Show More
@@ -1,255 +1,272
1 # encoding: utf-8
1 # encoding: utf-8
2 #
2 #
3 # Redmine - project management software
3 # Redmine - project management software
4 # Copyright (C) 2006-2011 Jean-Philippe Lang
4 # Copyright (C) 2006-2011 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 require 'attachments_controller'
21 require 'attachments_controller'
22
22
23 # Re-raise errors caught by the controller.
23 # Re-raise errors caught by the controller.
24 class AttachmentsController; def rescue_action(e) raise e end; end
24 class AttachmentsController; def rescue_action(e) raise e end; end
25
25
26 class AttachmentsControllerTest < ActionController::TestCase
26 class AttachmentsControllerTest < ActionController::TestCase
27 fixtures :users, :projects, :roles, :members, :member_roles,
27 fixtures :users, :projects, :roles, :members, :member_roles,
28 :enabled_modules, :issues, :trackers, :attachments,
28 :enabled_modules, :issues, :trackers, :attachments,
29 :versions, :wiki_pages, :wikis, :documents
29 :versions, :wiki_pages, :wikis, :documents
30
30
31 def setup
31 def setup
32 @controller = AttachmentsController.new
32 @controller = AttachmentsController.new
33 @request = ActionController::TestRequest.new
33 @request = ActionController::TestRequest.new
34 @response = ActionController::TestResponse.new
34 @response = ActionController::TestResponse.new
35 Attachment.storage_path = "#{Rails.root}/test/fixtures/files"
35 Attachment.storage_path = "#{Rails.root}/test/fixtures/files"
36 User.current = nil
36 User.current = nil
37 end
37 end
38
38
39 def test_show_diff
39 def test_show_diff
40 ['inline', 'sbs'].each do |dt|
40 ['inline', 'sbs'].each do |dt|
41 # 060719210727_changeset_utf8.diff
41 # 060719210727_changeset_utf8.diff
42 get :show, :id => 14, :type => dt
42 get :show, :id => 14, :type => dt
43 assert_response :success
43 assert_response :success
44 assert_template 'diff'
44 assert_template 'diff'
45 assert_equal 'text/html', @response.content_type
45 assert_equal 'text/html', @response.content_type
46 assert_tag 'th',
46 assert_tag 'th',
47 :attributes => {:class => /filename/},
47 :attributes => {:class => /filename/},
48 :content => /issues_controller.rb\t\(rΓ©vision 1484\)/
48 :content => /issues_controller.rb\t\(rΓ©vision 1484\)/
49 assert_tag 'td',
49 assert_tag 'td',
50 :attributes => {:class => /line-code/},
50 :attributes => {:class => /line-code/},
51 :content => /Demande créée avec succès/
51 :content => /Demande créée avec succès/
52 end
52 end
53 set_tmp_attachments_directory
53 end
54 end
54
55
55 def test_show_diff_replcace_cannot_convert_content
56 def test_show_diff_replcace_cannot_convert_content
56 with_settings :repositories_encodings => 'UTF-8' do
57 with_settings :repositories_encodings => 'UTF-8' do
57 ['inline', 'sbs'].each do |dt|
58 ['inline', 'sbs'].each do |dt|
58 # 060719210727_changeset_iso8859-1.diff
59 # 060719210727_changeset_iso8859-1.diff
59 get :show, :id => 5, :type => dt
60 get :show, :id => 5, :type => dt
60 assert_response :success
61 assert_response :success
61 assert_template 'diff'
62 assert_template 'diff'
62 assert_equal 'text/html', @response.content_type
63 assert_equal 'text/html', @response.content_type
63 assert_tag 'th',
64 assert_tag 'th',
64 :attributes => {:class => "filename"},
65 :attributes => {:class => "filename"},
65 :content => /issues_controller.rb\t\(r\?vision 1484\)/
66 :content => /issues_controller.rb\t\(r\?vision 1484\)/
66 assert_tag 'td',
67 assert_tag 'td',
67 :attributes => {:class => /line-code/},
68 :attributes => {:class => /line-code/},
68 :content => /Demande cr\?\?e avec succ\?s/
69 :content => /Demande cr\?\?e avec succ\?s/
69 end
70 end
70 end
71 end
72 set_tmp_attachments_directory
71 end
73 end
72
74
73 def test_show_diff_latin_1
75 def test_show_diff_latin_1
74 with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
76 with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
75 ['inline', 'sbs'].each do |dt|
77 ['inline', 'sbs'].each do |dt|
76 # 060719210727_changeset_iso8859-1.diff
78 # 060719210727_changeset_iso8859-1.diff
77 get :show, :id => 5, :type => dt
79 get :show, :id => 5, :type => dt
78 assert_response :success
80 assert_response :success
79 assert_template 'diff'
81 assert_template 'diff'
80 assert_equal 'text/html', @response.content_type
82 assert_equal 'text/html', @response.content_type
81 assert_tag 'th',
83 assert_tag 'th',
82 :attributes => {:class => "filename"},
84 :attributes => {:class => "filename"},
83 :content => /issues_controller.rb\t\(rΓ©vision 1484\)/
85 :content => /issues_controller.rb\t\(rΓ©vision 1484\)/
84 assert_tag 'td',
86 assert_tag 'td',
85 :attributes => {:class => /line-code/},
87 :attributes => {:class => /line-code/},
86 :content => /Demande créée avec succès/
88 :content => /Demande créée avec succès/
87 end
89 end
88 end
90 end
91 set_tmp_attachments_directory
89 end
92 end
90
93
91 def test_show_text_file
94 def test_show_text_file
92 get :show, :id => 4
95 get :show, :id => 4
93 assert_response :success
96 assert_response :success
94 assert_template 'file'
97 assert_template 'file'
95 assert_equal 'text/html', @response.content_type
98 assert_equal 'text/html', @response.content_type
99 set_tmp_attachments_directory
96 end
100 end
97
101
98 def test_show_text_file_utf_8
102 def test_show_text_file_utf_8
99 set_tmp_attachments_directory
103 set_tmp_attachments_directory
100 a = Attachment.new(:container => Issue.find(1),
104 a = Attachment.new(:container => Issue.find(1),
101 :file => uploaded_test_file("japanese-utf-8.txt", "text/plain"),
105 :file => uploaded_test_file("japanese-utf-8.txt", "text/plain"),
102 :author => User.find(1))
106 :author => User.find(1))
103 assert a.save
107 assert a.save
104 assert_equal 'japanese-utf-8.txt', a.filename
108 assert_equal 'japanese-utf-8.txt', a.filename
105
109
106 str_japanese = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e"
110 str_japanese = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e"
107 str_japanese.force_encoding('UTF-8') if str_japanese.respond_to?(:force_encoding)
111 str_japanese.force_encoding('UTF-8') if str_japanese.respond_to?(:force_encoding)
108
112
109 get :show, :id => a.id
113 get :show, :id => a.id
110 assert_response :success
114 assert_response :success
111 assert_template 'file'
115 assert_template 'file'
112 assert_equal 'text/html', @response.content_type
116 assert_equal 'text/html', @response.content_type
113 assert_tag :tag => 'th',
117 assert_tag :tag => 'th',
114 :content => '1',
118 :content => '1',
115 :attributes => { :class => 'line-num' },
119 :attributes => { :class => 'line-num' },
116 :sibling => { :tag => 'td', :content => /#{str_japanese}/ }
120 :sibling => { :tag => 'td', :content => /#{str_japanese}/ }
117 end
121 end
118
122
119 def test_show_text_file_replcace_cannot_convert_content
123 def test_show_text_file_replcace_cannot_convert_content
120 set_tmp_attachments_directory
124 set_tmp_attachments_directory
121 with_settings :repositories_encodings => 'UTF-8' do
125 with_settings :repositories_encodings => 'UTF-8' do
122 a = Attachment.new(:container => Issue.find(1),
126 a = Attachment.new(:container => Issue.find(1),
123 :file => uploaded_test_file("iso8859-1.txt", "text/plain"),
127 :file => uploaded_test_file("iso8859-1.txt", "text/plain"),
124 :author => User.find(1))
128 :author => User.find(1))
125 assert a.save
129 assert a.save
126 assert_equal 'iso8859-1.txt', a.filename
130 assert_equal 'iso8859-1.txt', a.filename
127
131
128 get :show, :id => a.id
132 get :show, :id => a.id
129 assert_response :success
133 assert_response :success
130 assert_template 'file'
134 assert_template 'file'
131 assert_equal 'text/html', @response.content_type
135 assert_equal 'text/html', @response.content_type
132 assert_tag :tag => 'th',
136 assert_tag :tag => 'th',
133 :content => '7',
137 :content => '7',
134 :attributes => { :class => 'line-num' },
138 :attributes => { :class => 'line-num' },
135 :sibling => { :tag => 'td', :content => /Demande cr\?\?e avec succ\?s/ }
139 :sibling => { :tag => 'td', :content => /Demande cr\?\?e avec succ\?s/ }
136 end
140 end
137 end
141 end
138
142
139 def test_show_text_file_latin_1
143 def test_show_text_file_latin_1
140 set_tmp_attachments_directory
144 set_tmp_attachments_directory
141 with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
145 with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
142 a = Attachment.new(:container => Issue.find(1),
146 a = Attachment.new(:container => Issue.find(1),
143 :file => uploaded_test_file("iso8859-1.txt", "text/plain"),
147 :file => uploaded_test_file("iso8859-1.txt", "text/plain"),
144 :author => User.find(1))
148 :author => User.find(1))
145 assert a.save
149 assert a.save
146 assert_equal 'iso8859-1.txt', a.filename
150 assert_equal 'iso8859-1.txt', a.filename
147
151
148 get :show, :id => a.id
152 get :show, :id => a.id
149 assert_response :success
153 assert_response :success
150 assert_template 'file'
154 assert_template 'file'
151 assert_equal 'text/html', @response.content_type
155 assert_equal 'text/html', @response.content_type
152 assert_tag :tag => 'th',
156 assert_tag :tag => 'th',
153 :content => '7',
157 :content => '7',
154 :attributes => { :class => 'line-num' },
158 :attributes => { :class => 'line-num' },
155 :sibling => { :tag => 'td', :content => /Demande créée avec succès/ }
159 :sibling => { :tag => 'td', :content => /Demande créée avec succès/ }
156 end
160 end
157 end
161 end
158
162
159 def test_show_text_file_should_send_if_too_big
163 def test_show_text_file_should_send_if_too_big
160 Setting.file_max_size_displayed = 512
164 Setting.file_max_size_displayed = 512
161 Attachment.find(4).update_attribute :filesize, 754.kilobyte
165 Attachment.find(4).update_attribute :filesize, 754.kilobyte
162
166
163 get :show, :id => 4
167 get :show, :id => 4
164 assert_response :success
168 assert_response :success
165 assert_equal 'application/x-ruby', @response.content_type
169 assert_equal 'application/x-ruby', @response.content_type
170 set_tmp_attachments_directory
166 end
171 end
167
172
168 def test_show_other
173 def test_show_other
169 get :show, :id => 6
174 get :show, :id => 6
170 assert_response :success
175 assert_response :success
171 assert_equal 'application/octet-stream', @response.content_type
176 assert_equal 'application/octet-stream', @response.content_type
177 set_tmp_attachments_directory
172 end
178 end
173
179
174 def test_show_file_from_private_issue_without_permission
180 def test_show_file_from_private_issue_without_permission
175 get :show, :id => 15
181 get :show, :id => 15
176 assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Fattachments%2F15'
182 assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Fattachments%2F15'
183 set_tmp_attachments_directory
177 end
184 end
178
185
179 def test_show_file_from_private_issue_with_permission
186 def test_show_file_from_private_issue_with_permission
180 @request.session[:user_id] = 2
187 @request.session[:user_id] = 2
181 get :show, :id => 15
188 get :show, :id => 15
182 assert_response :success
189 assert_response :success
183 assert_tag 'h2', :content => /private.diff/
190 assert_tag 'h2', :content => /private.diff/
191 set_tmp_attachments_directory
184 end
192 end
185
193
186 def test_download_text_file
194 def test_download_text_file
187 get :download, :id => 4
195 get :download, :id => 4
188 assert_response :success
196 assert_response :success
189 assert_equal 'application/x-ruby', @response.content_type
197 assert_equal 'application/x-ruby', @response.content_type
198 set_tmp_attachments_directory
190 end
199 end
191
200
192 def test_download_should_assign_content_type_if_blank
201 def test_download_should_assign_content_type_if_blank
193 Attachment.find(4).update_attribute(:content_type, '')
202 Attachment.find(4).update_attribute(:content_type, '')
194
203
195 get :download, :id => 4
204 get :download, :id => 4
196 assert_response :success
205 assert_response :success
197 assert_equal 'text/x-ruby', @response.content_type
206 assert_equal 'text/x-ruby', @response.content_type
207 set_tmp_attachments_directory
198 end
208 end
199
209
200 def test_download_missing_file
210 def test_download_missing_file
201 get :download, :id => 2
211 get :download, :id => 2
202 assert_response 404
212 assert_response 404
213 set_tmp_attachments_directory
203 end
214 end
204
215
205 def test_anonymous_on_private_private
216 def test_anonymous_on_private_private
206 get :download, :id => 7
217 get :download, :id => 7
207 assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Fattachments%2Fdownload%2F7'
218 assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Fattachments%2Fdownload%2F7'
219 set_tmp_attachments_directory
208 end
220 end
209
221
210 def test_destroy_issue_attachment
222 def test_destroy_issue_attachment
211 issue = Issue.find(3)
223 issue = Issue.find(3)
212 @request.session[:user_id] = 2
224 @request.session[:user_id] = 2
213
225
214 assert_difference 'issue.attachments.count', -1 do
226 assert_difference 'issue.attachments.count', -1 do
215 post :destroy, :id => 1
227 post :destroy, :id => 1
216 end
228 end
217 # no referrer
229 # no referrer
218 assert_redirected_to '/projects/ecookbook'
230 assert_redirected_to '/projects/ecookbook'
219 assert_nil Attachment.find_by_id(1)
231 assert_nil Attachment.find_by_id(1)
220 j = issue.journals.find(:first, :order => 'created_on DESC')
232 j = issue.journals.find(:first, :order => 'created_on DESC')
221 assert_equal 'attachment', j.details.first.property
233 assert_equal 'attachment', j.details.first.property
222 assert_equal '1', j.details.first.prop_key
234 assert_equal '1', j.details.first.prop_key
223 assert_equal 'error281.txt', j.details.first.old_value
235 assert_equal 'error281.txt', j.details.first.old_value
236 set_tmp_attachments_directory
224 end
237 end
225
238
226 def test_destroy_wiki_page_attachment
239 def test_destroy_wiki_page_attachment
227 @request.session[:user_id] = 2
240 @request.session[:user_id] = 2
228 assert_difference 'Attachment.count', -1 do
241 assert_difference 'Attachment.count', -1 do
229 post :destroy, :id => 3
242 post :destroy, :id => 3
230 assert_response 302
243 assert_response 302
231 end
244 end
245 set_tmp_attachments_directory
232 end
246 end
233
247
234 def test_destroy_project_attachment
248 def test_destroy_project_attachment
235 @request.session[:user_id] = 2
249 @request.session[:user_id] = 2
236 assert_difference 'Attachment.count', -1 do
250 assert_difference 'Attachment.count', -1 do
237 post :destroy, :id => 8
251 post :destroy, :id => 8
238 assert_response 302
252 assert_response 302
239 end
253 end
254 set_tmp_attachments_directory
240 end
255 end
241
256
242 def test_destroy_version_attachment
257 def test_destroy_version_attachment
243 @request.session[:user_id] = 2
258 @request.session[:user_id] = 2
244 assert_difference 'Attachment.count', -1 do
259 assert_difference 'Attachment.count', -1 do
245 post :destroy, :id => 9
260 post :destroy, :id => 9
246 assert_response 302
261 assert_response 302
247 end
262 end
263 set_tmp_attachments_directory
248 end
264 end
249
265
250 def test_destroy_without_permission
266 def test_destroy_without_permission
251 post :destroy, :id => 3
267 post :destroy, :id => 3
252 assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Fattachments%2Fdestroy%2F3'
268 assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Fattachments%2Fdestroy%2F3'
253 assert Attachment.find_by_id(3)
269 assert Attachment.find_by_id(3)
270 set_tmp_attachments_directory
254 end
271 end
255 end
272 end
@@ -1,86 +1,86
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class ApiTest::AttachmentsTest < ActionController::IntegrationTest
20 class ApiTest::AttachmentsTest < ActionController::IntegrationTest
21 fixtures :projects, :trackers, :issue_statuses, :issues,
21 fixtures :projects, :trackers, :issue_statuses, :issues,
22 :enumerations, :users, :issue_categories,
22 :enumerations, :users, :issue_categories,
23 :projects_trackers,
23 :projects_trackers,
24 :roles,
24 :roles,
25 :member_roles,
25 :member_roles,
26 :members,
26 :members,
27 :enabled_modules,
27 :enabled_modules,
28 :workflows,
28 :workflows,
29 :attachments
29 :attachments
30
30
31 def setup
31 def setup
32 Setting.rest_api_enabled = '1'
32 Setting.rest_api_enabled = '1'
33 Attachment.storage_path = "#{Rails.root}/test/fixtures/files"
33 Attachment.storage_path = "#{Rails.root}/test/fixtures/files"
34 end
34 end
35
35
36 context "/attachments/:id" do
36 context "/attachments/:id" do
37 context "GET" do
37 context "GET" do
38 should "return the attachment" do
38 should "return the attachment" do
39 get '/attachments/7.xml', {}, :authorization => credentials('jsmith')
39 get '/attachments/7.xml', {}, :authorization => credentials('jsmith')
40
41 assert_response :success
40 assert_response :success
42 assert_equal 'application/xml', @response.content_type
41 assert_equal 'application/xml', @response.content_type
43 assert_tag :tag => 'attachment',
42 assert_tag :tag => 'attachment',
44 :child => {
43 :child => {
45 :tag => 'id',
44 :tag => 'id',
46 :content => '7',
45 :content => '7',
47 :sibling => {
46 :sibling => {
48 :tag => 'filename',
47 :tag => 'filename',
49 :content => 'archive.zip',
48 :content => 'archive.zip',
50 :sibling => {
49 :sibling => {
51 :tag => 'content_url',
50 :tag => 'content_url',
52 :content => 'http://www.example.com/attachments/download/7/archive.zip'
51 :content => 'http://www.example.com/attachments/download/7/archive.zip'
53 }
52 }
54 }
53 }
55 }
54 }
56 end
55 end
57
56
58 should "deny access without credentials" do
57 should "deny access without credentials" do
59 get '/attachments/7.xml'
58 get '/attachments/7.xml'
60
61 assert_response 401
59 assert_response 401
60 set_tmp_attachments_directory
62 end
61 end
63 end
62 end
64 end
63 end
65
64
66 context "/attachments/download/:id/:filename" do
65 context "/attachments/download/:id/:filename" do
67 context "GET" do
66 context "GET" do
68 should "return the attachment content" do
67 should "return the attachment content" do
69 get '/attachments/download/7/archive.zip', {}, :authorization => credentials('jsmith')
68 get '/attachments/download/7/archive.zip',
70
69 {}, :authorization => credentials('jsmith')
71 assert_response :success
70 assert_response :success
72 assert_equal 'application/octet-stream', @response.content_type
71 assert_equal 'application/octet-stream', @response.content_type
72 set_tmp_attachments_directory
73 end
73 end
74
74
75 should "deny access without credentials" do
75 should "deny access without credentials" do
76 get '/attachments/download/7/archive.zip'
76 get '/attachments/download/7/archive.zip'
77
78 assert_response 302
77 assert_response 302
78 set_tmp_attachments_directory
79 end
79 end
80 end
80 end
81 end
81 end
82
82
83 def credentials(user, password=nil)
83 def credentials(user, password=nil)
84 ActionController::HttpAuthentication::Basic.encode_credentials(user, password || user)
84 ActionController::HttpAuthentication::Basic.encode_credentials(user, password || user)
85 end
85 end
86 end
86 end
@@ -1,145 +1,147
1 # encoding: utf-8
1 # encoding: utf-8
2 #
2 #
3 # Redmine - project management software
3 # Redmine - project management software
4 # Copyright (C) 2006-2011 Jean-Philippe Lang
4 # Copyright (C) 2006-2011 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 def setup
26 def setup
27 set_tmp_attachments_directory
27 set_tmp_attachments_directory
28 end
28 end
29
29
30 def test_create
30 def test_create
31 a = Attachment.new(:container => Issue.find(1),
31 a = Attachment.new(:container => Issue.find(1),
32 :file => uploaded_test_file("testfile.txt", "text/plain"),
32 :file => uploaded_test_file("testfile.txt", "text/plain"),
33 :author => User.find(1))
33 :author => User.find(1))
34 assert a.save
34 assert a.save
35 assert_equal 'testfile.txt', a.filename
35 assert_equal 'testfile.txt', a.filename
36 assert_equal 59, a.filesize
36 assert_equal 59, a.filesize
37 assert_equal 'text/plain', a.content_type
37 assert_equal 'text/plain', a.content_type
38 assert_equal 0, a.downloads
38 assert_equal 0, a.downloads
39 assert_equal '1478adae0d4eb06d35897518540e25d6', a.digest
39 assert_equal '1478adae0d4eb06d35897518540e25d6', a.digest
40 assert File.exist?(a.diskfile)
40 assert File.exist?(a.diskfile)
41 assert_equal 59, File.size(a.diskfile)
41 assert_equal 59, File.size(a.diskfile)
42 end
42 end
43
43
44 def test_destroy
44 def test_destroy
45 a = Attachment.new(:container => Issue.find(1),
45 a = Attachment.new(:container => Issue.find(1),
46 :file => uploaded_test_file("testfile.txt", "text/plain"),
46 :file => uploaded_test_file("testfile.txt", "text/plain"),
47 :author => User.find(1))
47 :author => User.find(1))
48 assert a.save
48 assert a.save
49 assert_equal 'testfile.txt', a.filename
49 assert_equal 'testfile.txt', a.filename
50 assert_equal 59, a.filesize
50 assert_equal 59, a.filesize
51 assert_equal 'text/plain', a.content_type
51 assert_equal 'text/plain', a.content_type
52 assert_equal 0, a.downloads
52 assert_equal 0, a.downloads
53 assert_equal '1478adae0d4eb06d35897518540e25d6', a.digest
53 assert_equal '1478adae0d4eb06d35897518540e25d6', a.digest
54 diskfile = a.diskfile
54 diskfile = a.diskfile
55 assert File.exist?(diskfile)
55 assert File.exist?(diskfile)
56 assert_equal 59, File.size(a.diskfile)
56 assert_equal 59, File.size(a.diskfile)
57 assert a.destroy
57 assert a.destroy
58 assert !File.exist?(diskfile)
58 assert !File.exist?(diskfile)
59 end
59 end
60
60
61 def test_create_should_auto_assign_content_type
61 def test_create_should_auto_assign_content_type
62 a = Attachment.new(:container => Issue.find(1),
62 a = Attachment.new(:container => Issue.find(1),
63 :file => uploaded_test_file("testfile.txt", ""),
63 :file => uploaded_test_file("testfile.txt", ""),
64 :author => User.find(1))
64 :author => User.find(1))
65 assert a.save
65 assert a.save
66 assert_equal 'text/plain', a.content_type
66 assert_equal 'text/plain', a.content_type
67 end
67 end
68
68
69 def test_identical_attachments_at_the_same_time_should_not_overwrite
69 def test_identical_attachments_at_the_same_time_should_not_overwrite
70 a1 = Attachment.create!(:container => Issue.find(1),
70 a1 = Attachment.create!(:container => Issue.find(1),
71 :file => uploaded_test_file("testfile.txt", ""),
71 :file => uploaded_test_file("testfile.txt", ""),
72 :author => User.find(1))
72 :author => User.find(1))
73 a2 = Attachment.create!(:container => Issue.find(1),
73 a2 = Attachment.create!(:container => Issue.find(1),
74 :file => uploaded_test_file("testfile.txt", ""),
74 :file => uploaded_test_file("testfile.txt", ""),
75 :author => User.find(1))
75 :author => User.find(1))
76 assert a1.disk_filename != a2.disk_filename
76 assert a1.disk_filename != a2.disk_filename
77 end
77 end
78
78
79 def test_diskfilename
79 def test_diskfilename
80 assert Attachment.disk_filename("test_file.txt") =~ /^\d{12}_test_file.txt$/
80 assert Attachment.disk_filename("test_file.txt") =~ /^\d{12}_test_file.txt$/
81 assert_equal 'test_file.txt', Attachment.disk_filename("test_file.txt")[13..-1]
81 assert_equal 'test_file.txt', Attachment.disk_filename("test_file.txt")[13..-1]
82 assert_equal '770c509475505f37c2b8fb6030434d6b.txt', Attachment.disk_filename("test_accentuΓ©.txt")[13..-1]
82 assert_equal '770c509475505f37c2b8fb6030434d6b.txt', Attachment.disk_filename("test_accentuΓ©.txt")[13..-1]
83 assert_equal 'f8139524ebb8f32e51976982cd20a85d', Attachment.disk_filename("test_accentuΓ©")[13..-1]
83 assert_equal 'f8139524ebb8f32e51976982cd20a85d', Attachment.disk_filename("test_accentuΓ©")[13..-1]
84 assert_equal 'cbb5b0f30978ba03731d61f9f6d10011', Attachment.disk_filename("test_accentuΓ©.Γ§a")[13..-1]
84 assert_equal 'cbb5b0f30978ba03731d61f9f6d10011', Attachment.disk_filename("test_accentuΓ©.Γ§a")[13..-1]
85 end
85 end
86
86
87 context "Attachmnet.attach_files" do
87 context "Attachmnet.attach_files" do
88 should "attach the file" do
88 should "attach the file" do
89 issue = Issue.first
89 issue = Issue.first
90 assert_difference 'Attachment.count' do
90 assert_difference 'Attachment.count' do
91 Attachment.attach_files(issue,
91 Attachment.attach_files(issue,
92 '1' => {
92 '1' => {
93 'file' => uploaded_test_file('testfile.txt', 'text/plain'),
93 'file' => uploaded_test_file('testfile.txt', 'text/plain'),
94 'description' => 'test'
94 'description' => 'test'
95 })
95 })
96 end
96 end
97
97
98 attachment = Attachment.first(:order => 'id DESC')
98 attachment = Attachment.first(:order => 'id DESC')
99 assert_equal issue, attachment.container
99 assert_equal issue, attachment.container
100 assert_equal 'testfile.txt', attachment.filename
100 assert_equal 'testfile.txt', attachment.filename
101 assert_equal 59, attachment.filesize
101 assert_equal 59, attachment.filesize
102 assert_equal 'test', attachment.description
102 assert_equal 'test', attachment.description
103 assert_equal 'text/plain', attachment.content_type
103 assert_equal 'text/plain', attachment.content_type
104 assert File.exists?(attachment.diskfile)
104 assert File.exists?(attachment.diskfile)
105 assert_equal 59, File.size(attachment.diskfile)
105 assert_equal 59, File.size(attachment.diskfile)
106 end
106 end
107
107
108 should "add unsaved files to the object as unsaved attachments" do
108 should "add unsaved files to the object as unsaved attachments" do
109 # Max size of 0 to force Attachment creation failures
109 # Max size of 0 to force Attachment creation failures
110 with_settings(:attachment_max_size => 0) do
110 with_settings(:attachment_max_size => 0) do
111 @project = Project.generate!
111 @project = Project.generate!
112 response = Attachment.attach_files(@project, {
112 response = Attachment.attach_files(@project, {
113 '1' => {'file' => mock_file, 'description' => 'test'},
113 '1' => {'file' => mock_file, 'description' => 'test'},
114 '2' => {'file' => mock_file, 'description' => 'test'}
114 '2' => {'file' => mock_file, 'description' => 'test'}
115 })
115 })
116
116
117 assert response[:unsaved].present?
117 assert response[:unsaved].present?
118 assert_equal 2, response[:unsaved].length
118 assert_equal 2, response[:unsaved].length
119 assert response[:unsaved].first.new_record?
119 assert response[:unsaved].first.new_record?
120 assert response[:unsaved].second.new_record?
120 assert response[:unsaved].second.new_record?
121 assert_equal response[:unsaved], @project.unsaved_attachments
121 assert_equal response[:unsaved], @project.unsaved_attachments
122 end
122 end
123 end
123 end
124 end
124 end
125
125
126 def test_latest_attach
126 def test_latest_attach
127 Attachment.storage_path = "#{Rails.root}/test/fixtures/files"
127 Attachment.storage_path = "#{Rails.root}/test/fixtures/files"
128 a1 = Attachment.find(16)
128 a1 = Attachment.find(16)
129 assert_equal "testfile.png", a1.filename
129 assert_equal "testfile.png", a1.filename
130 assert a1.readable?
130 assert a1.readable?
131 assert (! a1.visible?(User.anonymous))
131 assert (! a1.visible?(User.anonymous))
132 assert a1.visible?(User.find(2))
132 assert a1.visible?(User.find(2))
133 a2 = Attachment.find(17)
133 a2 = Attachment.find(17)
134 assert_equal "testfile.PNG", a2.filename
134 assert_equal "testfile.PNG", a2.filename
135 assert a2.readable?
135 assert a2.readable?
136 assert (! a2.visible?(User.anonymous))
136 assert (! a2.visible?(User.anonymous))
137 assert a2.visible?(User.find(2))
137 assert a2.visible?(User.find(2))
138 assert a1.created_on < a2.created_on
138 assert a1.created_on < a2.created_on
139
139
140 la1 = Attachment.latest_attach([a1, a2], "testfile.png")
140 la1 = Attachment.latest_attach([a1, a2], "testfile.png")
141 assert_equal 17, la1.id
141 assert_equal 17, la1.id
142 la2 = Attachment.latest_attach([a1, a2], "Testfile.PNG")
142 la2 = Attachment.latest_attach([a1, a2], "Testfile.PNG")
143 assert_equal 17, la2.id
143 assert_equal 17, la2.id
144
145 set_tmp_attachments_directory
144 end
146 end
145 end
147 end
@@ -1,877 +1,878
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class ApplicationHelperTest < ActionView::TestCase
20 class ApplicationHelperTest < ActionView::TestCase
21 fixtures :projects, :roles, :enabled_modules, :users,
21 fixtures :projects, :roles, :enabled_modules, :users,
22 :repositories, :changesets,
22 :repositories, :changesets,
23 :trackers, :issue_statuses, :issues, :versions, :documents,
23 :trackers, :issue_statuses, :issues, :versions, :documents,
24 :wikis, :wiki_pages, :wiki_contents,
24 :wikis, :wiki_pages, :wiki_contents,
25 :boards, :messages, :news,
25 :boards, :messages, :news,
26 :attachments, :enumerations
26 :attachments, :enumerations
27
27
28 def setup
28 def setup
29 super
29 super
30 set_tmp_attachments_directory
30 set_tmp_attachments_directory
31 end
31 end
32
32
33 context "#link_to_if_authorized" do
33 context "#link_to_if_authorized" do
34 context "authorized user" do
34 context "authorized user" do
35 should "be tested"
35 should "be tested"
36 end
36 end
37
37
38 context "unauthorized user" do
38 context "unauthorized user" do
39 should "be tested"
39 should "be tested"
40 end
40 end
41
41
42 should "allow using the :controller and :action for the target link" do
42 should "allow using the :controller and :action for the target link" do
43 User.current = User.find_by_login('admin')
43 User.current = User.find_by_login('admin')
44
44
45 @project = Issue.first.project # Used by helper
45 @project = Issue.first.project # Used by helper
46 response = link_to_if_authorized("By controller/action",
46 response = link_to_if_authorized("By controller/action",
47 {:controller => 'issues', :action => 'edit', :id => Issue.first.id})
47 {:controller => 'issues', :action => 'edit', :id => Issue.first.id})
48 assert_match /href/, response
48 assert_match /href/, response
49 end
49 end
50
50
51 end
51 end
52
52
53 def test_auto_links
53 def test_auto_links
54 to_test = {
54 to_test = {
55 'http://foo.bar' => '<a class="external" href="http://foo.bar">http://foo.bar</a>',
55 'http://foo.bar' => '<a class="external" href="http://foo.bar">http://foo.bar</a>',
56 'http://foo.bar/~user' => '<a class="external" href="http://foo.bar/~user">http://foo.bar/~user</a>',
56 'http://foo.bar/~user' => '<a class="external" href="http://foo.bar/~user">http://foo.bar/~user</a>',
57 'http://foo.bar.' => '<a class="external" href="http://foo.bar">http://foo.bar</a>.',
57 'http://foo.bar.' => '<a class="external" href="http://foo.bar">http://foo.bar</a>.',
58 'https://foo.bar.' => '<a class="external" href="https://foo.bar">https://foo.bar</a>.',
58 'https://foo.bar.' => '<a class="external" href="https://foo.bar">https://foo.bar</a>.',
59 'This is a link: http://foo.bar.' => 'This is a link: <a class="external" href="http://foo.bar">http://foo.bar</a>.',
59 'This is a link: http://foo.bar.' => 'This is a link: <a class="external" href="http://foo.bar">http://foo.bar</a>.',
60 'A link (eg. http://foo.bar).' => 'A link (eg. <a class="external" href="http://foo.bar">http://foo.bar</a>).',
60 'A link (eg. http://foo.bar).' => 'A link (eg. <a class="external" href="http://foo.bar">http://foo.bar</a>).',
61 'http://foo.bar/foo.bar#foo.bar.' => '<a class="external" href="http://foo.bar/foo.bar#foo.bar">http://foo.bar/foo.bar#foo.bar</a>.',
61 'http://foo.bar/foo.bar#foo.bar.' => '<a class="external" href="http://foo.bar/foo.bar#foo.bar">http://foo.bar/foo.bar#foo.bar</a>.',
62 'http://www.foo.bar/Test_(foobar)' => '<a class="external" href="http://www.foo.bar/Test_(foobar)">http://www.foo.bar/Test_(foobar)</a>',
62 'http://www.foo.bar/Test_(foobar)' => '<a class="external" href="http://www.foo.bar/Test_(foobar)">http://www.foo.bar/Test_(foobar)</a>',
63 '(see inline link : http://www.foo.bar/Test_(foobar))' => '(see inline link : <a class="external" href="http://www.foo.bar/Test_(foobar)">http://www.foo.bar/Test_(foobar)</a>)',
63 '(see inline link : http://www.foo.bar/Test_(foobar))' => '(see inline link : <a class="external" href="http://www.foo.bar/Test_(foobar)">http://www.foo.bar/Test_(foobar)</a>)',
64 '(see inline link : http://www.foo.bar/Test)' => '(see inline link : <a class="external" href="http://www.foo.bar/Test">http://www.foo.bar/Test</a>)',
64 '(see inline link : http://www.foo.bar/Test)' => '(see inline link : <a class="external" href="http://www.foo.bar/Test">http://www.foo.bar/Test</a>)',
65 '(see inline link : http://www.foo.bar/Test).' => '(see inline link : <a class="external" href="http://www.foo.bar/Test">http://www.foo.bar/Test</a>).',
65 '(see inline link : http://www.foo.bar/Test).' => '(see inline link : <a class="external" href="http://www.foo.bar/Test">http://www.foo.bar/Test</a>).',
66 '(see "inline link":http://www.foo.bar/Test_(foobar))' => '(see <a href="http://www.foo.bar/Test_(foobar)" class="external">inline link</a>)',
66 '(see "inline link":http://www.foo.bar/Test_(foobar))' => '(see <a href="http://www.foo.bar/Test_(foobar)" class="external">inline link</a>)',
67 '(see "inline link":http://www.foo.bar/Test)' => '(see <a href="http://www.foo.bar/Test" class="external">inline link</a>)',
67 '(see "inline link":http://www.foo.bar/Test)' => '(see <a href="http://www.foo.bar/Test" class="external">inline link</a>)',
68 '(see "inline link":http://www.foo.bar/Test).' => '(see <a href="http://www.foo.bar/Test" class="external">inline link</a>).',
68 '(see "inline link":http://www.foo.bar/Test).' => '(see <a href="http://www.foo.bar/Test" class="external">inline link</a>).',
69 'www.foo.bar' => '<a class="external" href="http://www.foo.bar">www.foo.bar</a>',
69 'www.foo.bar' => '<a class="external" href="http://www.foo.bar">www.foo.bar</a>',
70 'http://foo.bar/page?p=1&t=z&s=' => '<a class="external" href="http://foo.bar/page?p=1&#38;t=z&#38;s=">http://foo.bar/page?p=1&#38;t=z&#38;s=</a>',
70 'http://foo.bar/page?p=1&t=z&s=' => '<a class="external" href="http://foo.bar/page?p=1&#38;t=z&#38;s=">http://foo.bar/page?p=1&#38;t=z&#38;s=</a>',
71 'http://foo.bar/page#125' => '<a class="external" href="http://foo.bar/page#125">http://foo.bar/page#125</a>',
71 'http://foo.bar/page#125' => '<a class="external" href="http://foo.bar/page#125">http://foo.bar/page#125</a>',
72 'http://foo@www.bar.com' => '<a class="external" href="http://foo@www.bar.com">http://foo@www.bar.com</a>',
72 'http://foo@www.bar.com' => '<a class="external" href="http://foo@www.bar.com">http://foo@www.bar.com</a>',
73 'http://foo:bar@www.bar.com' => '<a class="external" href="http://foo:bar@www.bar.com">http://foo:bar@www.bar.com</a>',
73 'http://foo:bar@www.bar.com' => '<a class="external" href="http://foo:bar@www.bar.com">http://foo:bar@www.bar.com</a>',
74 'ftp://foo.bar' => '<a class="external" href="ftp://foo.bar">ftp://foo.bar</a>',
74 'ftp://foo.bar' => '<a class="external" href="ftp://foo.bar">ftp://foo.bar</a>',
75 'ftps://foo.bar' => '<a class="external" href="ftps://foo.bar">ftps://foo.bar</a>',
75 'ftps://foo.bar' => '<a class="external" href="ftps://foo.bar">ftps://foo.bar</a>',
76 'sftp://foo.bar' => '<a class="external" href="sftp://foo.bar">sftp://foo.bar</a>',
76 'sftp://foo.bar' => '<a class="external" href="sftp://foo.bar">sftp://foo.bar</a>',
77 # two exclamation marks
77 # two exclamation marks
78 'http://example.net/path!602815048C7B5C20!302.html' => '<a class="external" href="http://example.net/path!602815048C7B5C20!302.html">http://example.net/path!602815048C7B5C20!302.html</a>',
78 'http://example.net/path!602815048C7B5C20!302.html' => '<a class="external" href="http://example.net/path!602815048C7B5C20!302.html">http://example.net/path!602815048C7B5C20!302.html</a>',
79 # escaping
79 # escaping
80 'http://foo"bar' => '<a class="external" href="http://foo&quot;bar">http://foo"bar</a>',
80 'http://foo"bar' => '<a class="external" href="http://foo&quot;bar">http://foo"bar</a>',
81 # wrap in angle brackets
81 # wrap in angle brackets
82 '<http://foo.bar>' => '&lt;<a class="external" href="http://foo.bar">http://foo.bar</a>&gt;'
82 '<http://foo.bar>' => '&lt;<a class="external" href="http://foo.bar">http://foo.bar</a>&gt;'
83 }
83 }
84 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
84 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
85 end
85 end
86
86
87 def test_auto_mailto
87 def test_auto_mailto
88 assert_equal '<p><a class="email" href="mailto:test@foo.bar">test@foo.bar</a></p>',
88 assert_equal '<p><a class="email" href="mailto:test@foo.bar">test@foo.bar</a></p>',
89 textilizable('test@foo.bar')
89 textilizable('test@foo.bar')
90 end
90 end
91
91
92 def test_inline_images
92 def test_inline_images
93 to_test = {
93 to_test = {
94 '!http://foo.bar/image.jpg!' => '<img src="http://foo.bar/image.jpg" alt="" />',
94 '!http://foo.bar/image.jpg!' => '<img src="http://foo.bar/image.jpg" alt="" />',
95 'floating !>http://foo.bar/image.jpg!' => 'floating <div style="float:right"><img src="http://foo.bar/image.jpg" alt="" /></div>',
95 'floating !>http://foo.bar/image.jpg!' => 'floating <div style="float:right"><img src="http://foo.bar/image.jpg" alt="" /></div>',
96 'with class !(some-class)http://foo.bar/image.jpg!' => 'with class <img src="http://foo.bar/image.jpg" class="some-class" alt="" />',
96 'with class !(some-class)http://foo.bar/image.jpg!' => 'with class <img src="http://foo.bar/image.jpg" class="some-class" alt="" />',
97 # inline styles should be stripped
97 # inline styles should be stripped
98 'with style !{width:100px;height100px}http://foo.bar/image.jpg!' => 'with style <img src="http://foo.bar/image.jpg" alt="" />',
98 'with style !{width:100px;height100px}http://foo.bar/image.jpg!' => 'with style <img src="http://foo.bar/image.jpg" alt="" />',
99 'with title !http://foo.bar/image.jpg(This is a title)!' => 'with title <img src="http://foo.bar/image.jpg" title="This is a title" alt="This is a title" />',
99 'with title !http://foo.bar/image.jpg(This is a title)!' => 'with title <img src="http://foo.bar/image.jpg" title="This is a title" alt="This is a title" />',
100 'with title !http://foo.bar/image.jpg(This is a double-quoted "title")!' => 'with title <img src="http://foo.bar/image.jpg" title="This is a double-quoted &quot;title&quot;" alt="This is a double-quoted &quot;title&quot;" />',
100 'with title !http://foo.bar/image.jpg(This is a double-quoted "title")!' => 'with title <img src="http://foo.bar/image.jpg" title="This is a double-quoted &quot;title&quot;" alt="This is a double-quoted &quot;title&quot;" />',
101 }
101 }
102 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
102 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
103 end
103 end
104
104
105 def test_inline_images_inside_tags
105 def test_inline_images_inside_tags
106 raw = <<-RAW
106 raw = <<-RAW
107 h1. !foo.png! Heading
107 h1. !foo.png! Heading
108
108
109 Centered image:
109 Centered image:
110
110
111 p=. !bar.gif!
111 p=. !bar.gif!
112 RAW
112 RAW
113
113
114 assert textilizable(raw).include?('<img src="foo.png" alt="" />')
114 assert textilizable(raw).include?('<img src="foo.png" alt="" />')
115 assert textilizable(raw).include?('<img src="bar.gif" alt="" />')
115 assert textilizable(raw).include?('<img src="bar.gif" alt="" />')
116 end
116 end
117
117
118 def test_attached_images
118 def test_attached_images
119 to_test = {
119 to_test = {
120 'Inline image: !logo.gif!' => 'Inline image: <img src="/attachments/download/3" title="This is a logo" alt="This is a logo" />',
120 'Inline image: !logo.gif!' => 'Inline image: <img src="/attachments/download/3" title="This is a logo" alt="This is a logo" />',
121 'Inline image: !logo.GIF!' => 'Inline image: <img src="/attachments/download/3" title="This is a logo" alt="This is a logo" />',
121 'Inline image: !logo.GIF!' => 'Inline image: <img src="/attachments/download/3" title="This is a logo" alt="This is a logo" />',
122 'No match: !ogo.gif!' => 'No match: <img src="ogo.gif" alt="" />',
122 'No match: !ogo.gif!' => 'No match: <img src="ogo.gif" alt="" />',
123 'No match: !ogo.GIF!' => 'No match: <img src="ogo.GIF" alt="" />',
123 'No match: !ogo.GIF!' => 'No match: <img src="ogo.GIF" alt="" />',
124 # link image
124 # link image
125 '!logo.gif!:http://foo.bar/' => '<a href="http://foo.bar/"><img src="/attachments/download/3" title="This is a logo" alt="This is a logo" /></a>',
125 '!logo.gif!:http://foo.bar/' => '<a href="http://foo.bar/"><img src="/attachments/download/3" title="This is a logo" alt="This is a logo" /></a>',
126 }
126 }
127 attachments = Attachment.find(:all)
127 attachments = Attachment.find(:all)
128 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text, :attachments => attachments) }
128 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text, :attachments => attachments) }
129 end
129 end
130
130
131 def test_attached_images_filename_extension
131 def test_attached_images_filename_extension
132 set_tmp_attachments_directory
132 set_tmp_attachments_directory
133 a1 = Attachment.new(
133 a1 = Attachment.new(
134 :container => Issue.find(1),
134 :container => Issue.find(1),
135 :file => mock_file_with_options({:original_filename => "testtest.JPG"}),
135 :file => mock_file_with_options({:original_filename => "testtest.JPG"}),
136 :author => User.find(1))
136 :author => User.find(1))
137 assert a1.save
137 assert a1.save
138 assert_equal "testtest.JPG", a1.filename
138 assert_equal "testtest.JPG", a1.filename
139 assert_equal "image/jpeg", a1.content_type
139 assert_equal "image/jpeg", a1.content_type
140 assert a1.image?
140 assert a1.image?
141
141
142 a2 = Attachment.new(
142 a2 = Attachment.new(
143 :container => Issue.find(1),
143 :container => Issue.find(1),
144 :file => mock_file_with_options({:original_filename => "testtest.jpeg"}),
144 :file => mock_file_with_options({:original_filename => "testtest.jpeg"}),
145 :author => User.find(1))
145 :author => User.find(1))
146 assert a2.save
146 assert a2.save
147 assert_equal "testtest.jpeg", a2.filename
147 assert_equal "testtest.jpeg", a2.filename
148 assert_equal "image/jpeg", a2.content_type
148 assert_equal "image/jpeg", a2.content_type
149 assert a2.image?
149 assert a2.image?
150
150
151 a3 = Attachment.new(
151 a3 = Attachment.new(
152 :container => Issue.find(1),
152 :container => Issue.find(1),
153 :file => mock_file_with_options({:original_filename => "testtest.JPE"}),
153 :file => mock_file_with_options({:original_filename => "testtest.JPE"}),
154 :author => User.find(1))
154 :author => User.find(1))
155 assert a3.save
155 assert a3.save
156 assert_equal "testtest.JPE", a3.filename
156 assert_equal "testtest.JPE", a3.filename
157 assert_equal "image/jpeg", a3.content_type
157 assert_equal "image/jpeg", a3.content_type
158 assert a3.image?
158 assert a3.image?
159
159
160 a4 = Attachment.new(
160 a4 = Attachment.new(
161 :container => Issue.find(1),
161 :container => Issue.find(1),
162 :file => mock_file_with_options({:original_filename => "Testtest.BMP"}),
162 :file => mock_file_with_options({:original_filename => "Testtest.BMP"}),
163 :author => User.find(1))
163 :author => User.find(1))
164 assert a4.save
164 assert a4.save
165 assert_equal "Testtest.BMP", a4.filename
165 assert_equal "Testtest.BMP", a4.filename
166 assert_equal "image/x-ms-bmp", a4.content_type
166 assert_equal "image/x-ms-bmp", a4.content_type
167 assert a4.image?
167 assert a4.image?
168
168
169 to_test = {
169 to_test = {
170 'Inline image: !testtest.jpg!' =>
170 'Inline image: !testtest.jpg!' =>
171 'Inline image: <img src="/attachments/download/' + a1.id.to_s + '" alt="" />',
171 'Inline image: <img src="/attachments/download/' + a1.id.to_s + '" alt="" />',
172 'Inline image: !testtest.jpeg!' =>
172 'Inline image: !testtest.jpeg!' =>
173 'Inline image: <img src="/attachments/download/' + a2.id.to_s + '" alt="" />',
173 'Inline image: <img src="/attachments/download/' + a2.id.to_s + '" alt="" />',
174 'Inline image: !testtest.jpe!' =>
174 'Inline image: !testtest.jpe!' =>
175 'Inline image: <img src="/attachments/download/' + a3.id.to_s + '" alt="" />',
175 'Inline image: <img src="/attachments/download/' + a3.id.to_s + '" alt="" />',
176 'Inline image: !testtest.bmp!' =>
176 'Inline image: !testtest.bmp!' =>
177 'Inline image: <img src="/attachments/download/' + a4.id.to_s + '" alt="" />',
177 'Inline image: <img src="/attachments/download/' + a4.id.to_s + '" alt="" />',
178 }
178 }
179
179
180 attachments = [a1, a2, a3, a4]
180 attachments = [a1, a2, a3, a4]
181 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text, :attachments => attachments) }
181 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text, :attachments => attachments) }
182 end
182 end
183
183
184 def test_attached_images_should_read_later
184 def test_attached_images_should_read_later
185 Attachment.storage_path = "#{Rails.root}/test/fixtures/files"
185 Attachment.storage_path = "#{Rails.root}/test/fixtures/files"
186 a1 = Attachment.find(16)
186 a1 = Attachment.find(16)
187 assert_equal "testfile.png", a1.filename
187 assert_equal "testfile.png", a1.filename
188 assert a1.readable?
188 assert a1.readable?
189 assert (! a1.visible?(User.anonymous))
189 assert (! a1.visible?(User.anonymous))
190 assert a1.visible?(User.find(2))
190 assert a1.visible?(User.find(2))
191 a2 = Attachment.find(17)
191 a2 = Attachment.find(17)
192 assert_equal "testfile.PNG", a2.filename
192 assert_equal "testfile.PNG", a2.filename
193 assert a2.readable?
193 assert a2.readable?
194 assert (! a2.visible?(User.anonymous))
194 assert (! a2.visible?(User.anonymous))
195 assert a2.visible?(User.find(2))
195 assert a2.visible?(User.find(2))
196 assert a1.created_on < a2.created_on
196 assert a1.created_on < a2.created_on
197
197
198 to_test = {
198 to_test = {
199 'Inline image: !testfile.png!' =>
199 'Inline image: !testfile.png!' =>
200 'Inline image: <img src="/attachments/download/' + a2.id.to_s + '" alt="" />',
200 'Inline image: <img src="/attachments/download/' + a2.id.to_s + '" alt="" />',
201 'Inline image: !Testfile.PNG!' =>
201 'Inline image: !Testfile.PNG!' =>
202 'Inline image: <img src="/attachments/download/' + a2.id.to_s + '" alt="" />',
202 'Inline image: <img src="/attachments/download/' + a2.id.to_s + '" alt="" />',
203 }
203 }
204 attachments = [a1, a2]
204 attachments = [a1, a2]
205 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text, :attachments => attachments) }
205 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text, :attachments => attachments) }
206 set_tmp_attachments_directory
206 end
207 end
207
208
208 def test_textile_external_links
209 def test_textile_external_links
209 to_test = {
210 to_test = {
210 'This is a "link":http://foo.bar' => 'This is a <a href="http://foo.bar" class="external">link</a>',
211 'This is a "link":http://foo.bar' => 'This is a <a href="http://foo.bar" class="external">link</a>',
211 'This is an intern "link":/foo/bar' => 'This is an intern <a href="/foo/bar">link</a>',
212 'This is an intern "link":/foo/bar' => 'This is an intern <a href="/foo/bar">link</a>',
212 '"link (Link title)":http://foo.bar' => '<a href="http://foo.bar" title="Link title" class="external">link</a>',
213 '"link (Link title)":http://foo.bar' => '<a href="http://foo.bar" title="Link title" class="external">link</a>',
213 '"link (Link title with "double-quotes")":http://foo.bar' => '<a href="http://foo.bar" title="Link title with &quot;double-quotes&quot;" class="external">link</a>',
214 '"link (Link title with "double-quotes")":http://foo.bar' => '<a href="http://foo.bar" title="Link title with &quot;double-quotes&quot;" class="external">link</a>',
214 "This is not a \"Link\":\n\nAnother paragraph" => "This is not a \"Link\":</p>\n\n\n\t<p>Another paragraph",
215 "This is not a \"Link\":\n\nAnother paragraph" => "This is not a \"Link\":</p>\n\n\n\t<p>Another paragraph",
215 # no multiline link text
216 # no multiline link text
216 "This is a double quote \"on the first line\nand another on a second line\":test" => "This is a double quote \"on the first line<br />and another on a second line\":test",
217 "This is a double quote \"on the first line\nand another on a second line\":test" => "This is a double quote \"on the first line<br />and another on a second line\":test",
217 # mailto link
218 # mailto link
218 "\"system administrator\":mailto:sysadmin@example.com?subject=redmine%20permissions" => "<a href=\"mailto:sysadmin@example.com?subject=redmine%20permissions\">system administrator</a>",
219 "\"system administrator\":mailto:sysadmin@example.com?subject=redmine%20permissions" => "<a href=\"mailto:sysadmin@example.com?subject=redmine%20permissions\">system administrator</a>",
219 # two exclamation marks
220 # two exclamation marks
220 '"a link":http://example.net/path!602815048C7B5C20!302.html' => '<a href="http://example.net/path!602815048C7B5C20!302.html" class="external">a link</a>',
221 '"a link":http://example.net/path!602815048C7B5C20!302.html' => '<a href="http://example.net/path!602815048C7B5C20!302.html" class="external">a link</a>',
221 # escaping
222 # escaping
222 '"test":http://foo"bar' => '<a href="http://foo&quot;bar" class="external">test</a>',
223 '"test":http://foo"bar' => '<a href="http://foo&quot;bar" class="external">test</a>',
223 }
224 }
224 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
225 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
225 end
226 end
226
227
227 def test_redmine_links
228 def test_redmine_links
228 issue_link = link_to('#3', {:controller => 'issues', :action => 'show', :id => 3},
229 issue_link = link_to('#3', {:controller => 'issues', :action => 'show', :id => 3},
229 :class => 'issue status-1 priority-1 overdue', :title => 'Error 281 when updating a recipe (New)')
230 :class => 'issue status-1 priority-1 overdue', :title => 'Error 281 when updating a recipe (New)')
230
231
231 changeset_link = link_to('r1', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :rev => 1},
232 changeset_link = link_to('r1', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :rev => 1},
232 :class => 'changeset', :title => 'My very first commit')
233 :class => 'changeset', :title => 'My very first commit')
233 changeset_link2 = link_to('r2', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :rev => 2},
234 changeset_link2 = link_to('r2', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :rev => 2},
234 :class => 'changeset', :title => 'This commit fixes #1, #2 and references #1 & #3')
235 :class => 'changeset', :title => 'This commit fixes #1, #2 and references #1 & #3')
235
236
236 document_link = link_to('Test document', {:controller => 'documents', :action => 'show', :id => 1},
237 document_link = link_to('Test document', {:controller => 'documents', :action => 'show', :id => 1},
237 :class => 'document')
238 :class => 'document')
238
239
239 version_link = link_to('1.0', {:controller => 'versions', :action => 'show', :id => 2},
240 version_link = link_to('1.0', {:controller => 'versions', :action => 'show', :id => 2},
240 :class => 'version')
241 :class => 'version')
241
242
242 board_url = {:controller => 'boards', :action => 'show', :id => 2, :project_id => 'ecookbook'}
243 board_url = {:controller => 'boards', :action => 'show', :id => 2, :project_id => 'ecookbook'}
243
244
244 message_url = {:controller => 'messages', :action => 'show', :board_id => 1, :id => 4}
245 message_url = {:controller => 'messages', :action => 'show', :board_id => 1, :id => 4}
245
246
246 news_url = {:controller => 'news', :action => 'show', :id => 1}
247 news_url = {:controller => 'news', :action => 'show', :id => 1}
247
248
248 project_url = {:controller => 'projects', :action => 'show', :id => 'subproject1'}
249 project_url = {:controller => 'projects', :action => 'show', :id => 'subproject1'}
249
250
250 source_url = {:controller => 'repositories', :action => 'entry', :id => 'ecookbook', :path => ['some', 'file']}
251 source_url = {:controller => 'repositories', :action => 'entry', :id => 'ecookbook', :path => ['some', 'file']}
251 source_url_with_ext = {:controller => 'repositories', :action => 'entry', :id => 'ecookbook', :path => ['some', 'file.ext']}
252 source_url_with_ext = {:controller => 'repositories', :action => 'entry', :id => 'ecookbook', :path => ['some', 'file.ext']}
252
253
253 to_test = {
254 to_test = {
254 # tickets
255 # tickets
255 '#3, [#3], (#3) and #3.' => "#{issue_link}, [#{issue_link}], (#{issue_link}) and #{issue_link}.",
256 '#3, [#3], (#3) and #3.' => "#{issue_link}, [#{issue_link}], (#{issue_link}) and #{issue_link}.",
256 # changesets
257 # changesets
257 'r1' => changeset_link,
258 'r1' => changeset_link,
258 'r1.' => "#{changeset_link}.",
259 'r1.' => "#{changeset_link}.",
259 'r1, r2' => "#{changeset_link}, #{changeset_link2}",
260 'r1, r2' => "#{changeset_link}, #{changeset_link2}",
260 'r1,r2' => "#{changeset_link},#{changeset_link2}",
261 'r1,r2' => "#{changeset_link},#{changeset_link2}",
261 # documents
262 # documents
262 'document#1' => document_link,
263 'document#1' => document_link,
263 'document:"Test document"' => document_link,
264 'document:"Test document"' => document_link,
264 # versions
265 # versions
265 'version#2' => version_link,
266 'version#2' => version_link,
266 'version:1.0' => version_link,
267 'version:1.0' => version_link,
267 'version:"1.0"' => version_link,
268 'version:"1.0"' => version_link,
268 # source
269 # source
269 'source:/some/file' => link_to('source:/some/file', source_url, :class => 'source'),
270 'source:/some/file' => link_to('source:/some/file', source_url, :class => 'source'),
270 'source:/some/file.' => link_to('source:/some/file', source_url, :class => 'source') + ".",
271 'source:/some/file.' => link_to('source:/some/file', source_url, :class => 'source') + ".",
271 'source:/some/file.ext.' => link_to('source:/some/file.ext', source_url_with_ext, :class => 'source') + ".",
272 'source:/some/file.ext.' => link_to('source:/some/file.ext', source_url_with_ext, :class => 'source') + ".",
272 'source:/some/file. ' => link_to('source:/some/file', source_url, :class => 'source') + ".",
273 'source:/some/file. ' => link_to('source:/some/file', source_url, :class => 'source') + ".",
273 'source:/some/file.ext. ' => link_to('source:/some/file.ext', source_url_with_ext, :class => 'source') + ".",
274 'source:/some/file.ext. ' => link_to('source:/some/file.ext', source_url_with_ext, :class => 'source') + ".",
274 'source:/some/file, ' => link_to('source:/some/file', source_url, :class => 'source') + ",",
275 'source:/some/file, ' => link_to('source:/some/file', source_url, :class => 'source') + ",",
275 'source:/some/file@52' => link_to('source:/some/file@52', source_url.merge(:rev => 52), :class => 'source'),
276 'source:/some/file@52' => link_to('source:/some/file@52', source_url.merge(:rev => 52), :class => 'source'),
276 'source:/some/file.ext@52' => link_to('source:/some/file.ext@52', source_url_with_ext.merge(:rev => 52), :class => 'source'),
277 'source:/some/file.ext@52' => link_to('source:/some/file.ext@52', source_url_with_ext.merge(:rev => 52), :class => 'source'),
277 'source:/some/file#L110' => link_to('source:/some/file#L110', source_url.merge(:anchor => 'L110'), :class => 'source'),
278 'source:/some/file#L110' => link_to('source:/some/file#L110', source_url.merge(:anchor => 'L110'), :class => 'source'),
278 'source:/some/file.ext#L110' => link_to('source:/some/file.ext#L110', source_url_with_ext.merge(:anchor => 'L110'), :class => 'source'),
279 'source:/some/file.ext#L110' => link_to('source:/some/file.ext#L110', source_url_with_ext.merge(:anchor => 'L110'), :class => 'source'),
279 'source:/some/file@52#L110' => link_to('source:/some/file@52#L110', source_url.merge(:rev => 52, :anchor => 'L110'), :class => 'source'),
280 'source:/some/file@52#L110' => link_to('source:/some/file@52#L110', source_url.merge(:rev => 52, :anchor => 'L110'), :class => 'source'),
280 'export:/some/file' => link_to('export:/some/file', source_url.merge(:format => 'raw'), :class => 'source download'),
281 'export:/some/file' => link_to('export:/some/file', source_url.merge(:format => 'raw'), :class => 'source download'),
281 # forum
282 # forum
282 'forum#2' => link_to('Discussion', board_url, :class => 'board'),
283 'forum#2' => link_to('Discussion', board_url, :class => 'board'),
283 'forum:Discussion' => link_to('Discussion', board_url, :class => 'board'),
284 'forum:Discussion' => link_to('Discussion', board_url, :class => 'board'),
284 # message
285 # message
285 'message#4' => link_to('Post 2', message_url, :class => 'message'),
286 'message#4' => link_to('Post 2', message_url, :class => 'message'),
286 'message#5' => link_to('RE: post 2', message_url.merge(:anchor => 'message-5', :r => 5), :class => 'message'),
287 'message#5' => link_to('RE: post 2', message_url.merge(:anchor => 'message-5', :r => 5), :class => 'message'),
287 # news
288 # news
288 'news#1' => link_to('eCookbook first release !', news_url, :class => 'news'),
289 'news#1' => link_to('eCookbook first release !', news_url, :class => 'news'),
289 'news:"eCookbook first release !"' => link_to('eCookbook first release !', news_url, :class => 'news'),
290 'news:"eCookbook first release !"' => link_to('eCookbook first release !', news_url, :class => 'news'),
290 # project
291 # project
291 'project#3' => link_to('eCookbook Subproject 1', project_url, :class => 'project'),
292 'project#3' => link_to('eCookbook Subproject 1', project_url, :class => 'project'),
292 'project:subproject1' => link_to('eCookbook Subproject 1', project_url, :class => 'project'),
293 'project:subproject1' => link_to('eCookbook Subproject 1', project_url, :class => 'project'),
293 'project:"eCookbook subProject 1"' => link_to('eCookbook Subproject 1', project_url, :class => 'project'),
294 'project:"eCookbook subProject 1"' => link_to('eCookbook Subproject 1', project_url, :class => 'project'),
294 # escaping
295 # escaping
295 '!#3.' => '#3.',
296 '!#3.' => '#3.',
296 '!r1' => 'r1',
297 '!r1' => 'r1',
297 '!document#1' => 'document#1',
298 '!document#1' => 'document#1',
298 '!document:"Test document"' => 'document:"Test document"',
299 '!document:"Test document"' => 'document:"Test document"',
299 '!version#2' => 'version#2',
300 '!version#2' => 'version#2',
300 '!version:1.0' => 'version:1.0',
301 '!version:1.0' => 'version:1.0',
301 '!version:"1.0"' => 'version:"1.0"',
302 '!version:"1.0"' => 'version:"1.0"',
302 '!source:/some/file' => 'source:/some/file',
303 '!source:/some/file' => 'source:/some/file',
303 # not found
304 # not found
304 '#0123456789' => '#0123456789',
305 '#0123456789' => '#0123456789',
305 # invalid expressions
306 # invalid expressions
306 'source:' => 'source:',
307 'source:' => 'source:',
307 # url hash
308 # url hash
308 "http://foo.bar/FAQ#3" => '<a class="external" href="http://foo.bar/FAQ#3">http://foo.bar/FAQ#3</a>',
309 "http://foo.bar/FAQ#3" => '<a class="external" href="http://foo.bar/FAQ#3">http://foo.bar/FAQ#3</a>',
309 }
310 }
310 @project = Project.find(1)
311 @project = Project.find(1)
311 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text), "#{text} failed" }
312 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text), "#{text} failed" }
312 end
313 end
313
314
314 def test_cross_project_redmine_links
315 def test_cross_project_redmine_links
315 source_link = link_to('ecookbook:source:/some/file', {:controller => 'repositories', :action => 'entry', :id => 'ecookbook', :path => ['some', 'file']},
316 source_link = link_to('ecookbook:source:/some/file', {:controller => 'repositories', :action => 'entry', :id => 'ecookbook', :path => ['some', 'file']},
316 :class => 'source')
317 :class => 'source')
317
318
318 changeset_link = link_to('ecookbook:r2', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :rev => 2},
319 changeset_link = link_to('ecookbook:r2', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :rev => 2},
319 :class => 'changeset', :title => 'This commit fixes #1, #2 and references #1 & #3')
320 :class => 'changeset', :title => 'This commit fixes #1, #2 and references #1 & #3')
320
321
321 to_test = {
322 to_test = {
322 # documents
323 # documents
323 'document:"Test document"' => 'document:"Test document"',
324 'document:"Test document"' => 'document:"Test document"',
324 'ecookbook:document:"Test document"' => '<a href="/documents/1" class="document">Test document</a>',
325 'ecookbook:document:"Test document"' => '<a href="/documents/1" class="document">Test document</a>',
325 'invalid:document:"Test document"' => 'invalid:document:"Test document"',
326 'invalid:document:"Test document"' => 'invalid:document:"Test document"',
326 # versions
327 # versions
327 'version:"1.0"' => 'version:"1.0"',
328 'version:"1.0"' => 'version:"1.0"',
328 'ecookbook:version:"1.0"' => '<a href="/versions/2" class="version">1.0</a>',
329 'ecookbook:version:"1.0"' => '<a href="/versions/2" class="version">1.0</a>',
329 'invalid:version:"1.0"' => 'invalid:version:"1.0"',
330 'invalid:version:"1.0"' => 'invalid:version:"1.0"',
330 # changeset
331 # changeset
331 'r2' => 'r2',
332 'r2' => 'r2',
332 'ecookbook:r2' => changeset_link,
333 'ecookbook:r2' => changeset_link,
333 'invalid:r2' => 'invalid:r2',
334 'invalid:r2' => 'invalid:r2',
334 # source
335 # source
335 'source:/some/file' => 'source:/some/file',
336 'source:/some/file' => 'source:/some/file',
336 'ecookbook:source:/some/file' => source_link,
337 'ecookbook:source:/some/file' => source_link,
337 'invalid:source:/some/file' => 'invalid:source:/some/file',
338 'invalid:source:/some/file' => 'invalid:source:/some/file',
338 }
339 }
339 @project = Project.find(3)
340 @project = Project.find(3)
340 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text), "#{text} failed" }
341 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text), "#{text} failed" }
341 end
342 end
342
343
343 def test_redmine_links_git_commit
344 def test_redmine_links_git_commit
344 changeset_link = link_to('abcd',
345 changeset_link = link_to('abcd',
345 {
346 {
346 :controller => 'repositories',
347 :controller => 'repositories',
347 :action => 'revision',
348 :action => 'revision',
348 :id => 'subproject1',
349 :id => 'subproject1',
349 :rev => 'abcd',
350 :rev => 'abcd',
350 },
351 },
351 :class => 'changeset', :title => 'test commit')
352 :class => 'changeset', :title => 'test commit')
352 to_test = {
353 to_test = {
353 'commit:abcd' => changeset_link,
354 'commit:abcd' => changeset_link,
354 }
355 }
355 @project = Project.find(3)
356 @project = Project.find(3)
356 r = Repository::Git.create!(:project => @project, :url => '/tmp/test/git')
357 r = Repository::Git.create!(:project => @project, :url => '/tmp/test/git')
357 assert r
358 assert r
358 c = Changeset.new(:repository => r,
359 c = Changeset.new(:repository => r,
359 :committed_on => Time.now,
360 :committed_on => Time.now,
360 :revision => 'abcd',
361 :revision => 'abcd',
361 :scmid => 'abcd',
362 :scmid => 'abcd',
362 :comments => 'test commit')
363 :comments => 'test commit')
363 assert( c.save )
364 assert( c.save )
364 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
365 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
365 end
366 end
366
367
367 # TODO: Bazaar commit id contains mail address, so it contains '@' and '_'.
368 # TODO: Bazaar commit id contains mail address, so it contains '@' and '_'.
368 def test_redmine_links_darcs_commit
369 def test_redmine_links_darcs_commit
369 changeset_link = link_to('20080308225258-98289-abcd456efg.gz',
370 changeset_link = link_to('20080308225258-98289-abcd456efg.gz',
370 {
371 {
371 :controller => 'repositories',
372 :controller => 'repositories',
372 :action => 'revision',
373 :action => 'revision',
373 :id => 'subproject1',
374 :id => 'subproject1',
374 :rev => '123',
375 :rev => '123',
375 },
376 },
376 :class => 'changeset', :title => 'test commit')
377 :class => 'changeset', :title => 'test commit')
377 to_test = {
378 to_test = {
378 'commit:20080308225258-98289-abcd456efg.gz' => changeset_link,
379 'commit:20080308225258-98289-abcd456efg.gz' => changeset_link,
379 }
380 }
380 @project = Project.find(3)
381 @project = Project.find(3)
381 r = Repository::Darcs.create!(
382 r = Repository::Darcs.create!(
382 :project => @project, :url => '/tmp/test/darcs',
383 :project => @project, :url => '/tmp/test/darcs',
383 :log_encoding => 'UTF-8')
384 :log_encoding => 'UTF-8')
384 assert r
385 assert r
385 c = Changeset.new(:repository => r,
386 c = Changeset.new(:repository => r,
386 :committed_on => Time.now,
387 :committed_on => Time.now,
387 :revision => '123',
388 :revision => '123',
388 :scmid => '20080308225258-98289-abcd456efg.gz',
389 :scmid => '20080308225258-98289-abcd456efg.gz',
389 :comments => 'test commit')
390 :comments => 'test commit')
390 assert( c.save )
391 assert( c.save )
391 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
392 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
392 end
393 end
393
394
394 def test_redmine_links_mercurial_commit
395 def test_redmine_links_mercurial_commit
395 changeset_link_rev = link_to('r123',
396 changeset_link_rev = link_to('r123',
396 {
397 {
397 :controller => 'repositories',
398 :controller => 'repositories',
398 :action => 'revision',
399 :action => 'revision',
399 :id => 'subproject1',
400 :id => 'subproject1',
400 :rev => '123' ,
401 :rev => '123' ,
401 },
402 },
402 :class => 'changeset', :title => 'test commit')
403 :class => 'changeset', :title => 'test commit')
403 changeset_link_commit = link_to('abcd',
404 changeset_link_commit = link_to('abcd',
404 {
405 {
405 :controller => 'repositories',
406 :controller => 'repositories',
406 :action => 'revision',
407 :action => 'revision',
407 :id => 'subproject1',
408 :id => 'subproject1',
408 :rev => 'abcd' ,
409 :rev => 'abcd' ,
409 },
410 },
410 :class => 'changeset', :title => 'test commit')
411 :class => 'changeset', :title => 'test commit')
411 to_test = {
412 to_test = {
412 'r123' => changeset_link_rev,
413 'r123' => changeset_link_rev,
413 'commit:abcd' => changeset_link_commit,
414 'commit:abcd' => changeset_link_commit,
414 }
415 }
415 @project = Project.find(3)
416 @project = Project.find(3)
416 r = Repository::Mercurial.create!(:project => @project, :url => '/tmp/test')
417 r = Repository::Mercurial.create!(:project => @project, :url => '/tmp/test')
417 assert r
418 assert r
418 c = Changeset.new(:repository => r,
419 c = Changeset.new(:repository => r,
419 :committed_on => Time.now,
420 :committed_on => Time.now,
420 :revision => '123',
421 :revision => '123',
421 :scmid => 'abcd',
422 :scmid => 'abcd',
422 :comments => 'test commit')
423 :comments => 'test commit')
423 assert( c.save )
424 assert( c.save )
424 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
425 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
425 end
426 end
426
427
427 def test_attachment_links
428 def test_attachment_links
428 attachment_link = link_to('error281.txt', {:controller => 'attachments', :action => 'download', :id => '1'}, :class => 'attachment')
429 attachment_link = link_to('error281.txt', {:controller => 'attachments', :action => 'download', :id => '1'}, :class => 'attachment')
429 to_test = {
430 to_test = {
430 'attachment:error281.txt' => attachment_link
431 'attachment:error281.txt' => attachment_link
431 }
432 }
432 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text, :attachments => Issue.find(3).attachments), "#{text} failed" }
433 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text, :attachments => Issue.find(3).attachments), "#{text} failed" }
433 end
434 end
434
435
435 def test_wiki_links
436 def test_wiki_links
436 to_test = {
437 to_test = {
437 '[[CookBook documentation]]' => '<a href="/projects/ecookbook/wiki/CookBook_documentation" class="wiki-page">CookBook documentation</a>',
438 '[[CookBook documentation]]' => '<a href="/projects/ecookbook/wiki/CookBook_documentation" class="wiki-page">CookBook documentation</a>',
438 '[[Another page|Page]]' => '<a href="/projects/ecookbook/wiki/Another_page" class="wiki-page">Page</a>',
439 '[[Another page|Page]]' => '<a href="/projects/ecookbook/wiki/Another_page" class="wiki-page">Page</a>',
439 # title content should be formatted
440 # title content should be formatted
440 '[[Another page|With _styled_ *title*]]' => '<a href="/projects/ecookbook/wiki/Another_page" class="wiki-page">With <em>styled</em> <strong>title</strong></a>',
441 '[[Another page|With _styled_ *title*]]' => '<a href="/projects/ecookbook/wiki/Another_page" class="wiki-page">With <em>styled</em> <strong>title</strong></a>',
441 '[[Another page|With title containing <strong>HTML entities &amp; markups</strong>]]' => '<a href="/projects/ecookbook/wiki/Another_page" class="wiki-page">With title containing &lt;strong&gt;HTML entities &amp; markups&lt;/strong&gt;</a>',
442 '[[Another page|With title containing <strong>HTML entities &amp; markups</strong>]]' => '<a href="/projects/ecookbook/wiki/Another_page" class="wiki-page">With title containing &lt;strong&gt;HTML entities &amp; markups&lt;/strong&gt;</a>',
442 # link with anchor
443 # link with anchor
443 '[[CookBook documentation#One-section]]' => '<a href="/projects/ecookbook/wiki/CookBook_documentation#One-section" class="wiki-page">CookBook documentation</a>',
444 '[[CookBook documentation#One-section]]' => '<a href="/projects/ecookbook/wiki/CookBook_documentation#One-section" class="wiki-page">CookBook documentation</a>',
444 '[[Another page#anchor|Page]]' => '<a href="/projects/ecookbook/wiki/Another_page#anchor" class="wiki-page">Page</a>',
445 '[[Another page#anchor|Page]]' => '<a href="/projects/ecookbook/wiki/Another_page#anchor" class="wiki-page">Page</a>',
445 # page that doesn't exist
446 # page that doesn't exist
446 '[[Unknown page]]' => '<a href="/projects/ecookbook/wiki/Unknown_page" class="wiki-page new">Unknown page</a>',
447 '[[Unknown page]]' => '<a href="/projects/ecookbook/wiki/Unknown_page" class="wiki-page new">Unknown page</a>',
447 '[[Unknown page|404]]' => '<a href="/projects/ecookbook/wiki/Unknown_page" class="wiki-page new">404</a>',
448 '[[Unknown page|404]]' => '<a href="/projects/ecookbook/wiki/Unknown_page" class="wiki-page new">404</a>',
448 # link to another project wiki
449 # link to another project wiki
449 '[[onlinestore:]]' => '<a href="/projects/onlinestore/wiki" class="wiki-page">onlinestore</a>',
450 '[[onlinestore:]]' => '<a href="/projects/onlinestore/wiki" class="wiki-page">onlinestore</a>',
450 '[[onlinestore:|Wiki]]' => '<a href="/projects/onlinestore/wiki" class="wiki-page">Wiki</a>',
451 '[[onlinestore:|Wiki]]' => '<a href="/projects/onlinestore/wiki" class="wiki-page">Wiki</a>',
451 '[[onlinestore:Start page]]' => '<a href="/projects/onlinestore/wiki/Start_page" class="wiki-page">Start page</a>',
452 '[[onlinestore:Start page]]' => '<a href="/projects/onlinestore/wiki/Start_page" class="wiki-page">Start page</a>',
452 '[[onlinestore:Start page|Text]]' => '<a href="/projects/onlinestore/wiki/Start_page" class="wiki-page">Text</a>',
453 '[[onlinestore:Start page|Text]]' => '<a href="/projects/onlinestore/wiki/Start_page" class="wiki-page">Text</a>',
453 '[[onlinestore:Unknown page]]' => '<a href="/projects/onlinestore/wiki/Unknown_page" class="wiki-page new">Unknown page</a>',
454 '[[onlinestore:Unknown page]]' => '<a href="/projects/onlinestore/wiki/Unknown_page" class="wiki-page new">Unknown page</a>',
454 # striked through link
455 # striked through link
455 '-[[Another page|Page]]-' => '<del><a href="/projects/ecookbook/wiki/Another_page" class="wiki-page">Page</a></del>',
456 '-[[Another page|Page]]-' => '<del><a href="/projects/ecookbook/wiki/Another_page" class="wiki-page">Page</a></del>',
456 '-[[Another page|Page]] link-' => '<del><a href="/projects/ecookbook/wiki/Another_page" class="wiki-page">Page</a> link</del>',
457 '-[[Another page|Page]] link-' => '<del><a href="/projects/ecookbook/wiki/Another_page" class="wiki-page">Page</a> link</del>',
457 # escaping
458 # escaping
458 '![[Another page|Page]]' => '[[Another page|Page]]',
459 '![[Another page|Page]]' => '[[Another page|Page]]',
459 # project does not exist
460 # project does not exist
460 '[[unknowproject:Start]]' => '[[unknowproject:Start]]',
461 '[[unknowproject:Start]]' => '[[unknowproject:Start]]',
461 '[[unknowproject:Start|Page title]]' => '[[unknowproject:Start|Page title]]',
462 '[[unknowproject:Start|Page title]]' => '[[unknowproject:Start|Page title]]',
462 }
463 }
463
464
464 @project = Project.find(1)
465 @project = Project.find(1)
465 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
466 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
466 end
467 end
467
468
468 def test_wiki_links_within_local_file_generation_context
469 def test_wiki_links_within_local_file_generation_context
469
470
470 to_test = {
471 to_test = {
471 # link to a page
472 # link to a page
472 '[[CookBook documentation]]' => '<a href="CookBook_documentation.html" class="wiki-page">CookBook documentation</a>',
473 '[[CookBook documentation]]' => '<a href="CookBook_documentation.html" class="wiki-page">CookBook documentation</a>',
473 '[[CookBook documentation|documentation]]' => '<a href="CookBook_documentation.html" class="wiki-page">documentation</a>',
474 '[[CookBook documentation|documentation]]' => '<a href="CookBook_documentation.html" class="wiki-page">documentation</a>',
474 '[[CookBook documentation#One-section]]' => '<a href="CookBook_documentation.html#One-section" class="wiki-page">CookBook documentation</a>',
475 '[[CookBook documentation#One-section]]' => '<a href="CookBook_documentation.html#One-section" class="wiki-page">CookBook documentation</a>',
475 '[[CookBook documentation#One-section|documentation]]' => '<a href="CookBook_documentation.html#One-section" class="wiki-page">documentation</a>',
476 '[[CookBook documentation#One-section|documentation]]' => '<a href="CookBook_documentation.html#One-section" class="wiki-page">documentation</a>',
476 # page that doesn't exist
477 # page that doesn't exist
477 '[[Unknown page]]' => '<a href="Unknown_page.html" class="wiki-page new">Unknown page</a>',
478 '[[Unknown page]]' => '<a href="Unknown_page.html" class="wiki-page new">Unknown page</a>',
478 '[[Unknown page|404]]' => '<a href="Unknown_page.html" class="wiki-page new">404</a>',
479 '[[Unknown page|404]]' => '<a href="Unknown_page.html" class="wiki-page new">404</a>',
479 '[[Unknown page#anchor]]' => '<a href="Unknown_page.html#anchor" class="wiki-page new">Unknown page</a>',
480 '[[Unknown page#anchor]]' => '<a href="Unknown_page.html#anchor" class="wiki-page new">Unknown page</a>',
480 '[[Unknown page#anchor|404]]' => '<a href="Unknown_page.html#anchor" class="wiki-page new">404</a>',
481 '[[Unknown page#anchor|404]]' => '<a href="Unknown_page.html#anchor" class="wiki-page new">404</a>',
481 }
482 }
482
483
483 @project = Project.find(1)
484 @project = Project.find(1)
484
485
485 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text, :wiki_links => :local) }
486 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text, :wiki_links => :local) }
486 end
487 end
487
488
488 def test_html_tags
489 def test_html_tags
489 to_test = {
490 to_test = {
490 "<div>content</div>" => "<p>&lt;div&gt;content&lt;/div&gt;</p>",
491 "<div>content</div>" => "<p>&lt;div&gt;content&lt;/div&gt;</p>",
491 "<div class=\"bold\">content</div>" => "<p>&lt;div class=\"bold\"&gt;content&lt;/div&gt;</p>",
492 "<div class=\"bold\">content</div>" => "<p>&lt;div class=\"bold\"&gt;content&lt;/div&gt;</p>",
492 "<script>some script;</script>" => "<p>&lt;script&gt;some script;&lt;/script&gt;</p>",
493 "<script>some script;</script>" => "<p>&lt;script&gt;some script;&lt;/script&gt;</p>",
493 # do not escape pre/code tags
494 # do not escape pre/code tags
494 "<pre>\nline 1\nline2</pre>" => "<pre>\nline 1\nline2</pre>",
495 "<pre>\nline 1\nline2</pre>" => "<pre>\nline 1\nline2</pre>",
495 "<pre><code>\nline 1\nline2</code></pre>" => "<pre><code>\nline 1\nline2</code></pre>",
496 "<pre><code>\nline 1\nline2</code></pre>" => "<pre><code>\nline 1\nline2</code></pre>",
496 "<pre><div>content</div></pre>" => "<pre>&lt;div&gt;content&lt;/div&gt;</pre>",
497 "<pre><div>content</div></pre>" => "<pre>&lt;div&gt;content&lt;/div&gt;</pre>",
497 "HTML comment: <!-- no comments -->" => "<p>HTML comment: &lt;!-- no comments --&gt;</p>",
498 "HTML comment: <!-- no comments -->" => "<p>HTML comment: &lt;!-- no comments --&gt;</p>",
498 "<!-- opening comment" => "<p>&lt;!-- opening comment</p>",
499 "<!-- opening comment" => "<p>&lt;!-- opening comment</p>",
499 # remove attributes except class
500 # remove attributes except class
500 "<pre class='foo'>some text</pre>" => "<pre class='foo'>some text</pre>",
501 "<pre class='foo'>some text</pre>" => "<pre class='foo'>some text</pre>",
501 '<pre class="foo">some text</pre>' => '<pre class="foo">some text</pre>',
502 '<pre class="foo">some text</pre>' => '<pre class="foo">some text</pre>',
502 "<pre class='foo bar'>some text</pre>" => "<pre class='foo bar'>some text</pre>",
503 "<pre class='foo bar'>some text</pre>" => "<pre class='foo bar'>some text</pre>",
503 '<pre class="foo bar">some text</pre>' => '<pre class="foo bar">some text</pre>',
504 '<pre class="foo bar">some text</pre>' => '<pre class="foo bar">some text</pre>',
504 "<pre onmouseover='alert(1)'>some text</pre>" => "<pre>some text</pre>",
505 "<pre onmouseover='alert(1)'>some text</pre>" => "<pre>some text</pre>",
505 # xss
506 # xss
506 '<pre><code class=""onmouseover="alert(1)">text</code></pre>' => '<pre><code>text</code></pre>',
507 '<pre><code class=""onmouseover="alert(1)">text</code></pre>' => '<pre><code>text</code></pre>',
507 '<pre class=""onmouseover="alert(1)">text</pre>' => '<pre>text</pre>',
508 '<pre class=""onmouseover="alert(1)">text</pre>' => '<pre>text</pre>',
508 }
509 }
509 to_test.each { |text, result| assert_equal result, textilizable(text) }
510 to_test.each { |text, result| assert_equal result, textilizable(text) }
510 end
511 end
511
512
512 def test_allowed_html_tags
513 def test_allowed_html_tags
513 to_test = {
514 to_test = {
514 "<pre>preformatted text</pre>" => "<pre>preformatted text</pre>",
515 "<pre>preformatted text</pre>" => "<pre>preformatted text</pre>",
515 "<notextile>no *textile* formatting</notextile>" => "no *textile* formatting",
516 "<notextile>no *textile* formatting</notextile>" => "no *textile* formatting",
516 "<notextile>this is <tag>a tag</tag></notextile>" => "this is &lt;tag&gt;a tag&lt;/tag&gt;"
517 "<notextile>this is <tag>a tag</tag></notextile>" => "this is &lt;tag&gt;a tag&lt;/tag&gt;"
517 }
518 }
518 to_test.each { |text, result| assert_equal result, textilizable(text) }
519 to_test.each { |text, result| assert_equal result, textilizable(text) }
519 end
520 end
520
521
521 def test_pre_tags
522 def test_pre_tags
522 raw = <<-RAW
523 raw = <<-RAW
523 Before
524 Before
524
525
525 <pre>
526 <pre>
526 <prepared-statement-cache-size>32</prepared-statement-cache-size>
527 <prepared-statement-cache-size>32</prepared-statement-cache-size>
527 </pre>
528 </pre>
528
529
529 After
530 After
530 RAW
531 RAW
531
532
532 expected = <<-EXPECTED
533 expected = <<-EXPECTED
533 <p>Before</p>
534 <p>Before</p>
534 <pre>
535 <pre>
535 &lt;prepared-statement-cache-size&gt;32&lt;/prepared-statement-cache-size&gt;
536 &lt;prepared-statement-cache-size&gt;32&lt;/prepared-statement-cache-size&gt;
536 </pre>
537 </pre>
537 <p>After</p>
538 <p>After</p>
538 EXPECTED
539 EXPECTED
539
540
540 assert_equal expected.gsub(%r{[\r\n\t]}, ''), textilizable(raw).gsub(%r{[\r\n\t]}, '')
541 assert_equal expected.gsub(%r{[\r\n\t]}, ''), textilizable(raw).gsub(%r{[\r\n\t]}, '')
541 end
542 end
542
543
543 def test_pre_content_should_not_parse_wiki_and_redmine_links
544 def test_pre_content_should_not_parse_wiki_and_redmine_links
544 raw = <<-RAW
545 raw = <<-RAW
545 [[CookBook documentation]]
546 [[CookBook documentation]]
546
547
547 #1
548 #1
548
549
549 <pre>
550 <pre>
550 [[CookBook documentation]]
551 [[CookBook documentation]]
551
552
552 #1
553 #1
553 </pre>
554 </pre>
554 RAW
555 RAW
555
556
556 expected = <<-EXPECTED
557 expected = <<-EXPECTED
557 <p><a href="/projects/ecookbook/wiki/CookBook_documentation" class="wiki-page">CookBook documentation</a></p>
558 <p><a href="/projects/ecookbook/wiki/CookBook_documentation" class="wiki-page">CookBook documentation</a></p>
558 <p><a href="/issues/1" class="issue status-1 priority-1" title="Can't print recipes (New)">#1</a></p>
559 <p><a href="/issues/1" class="issue status-1 priority-1" title="Can't print recipes (New)">#1</a></p>
559 <pre>
560 <pre>
560 [[CookBook documentation]]
561 [[CookBook documentation]]
561
562
562 #1
563 #1
563 </pre>
564 </pre>
564 EXPECTED
565 EXPECTED
565
566
566 @project = Project.find(1)
567 @project = Project.find(1)
567 assert_equal expected.gsub(%r{[\r\n\t]}, ''), textilizable(raw).gsub(%r{[\r\n\t]}, '')
568 assert_equal expected.gsub(%r{[\r\n\t]}, ''), textilizable(raw).gsub(%r{[\r\n\t]}, '')
568 end
569 end
569
570
570 def test_non_closing_pre_blocks_should_be_closed
571 def test_non_closing_pre_blocks_should_be_closed
571 raw = <<-RAW
572 raw = <<-RAW
572 <pre><code>
573 <pre><code>
573 RAW
574 RAW
574
575
575 expected = <<-EXPECTED
576 expected = <<-EXPECTED
576 <pre><code>
577 <pre><code>
577 </code></pre>
578 </code></pre>
578 EXPECTED
579 EXPECTED
579
580
580 @project = Project.find(1)
581 @project = Project.find(1)
581 assert_equal expected.gsub(%r{[\r\n\t]}, ''), textilizable(raw).gsub(%r{[\r\n\t]}, '')
582 assert_equal expected.gsub(%r{[\r\n\t]}, ''), textilizable(raw).gsub(%r{[\r\n\t]}, '')
582 end
583 end
583
584
584 def test_syntax_highlight
585 def test_syntax_highlight
585 raw = <<-RAW
586 raw = <<-RAW
586 <pre><code class="ruby">
587 <pre><code class="ruby">
587 # Some ruby code here
588 # Some ruby code here
588 </code></pre>
589 </code></pre>
589 RAW
590 RAW
590
591
591 expected = <<-EXPECTED
592 expected = <<-EXPECTED
592 <pre><code class="ruby syntaxhl"><span class=\"CodeRay\"><span class="line-numbers">1</span><span class="comment"># Some ruby code here</span></span>
593 <pre><code class="ruby syntaxhl"><span class=\"CodeRay\"><span class="line-numbers">1</span><span class="comment"># Some ruby code here</span></span>
593 </code></pre>
594 </code></pre>
594 EXPECTED
595 EXPECTED
595
596
596 assert_equal expected.gsub(%r{[\r\n\t]}, ''), textilizable(raw).gsub(%r{[\r\n\t]}, '')
597 assert_equal expected.gsub(%r{[\r\n\t]}, ''), textilizable(raw).gsub(%r{[\r\n\t]}, '')
597 end
598 end
598
599
599 def test_wiki_links_in_tables
600 def test_wiki_links_in_tables
600 to_test = {"|[[Page|Link title]]|[[Other Page|Other title]]|\n|Cell 21|[[Last page]]|" =>
601 to_test = {"|[[Page|Link title]]|[[Other Page|Other title]]|\n|Cell 21|[[Last page]]|" =>
601 '<tr><td><a href="/projects/ecookbook/wiki/Page" class="wiki-page new">Link title</a></td>' +
602 '<tr><td><a href="/projects/ecookbook/wiki/Page" class="wiki-page new">Link title</a></td>' +
602 '<td><a href="/projects/ecookbook/wiki/Other_Page" class="wiki-page new">Other title</a></td>' +
603 '<td><a href="/projects/ecookbook/wiki/Other_Page" class="wiki-page new">Other title</a></td>' +
603 '</tr><tr><td>Cell 21</td><td><a href="/projects/ecookbook/wiki/Last_page" class="wiki-page new">Last page</a></td></tr>'
604 '</tr><tr><td>Cell 21</td><td><a href="/projects/ecookbook/wiki/Last_page" class="wiki-page new">Last page</a></td></tr>'
604 }
605 }
605 @project = Project.find(1)
606 @project = Project.find(1)
606 to_test.each { |text, result| assert_equal "<table>#{result}</table>", textilizable(text).gsub(/[\t\n]/, '') }
607 to_test.each { |text, result| assert_equal "<table>#{result}</table>", textilizable(text).gsub(/[\t\n]/, '') }
607 end
608 end
608
609
609 def test_text_formatting
610 def test_text_formatting
610 to_test = {'*_+bold, italic and underline+_*' => '<strong><em><ins>bold, italic and underline</ins></em></strong>',
611 to_test = {'*_+bold, italic and underline+_*' => '<strong><em><ins>bold, italic and underline</ins></em></strong>',
611 '(_text within parentheses_)' => '(<em>text within parentheses</em>)',
612 '(_text within parentheses_)' => '(<em>text within parentheses</em>)',
612 'a *Humane Web* Text Generator' => 'a <strong>Humane Web</strong> Text Generator',
613 'a *Humane Web* Text Generator' => 'a <strong>Humane Web</strong> Text Generator',
613 'a H *umane* W *eb* T *ext* G *enerator*' => 'a H <strong>umane</strong> W <strong>eb</strong> T <strong>ext</strong> G <strong>enerator</strong>',
614 'a H *umane* W *eb* T *ext* G *enerator*' => 'a H <strong>umane</strong> W <strong>eb</strong> T <strong>ext</strong> G <strong>enerator</strong>',
614 'a *H* umane *W* eb *T* ext *G* enerator' => 'a <strong>H</strong> umane <strong>W</strong> eb <strong>T</strong> ext <strong>G</strong> enerator',
615 'a *H* umane *W* eb *T* ext *G* enerator' => 'a <strong>H</strong> umane <strong>W</strong> eb <strong>T</strong> ext <strong>G</strong> enerator',
615 }
616 }
616 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
617 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
617 end
618 end
618
619
619 def test_wiki_horizontal_rule
620 def test_wiki_horizontal_rule
620 assert_equal '<hr />', textilizable('---')
621 assert_equal '<hr />', textilizable('---')
621 assert_equal '<p>Dashes: ---</p>', textilizable('Dashes: ---')
622 assert_equal '<p>Dashes: ---</p>', textilizable('Dashes: ---')
622 end
623 end
623
624
624 def test_footnotes
625 def test_footnotes
625 raw = <<-RAW
626 raw = <<-RAW
626 This is some text[1].
627 This is some text[1].
627
628
628 fn1. This is the foot note
629 fn1. This is the foot note
629 RAW
630 RAW
630
631
631 expected = <<-EXPECTED
632 expected = <<-EXPECTED
632 <p>This is some text<sup><a href=\"#fn1\">1</a></sup>.</p>
633 <p>This is some text<sup><a href=\"#fn1\">1</a></sup>.</p>
633 <p id="fn1" class="footnote"><sup>1</sup> This is the foot note</p>
634 <p id="fn1" class="footnote"><sup>1</sup> This is the foot note</p>
634 EXPECTED
635 EXPECTED
635
636
636 assert_equal expected.gsub(%r{[\r\n\t]}, ''), textilizable(raw).gsub(%r{[\r\n\t]}, '')
637 assert_equal expected.gsub(%r{[\r\n\t]}, ''), textilizable(raw).gsub(%r{[\r\n\t]}, '')
637 end
638 end
638
639
639 def test_headings
640 def test_headings
640 raw = 'h1. Some heading'
641 raw = 'h1. Some heading'
641 expected = %|<a name="Some-heading"></a>\n<h1 >Some heading<a href="#Some-heading" class="wiki-anchor">&para;</a></h1>|
642 expected = %|<a name="Some-heading"></a>\n<h1 >Some heading<a href="#Some-heading" class="wiki-anchor">&para;</a></h1>|
642
643
643 assert_equal expected, textilizable(raw)
644 assert_equal expected, textilizable(raw)
644 end
645 end
645
646
646 def test_headings_with_special_chars
647 def test_headings_with_special_chars
647 # This test makes sure that the generated anchor names match the expected
648 # This test makes sure that the generated anchor names match the expected
648 # ones even if the heading text contains unconventional characters
649 # ones even if the heading text contains unconventional characters
649 raw = 'h1. Some heading related to version 0.5'
650 raw = 'h1. Some heading related to version 0.5'
650 anchor = sanitize_anchor_name("Some-heading-related-to-version-0.5")
651 anchor = sanitize_anchor_name("Some-heading-related-to-version-0.5")
651 expected = %|<a name="#{anchor}"></a>\n<h1 >Some heading related to version 0.5<a href="##{anchor}" class="wiki-anchor">&para;</a></h1>|
652 expected = %|<a name="#{anchor}"></a>\n<h1 >Some heading related to version 0.5<a href="##{anchor}" class="wiki-anchor">&para;</a></h1>|
652
653
653 assert_equal expected, textilizable(raw)
654 assert_equal expected, textilizable(raw)
654 end
655 end
655
656
656 def test_wiki_links_within_wiki_page_context
657 def test_wiki_links_within_wiki_page_context
657
658
658 page = WikiPage.find_by_title('Another_page' )
659 page = WikiPage.find_by_title('Another_page' )
659
660
660 to_test = {
661 to_test = {
661 # link to another page
662 # link to another page
662 '[[CookBook documentation]]' => '<a href="/projects/ecookbook/wiki/CookBook_documentation" class="wiki-page">CookBook documentation</a>',
663 '[[CookBook documentation]]' => '<a href="/projects/ecookbook/wiki/CookBook_documentation" class="wiki-page">CookBook documentation</a>',
663 '[[CookBook documentation|documentation]]' => '<a href="/projects/ecookbook/wiki/CookBook_documentation" class="wiki-page">documentation</a>',
664 '[[CookBook documentation|documentation]]' => '<a href="/projects/ecookbook/wiki/CookBook_documentation" class="wiki-page">documentation</a>',
664 '[[CookBook documentation#One-section]]' => '<a href="/projects/ecookbook/wiki/CookBook_documentation#One-section" class="wiki-page">CookBook documentation</a>',
665 '[[CookBook documentation#One-section]]' => '<a href="/projects/ecookbook/wiki/CookBook_documentation#One-section" class="wiki-page">CookBook documentation</a>',
665 '[[CookBook documentation#One-section|documentation]]' => '<a href="/projects/ecookbook/wiki/CookBook_documentation#One-section" class="wiki-page">documentation</a>',
666 '[[CookBook documentation#One-section|documentation]]' => '<a href="/projects/ecookbook/wiki/CookBook_documentation#One-section" class="wiki-page">documentation</a>',
666 # link to the current page
667 # link to the current page
667 '[[Another page]]' => '<a href="/projects/ecookbook/wiki/Another_page" class="wiki-page">Another page</a>',
668 '[[Another page]]' => '<a href="/projects/ecookbook/wiki/Another_page" class="wiki-page">Another page</a>',
668 '[[Another page|Page]]' => '<a href="/projects/ecookbook/wiki/Another_page" class="wiki-page">Page</a>',
669 '[[Another page|Page]]' => '<a href="/projects/ecookbook/wiki/Another_page" class="wiki-page">Page</a>',
669 '[[Another page#anchor]]' => '<a href="#anchor" class="wiki-page">Another page</a>',
670 '[[Another page#anchor]]' => '<a href="#anchor" class="wiki-page">Another page</a>',
670 '[[Another page#anchor|Page]]' => '<a href="#anchor" class="wiki-page">Page</a>',
671 '[[Another page#anchor|Page]]' => '<a href="#anchor" class="wiki-page">Page</a>',
671 # page that doesn't exist
672 # page that doesn't exist
672 '[[Unknown page]]' => '<a href="/projects/ecookbook/wiki/Unknown_page" class="wiki-page new">Unknown page</a>',
673 '[[Unknown page]]' => '<a href="/projects/ecookbook/wiki/Unknown_page" class="wiki-page new">Unknown page</a>',
673 '[[Unknown page|404]]' => '<a href="/projects/ecookbook/wiki/Unknown_page" class="wiki-page new">404</a>',
674 '[[Unknown page|404]]' => '<a href="/projects/ecookbook/wiki/Unknown_page" class="wiki-page new">404</a>',
674 '[[Unknown page#anchor]]' => '<a href="/projects/ecookbook/wiki/Unknown_page#anchor" class="wiki-page new">Unknown page</a>',
675 '[[Unknown page#anchor]]' => '<a href="/projects/ecookbook/wiki/Unknown_page#anchor" class="wiki-page new">Unknown page</a>',
675 '[[Unknown page#anchor|404]]' => '<a href="/projects/ecookbook/wiki/Unknown_page#anchor" class="wiki-page new">404</a>',
676 '[[Unknown page#anchor|404]]' => '<a href="/projects/ecookbook/wiki/Unknown_page#anchor" class="wiki-page new">404</a>',
676 }
677 }
677
678
678 @project = Project.find(1)
679 @project = Project.find(1)
679
680
680 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(WikiContent.generate!( :text => text, :page => page ), :text) }
681 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(WikiContent.generate!( :text => text, :page => page ), :text) }
681 end
682 end
682
683
683 def test_wiki_links_anchor_option_should_prepend_page_title_to_href
684 def test_wiki_links_anchor_option_should_prepend_page_title_to_href
684
685
685 to_test = {
686 to_test = {
686 # link to a page
687 # link to a page
687 '[[CookBook documentation]]' => '<a href="#CookBook_documentation" class="wiki-page">CookBook documentation</a>',
688 '[[CookBook documentation]]' => '<a href="#CookBook_documentation" class="wiki-page">CookBook documentation</a>',
688 '[[CookBook documentation|documentation]]' => '<a href="#CookBook_documentation" class="wiki-page">documentation</a>',
689 '[[CookBook documentation|documentation]]' => '<a href="#CookBook_documentation" class="wiki-page">documentation</a>',
689 '[[CookBook documentation#One-section]]' => '<a href="#CookBook_documentation_One-section" class="wiki-page">CookBook documentation</a>',
690 '[[CookBook documentation#One-section]]' => '<a href="#CookBook_documentation_One-section" class="wiki-page">CookBook documentation</a>',
690 '[[CookBook documentation#One-section|documentation]]' => '<a href="#CookBook_documentation_One-section" class="wiki-page">documentation</a>',
691 '[[CookBook documentation#One-section|documentation]]' => '<a href="#CookBook_documentation_One-section" class="wiki-page">documentation</a>',
691 # page that doesn't exist
692 # page that doesn't exist
692 '[[Unknown page]]' => '<a href="#Unknown_page" class="wiki-page new">Unknown page</a>',
693 '[[Unknown page]]' => '<a href="#Unknown_page" class="wiki-page new">Unknown page</a>',
693 '[[Unknown page|404]]' => '<a href="#Unknown_page" class="wiki-page new">404</a>',
694 '[[Unknown page|404]]' => '<a href="#Unknown_page" class="wiki-page new">404</a>',
694 '[[Unknown page#anchor]]' => '<a href="#Unknown_page_anchor" class="wiki-page new">Unknown page</a>',
695 '[[Unknown page#anchor]]' => '<a href="#Unknown_page_anchor" class="wiki-page new">Unknown page</a>',
695 '[[Unknown page#anchor|404]]' => '<a href="#Unknown_page_anchor" class="wiki-page new">404</a>',
696 '[[Unknown page#anchor|404]]' => '<a href="#Unknown_page_anchor" class="wiki-page new">404</a>',
696 }
697 }
697
698
698 @project = Project.find(1)
699 @project = Project.find(1)
699
700
700 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text, :wiki_links => :anchor) }
701 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text, :wiki_links => :anchor) }
701 end
702 end
702
703
703 def test_headings_in_wiki_single_page_export_should_be_prepended_with_page_title
704 def test_headings_in_wiki_single_page_export_should_be_prepended_with_page_title
704 page = WikiPage.generate!( :title => 'Page Title' )
705 page = WikiPage.generate!( :title => 'Page Title' )
705 content = WikiContent.generate!( :text => 'h1. Some heading', :page => page )
706 content = WikiContent.generate!( :text => 'h1. Some heading', :page => page )
706
707
707 expected = %|<a name="Page_Title_Some-heading"></a>\n<h1 >Some heading<a href="#Page_Title_Some-heading" class="wiki-anchor">&para;</a></h1>|
708 expected = %|<a name="Page_Title_Some-heading"></a>\n<h1 >Some heading<a href="#Page_Title_Some-heading" class="wiki-anchor">&para;</a></h1>|
708
709
709 assert_equal expected, textilizable(content, :text, :wiki_links => :anchor )
710 assert_equal expected, textilizable(content, :text, :wiki_links => :anchor )
710 end
711 end
711
712
712 def test_table_of_content
713 def test_table_of_content
713 raw = <<-RAW
714 raw = <<-RAW
714 {{toc}}
715 {{toc}}
715
716
716 h1. Title
717 h1. Title
717
718
718 Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas sed libero.
719 Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas sed libero.
719
720
720 h2. Subtitle with a [[Wiki]] link
721 h2. Subtitle with a [[Wiki]] link
721
722
722 Nullam commodo metus accumsan nulla. Curabitur lobortis dui id dolor.
723 Nullam commodo metus accumsan nulla. Curabitur lobortis dui id dolor.
723
724
724 h2. Subtitle with [[Wiki|another Wiki]] link
725 h2. Subtitle with [[Wiki|another Wiki]] link
725
726
726 h2. Subtitle with %{color:red}red text%
727 h2. Subtitle with %{color:red}red text%
727
728
728 <pre>
729 <pre>
729 some code
730 some code
730 </pre>
731 </pre>
731
732
732 h3. Subtitle with *some* _modifiers_
733 h3. Subtitle with *some* _modifiers_
733
734
734 h1. Another title
735 h1. Another title
735
736
736 h3. An "Internet link":http://www.redmine.org/ inside subtitle
737 h3. An "Internet link":http://www.redmine.org/ inside subtitle
737
738
738 h2. "Project Name !/attachments/1234/logo_small.gif! !/attachments/5678/logo_2.png!":/projects/projectname/issues
739 h2. "Project Name !/attachments/1234/logo_small.gif! !/attachments/5678/logo_2.png!":/projects/projectname/issues
739
740
740 RAW
741 RAW
741
742
742 expected = '<ul class="toc">' +
743 expected = '<ul class="toc">' +
743 '<li><a href="#Title">Title</a>' +
744 '<li><a href="#Title">Title</a>' +
744 '<ul>' +
745 '<ul>' +
745 '<li><a href="#Subtitle-with-a-Wiki-link">Subtitle with a Wiki link</a></li>' +
746 '<li><a href="#Subtitle-with-a-Wiki-link">Subtitle with a Wiki link</a></li>' +
746 '<li><a href="#Subtitle-with-another-Wiki-link">Subtitle with another Wiki link</a></li>' +
747 '<li><a href="#Subtitle-with-another-Wiki-link">Subtitle with another Wiki link</a></li>' +
747 '<li><a href="#Subtitle-with-red-text">Subtitle with red text</a>' +
748 '<li><a href="#Subtitle-with-red-text">Subtitle with red text</a>' +
748 '<ul>' +
749 '<ul>' +
749 '<li><a href="#Subtitle-with-some-modifiers">Subtitle with some modifiers</a></li>' +
750 '<li><a href="#Subtitle-with-some-modifiers">Subtitle with some modifiers</a></li>' +
750 '</ul>' +
751 '</ul>' +
751 '</li>' +
752 '</li>' +
752 '</ul>' +
753 '</ul>' +
753 '</li>' +
754 '</li>' +
754 '<li><a href="#Another-title">Another title</a>' +
755 '<li><a href="#Another-title">Another title</a>' +
755 '<ul>' +
756 '<ul>' +
756 '<li>' +
757 '<li>' +
757 '<ul>' +
758 '<ul>' +
758 '<li><a href="#An-Internet-link-inside-subtitle">An Internet link inside subtitle</a></li>' +
759 '<li><a href="#An-Internet-link-inside-subtitle">An Internet link inside subtitle</a></li>' +
759 '</ul>' +
760 '</ul>' +
760 '</li>' +
761 '</li>' +
761 '<li><a href="#Project-Name">Project Name</a></li>' +
762 '<li><a href="#Project-Name">Project Name</a></li>' +
762 '</ul>' +
763 '</ul>' +
763 '</li>' +
764 '</li>' +
764 '</ul>'
765 '</ul>'
765
766
766 @project = Project.find(1)
767 @project = Project.find(1)
767 assert textilizable(raw).gsub("\n", "").include?(expected), textilizable(raw)
768 assert textilizable(raw).gsub("\n", "").include?(expected), textilizable(raw)
768 end
769 end
769
770
770 def test_table_of_content_should_contain_included_page_headings
771 def test_table_of_content_should_contain_included_page_headings
771 raw = <<-RAW
772 raw = <<-RAW
772 {{toc}}
773 {{toc}}
773
774
774 h1. Included
775 h1. Included
775
776
776 {{include(Child_1)}}
777 {{include(Child_1)}}
777 RAW
778 RAW
778
779
779 expected = '<ul class="toc">' +
780 expected = '<ul class="toc">' +
780 '<li><a href="#Included">Included</a></li>' +
781 '<li><a href="#Included">Included</a></li>' +
781 '<li><a href="#Child-page-1">Child page 1</a></li>' +
782 '<li><a href="#Child-page-1">Child page 1</a></li>' +
782 '</ul>'
783 '</ul>'
783
784
784 @project = Project.find(1)
785 @project = Project.find(1)
785 assert textilizable(raw).gsub("\n", "").include?(expected)
786 assert textilizable(raw).gsub("\n", "").include?(expected)
786 end
787 end
787
788
788 def test_default_formatter
789 def test_default_formatter
789 Setting.text_formatting = 'unknown'
790 Setting.text_formatting = 'unknown'
790 text = 'a *link*: http://www.example.net/'
791 text = 'a *link*: http://www.example.net/'
791 assert_equal '<p>a *link*: <a href="http://www.example.net/">http://www.example.net/</a></p>', textilizable(text)
792 assert_equal '<p>a *link*: <a href="http://www.example.net/">http://www.example.net/</a></p>', textilizable(text)
792 Setting.text_formatting = 'textile'
793 Setting.text_formatting = 'textile'
793 end
794 end
794
795
795 def test_due_date_distance_in_words
796 def test_due_date_distance_in_words
796 to_test = { Date.today => 'Due in 0 days',
797 to_test = { Date.today => 'Due in 0 days',
797 Date.today + 1 => 'Due in 1 day',
798 Date.today + 1 => 'Due in 1 day',
798 Date.today + 100 => 'Due in about 3 months',
799 Date.today + 100 => 'Due in about 3 months',
799 Date.today + 20000 => 'Due in over 54 years',
800 Date.today + 20000 => 'Due in over 54 years',
800 Date.today - 1 => '1 day late',
801 Date.today - 1 => '1 day late',
801 Date.today - 100 => 'about 3 months late',
802 Date.today - 100 => 'about 3 months late',
802 Date.today - 20000 => 'over 54 years late',
803 Date.today - 20000 => 'over 54 years late',
803 }
804 }
804 ::I18n.locale = :en
805 ::I18n.locale = :en
805 to_test.each do |date, expected|
806 to_test.each do |date, expected|
806 assert_equal expected, due_date_distance_in_words(date)
807 assert_equal expected, due_date_distance_in_words(date)
807 end
808 end
808 end
809 end
809
810
810 def test_avatar
811 def test_avatar
811 # turn on avatars
812 # turn on avatars
812 Setting.gravatar_enabled = '1'
813 Setting.gravatar_enabled = '1'
813 assert avatar(User.find_by_mail('jsmith@somenet.foo')).include?(Digest::MD5.hexdigest('jsmith@somenet.foo'))
814 assert avatar(User.find_by_mail('jsmith@somenet.foo')).include?(Digest::MD5.hexdigest('jsmith@somenet.foo'))
814 assert avatar('jsmith <jsmith@somenet.foo>').include?(Digest::MD5.hexdigest('jsmith@somenet.foo'))
815 assert avatar('jsmith <jsmith@somenet.foo>').include?(Digest::MD5.hexdigest('jsmith@somenet.foo'))
815 assert_nil avatar('jsmith')
816 assert_nil avatar('jsmith')
816 assert_nil avatar(nil)
817 assert_nil avatar(nil)
817
818
818 # turn off avatars
819 # turn off avatars
819 Setting.gravatar_enabled = '0'
820 Setting.gravatar_enabled = '0'
820 assert_equal '', avatar(User.find_by_mail('jsmith@somenet.foo'))
821 assert_equal '', avatar(User.find_by_mail('jsmith@somenet.foo'))
821 end
822 end
822
823
823 def test_link_to_user
824 def test_link_to_user
824 user = User.find(2)
825 user = User.find(2)
825 t = link_to_user(user)
826 t = link_to_user(user)
826 assert_equal "<a href=\"/users/2\">#{ user.name }</a>", t
827 assert_equal "<a href=\"/users/2\">#{ user.name }</a>", t
827 end
828 end
828
829
829 def test_link_to_user_should_not_link_to_locked_user
830 def test_link_to_user_should_not_link_to_locked_user
830 user = User.find(5)
831 user = User.find(5)
831 assert user.locked?
832 assert user.locked?
832 t = link_to_user(user)
833 t = link_to_user(user)
833 assert_equal user.name, t
834 assert_equal user.name, t
834 end
835 end
835
836
836 def test_link_to_user_should_not_link_to_anonymous
837 def test_link_to_user_should_not_link_to_anonymous
837 user = User.anonymous
838 user = User.anonymous
838 assert user.anonymous?
839 assert user.anonymous?
839 t = link_to_user(user)
840 t = link_to_user(user)
840 assert_equal ::I18n.t(:label_user_anonymous), t
841 assert_equal ::I18n.t(:label_user_anonymous), t
841 end
842 end
842
843
843 def test_link_to_project
844 def test_link_to_project
844 project = Project.find(1)
845 project = Project.find(1)
845 assert_equal %(<a href="/projects/ecookbook">eCookbook</a>),
846 assert_equal %(<a href="/projects/ecookbook">eCookbook</a>),
846 link_to_project(project)
847 link_to_project(project)
847 assert_equal %(<a href="/projects/ecookbook/settings">eCookbook</a>),
848 assert_equal %(<a href="/projects/ecookbook/settings">eCookbook</a>),
848 link_to_project(project, :action => 'settings')
849 link_to_project(project, :action => 'settings')
849 assert_equal %(<a href="http://test.host/projects/ecookbook?jump=blah">eCookbook</a>),
850 assert_equal %(<a href="http://test.host/projects/ecookbook?jump=blah">eCookbook</a>),
850 link_to_project(project, {:only_path => false, :jump => 'blah'})
851 link_to_project(project, {:only_path => false, :jump => 'blah'})
851 assert_equal %(<a href="/projects/ecookbook/settings" class="project">eCookbook</a>),
852 assert_equal %(<a href="/projects/ecookbook/settings" class="project">eCookbook</a>),
852 link_to_project(project, {:action => 'settings'}, :class => "project")
853 link_to_project(project, {:action => 'settings'}, :class => "project")
853 end
854 end
854
855
855 def test_principals_options_for_select_with_users
856 def test_principals_options_for_select_with_users
856 users = [User.find(2), User.find(4)]
857 users = [User.find(2), User.find(4)]
857 assert_equal %(<option value="2">John Smith</option><option value="4">Robert Hill</option>),
858 assert_equal %(<option value="2">John Smith</option><option value="4">Robert Hill</option>),
858 principals_options_for_select(users)
859 principals_options_for_select(users)
859 end
860 end
860
861
861 def test_principals_options_for_select_with_selected
862 def test_principals_options_for_select_with_selected
862 users = [User.find(2), User.find(4)]
863 users = [User.find(2), User.find(4)]
863 assert_equal %(<option value="2">John Smith</option><option value="4" selected="selected">Robert Hill</option>),
864 assert_equal %(<option value="2">John Smith</option><option value="4" selected="selected">Robert Hill</option>),
864 principals_options_for_select(users, User.find(4))
865 principals_options_for_select(users, User.find(4))
865 end
866 end
866
867
867 def test_principals_options_for_select_with_users_and_groups
868 def test_principals_options_for_select_with_users_and_groups
868 users = [User.find(2), Group.find(11), User.find(4), Group.find(10)]
869 users = [User.find(2), Group.find(11), User.find(4), Group.find(10)]
869 assert_equal %(<option value="2">John Smith</option><option value="4">Robert Hill</option>) +
870 assert_equal %(<option value="2">John Smith</option><option value="4">Robert Hill</option>) +
870 %(<optgroup label="Groups"><option value="10">A Team</option><option value="11">B Team</option></optgroup>),
871 %(<optgroup label="Groups"><option value="10">A Team</option><option value="11">B Team</option></optgroup>),
871 principals_options_for_select(users)
872 principals_options_for_select(users)
872 end
873 end
873
874
874 def test_principals_options_for_select_with_empty_collection
875 def test_principals_options_for_select_with_empty_collection
875 assert_equal '', principals_options_for_select([])
876 assert_equal '', principals_options_for_select([])
876 end
877 end
877 end
878 end
General Comments 0
You need to be logged in to leave comments. Login now