##// END OF EJS Templates
Moved text formatting tests from application_helper tests to formatter tests....
Jean-Philippe Lang -
r5012:208d2d409087
parent child
Show More
@@ -1,776 +1,671
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2010 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require File.expand_path('../../../test_helper', __FILE__)
19 19
20 20 class ApplicationHelperTest < ActionView::TestCase
21 21
22 22 fixtures :projects, :roles, :enabled_modules, :users,
23 23 :repositories, :changesets,
24 24 :trackers, :issue_statuses, :issues, :versions, :documents,
25 25 :wikis, :wiki_pages, :wiki_contents,
26 26 :boards, :messages,
27 27 :attachments,
28 28 :enumerations
29 29
30 30 def setup
31 31 super
32 32 end
33 33
34 34 context "#link_to_if_authorized" do
35 35 context "authorized user" do
36 36 should "be tested"
37 37 end
38 38
39 39 context "unauthorized user" do
40 40 should "be tested"
41 41 end
42 42
43 43 should "allow using the :controller and :action for the target link" do
44 44 User.current = User.find_by_login('admin')
45 45
46 46 @project = Issue.first.project # Used by helper
47 47 response = link_to_if_authorized("By controller/action",
48 48 {:controller => 'issues', :action => 'edit', :id => Issue.first.id})
49 49 assert_match /href/, response
50 50 end
51 51
52 52 end
53 53
54 54 def test_auto_links
55 55 to_test = {
56 56 'http://foo.bar' => '<a class="external" href="http://foo.bar">http://foo.bar</a>',
57 57 'http://foo.bar/~user' => '<a class="external" href="http://foo.bar/~user">http://foo.bar/~user</a>',
58 58 'http://foo.bar.' => '<a class="external" href="http://foo.bar">http://foo.bar</a>.',
59 59 'https://foo.bar.' => '<a class="external" href="https://foo.bar">https://foo.bar</a>.',
60 60 'This is a link: http://foo.bar.' => 'This is a link: <a class="external" href="http://foo.bar">http://foo.bar</a>.',
61 61 'A link (eg. http://foo.bar).' => 'A link (eg. <a class="external" href="http://foo.bar">http://foo.bar</a>).',
62 62 '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>.',
63 63 'http://www.foo.bar/Test_(foobar)' => '<a class="external" href="http://www.foo.bar/Test_(foobar)">http://www.foo.bar/Test_(foobar)</a>',
64 64 '(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>)',
65 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 66 '(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>).',
67 67 '(see "inline link":http://www.foo.bar/Test_(foobar))' => '(see <a href="http://www.foo.bar/Test_(foobar)" class="external">inline link</a>)',
68 68 '(see "inline link":http://www.foo.bar/Test)' => '(see <a href="http://www.foo.bar/Test" class="external">inline link</a>)',
69 69 '(see "inline link":http://www.foo.bar/Test).' => '(see <a href="http://www.foo.bar/Test" class="external">inline link</a>).',
70 70 'www.foo.bar' => '<a class="external" href="http://www.foo.bar">www.foo.bar</a>',
71 71 '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>',
72 72 'http://foo.bar/page#125' => '<a class="external" href="http://foo.bar/page#125">http://foo.bar/page#125</a>',
73 73 'http://foo@www.bar.com' => '<a class="external" href="http://foo@www.bar.com">http://foo@www.bar.com</a>',
74 74 'http://foo:bar@www.bar.com' => '<a class="external" href="http://foo:bar@www.bar.com">http://foo:bar@www.bar.com</a>',
75 75 'ftp://foo.bar' => '<a class="external" href="ftp://foo.bar">ftp://foo.bar</a>',
76 76 'ftps://foo.bar' => '<a class="external" href="ftps://foo.bar">ftps://foo.bar</a>',
77 77 'sftp://foo.bar' => '<a class="external" href="sftp://foo.bar">sftp://foo.bar</a>',
78 78 # two exclamation marks
79 79 '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>',
80 80 # escaping
81 81 'http://foo"bar' => '<a class="external" href="http://foo&quot;bar">http://foo"bar</a>',
82 82 # wrap in angle brackets
83 83 '<http://foo.bar>' => '&lt;<a class="external" href="http://foo.bar">http://foo.bar</a>&gt;'
84 84 }
85 85 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
86 86 end
87 87
88 88 def test_auto_mailto
89 89 assert_equal '<p><a class="email" href="mailto:test@foo.bar">test@foo.bar</a></p>',
90 90 textilizable('test@foo.bar')
91 91 end
92 92
93 93 def test_inline_images
94 94 to_test = {
95 95 '!http://foo.bar/image.jpg!' => '<img src="http://foo.bar/image.jpg" alt="" />',
96 96 'floating !>http://foo.bar/image.jpg!' => 'floating <div style="float:right"><img src="http://foo.bar/image.jpg" alt="" /></div>',
97 97 'with class !(some-class)http://foo.bar/image.jpg!' => 'with class <img src="http://foo.bar/image.jpg" class="some-class" alt="" />',
98 98 # inline styles should be stripped
99 99 'with style !{width:100px;height100px}http://foo.bar/image.jpg!' => 'with style <img src="http://foo.bar/image.jpg" alt="" />',
100 100 '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" />',
101 101 '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;" />',
102 102 }
103 103 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
104 104 end
105 105
106 106 def test_inline_images_inside_tags
107 107 raw = <<-RAW
108 108 h1. !foo.png! Heading
109 109
110 110 Centered image:
111 111
112 112 p=. !bar.gif!
113 113 RAW
114 114
115 115 assert textilizable(raw).include?('<img src="foo.png" alt="" />')
116 116 assert textilizable(raw).include?('<img src="bar.gif" alt="" />')
117 117 end
118 118
119 119 def test_attached_images
120 120 to_test = {
121 121 'Inline image: !logo.gif!' => 'Inline image: <img src="/attachments/download/3" title="This is a logo" alt="This is a logo" />',
122 122 'Inline image: !logo.GIF!' => 'Inline image: <img src="/attachments/download/3" title="This is a logo" alt="This is a logo" />',
123 123 'No match: !ogo.gif!' => 'No match: <img src="ogo.gif" alt="" />',
124 124 'No match: !ogo.GIF!' => 'No match: <img src="ogo.GIF" alt="" />',
125 125 # link image
126 126 '!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>',
127 127 }
128 128 attachments = Attachment.find(:all)
129 129 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text, :attachments => attachments) }
130 130 end
131 131
132 132 def test_textile_external_links
133 133 to_test = {
134 134 'This is a "link":http://foo.bar' => 'This is a <a href="http://foo.bar" class="external">link</a>',
135 135 'This is an intern "link":/foo/bar' => 'This is an intern <a href="/foo/bar">link</a>',
136 136 '"link (Link title)":http://foo.bar' => '<a href="http://foo.bar" title="Link title" class="external">link</a>',
137 137 '"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>',
138 138 "This is not a \"Link\":\n\nAnother paragraph" => "This is not a \"Link\":</p>\n\n\n\t<p>Another paragraph",
139 139 # no multiline link text
140 140 "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",
141 141 # mailto link
142 142 "\"system administrator\":mailto:sysadmin@example.com?subject=redmine%20permissions" => "<a href=\"mailto:sysadmin@example.com?subject=redmine%20permissions\">system administrator</a>",
143 143 # two exclamation marks
144 144 '"a link":http://example.net/path!602815048C7B5C20!302.html' => '<a href="http://example.net/path!602815048C7B5C20!302.html" class="external">a link</a>',
145 145 # escaping
146 146 '"test":http://foo"bar' => '<a href="http://foo&quot;bar" class="external">test</a>',
147 147 }
148 148 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
149 149 end
150 150
151 151 def test_redmine_links
152 152 issue_link = link_to('#3', {:controller => 'issues', :action => 'show', :id => 3},
153 153 :class => 'issue status-1 priority-1 overdue', :title => 'Error 281 when updating a recipe (New)')
154 154
155 155 changeset_link = link_to('r1', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :rev => 1},
156 156 :class => 'changeset', :title => 'My very first commit')
157 157 changeset_link2 = link_to('r2', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :rev => 2},
158 158 :class => 'changeset', :title => 'This commit fixes #1, #2 and references #1 & #3')
159 159
160 160 document_link = link_to('Test document', {:controller => 'documents', :action => 'show', :id => 1},
161 161 :class => 'document')
162 162
163 163 version_link = link_to('1.0', {:controller => 'versions', :action => 'show', :id => 2},
164 164 :class => 'version')
165 165
166 166 message_url = {:controller => 'messages', :action => 'show', :board_id => 1, :id => 4}
167 167
168 168 project_url = {:controller => 'projects', :action => 'show', :id => 'subproject1'}
169 169
170 170 source_url = {:controller => 'repositories', :action => 'entry', :id => 'ecookbook', :path => ['some', 'file']}
171 171 source_url_with_ext = {:controller => 'repositories', :action => 'entry', :id => 'ecookbook', :path => ['some', 'file.ext']}
172 172
173 173 to_test = {
174 174 # tickets
175 175 '#3, [#3], (#3) and #3.' => "#{issue_link}, [#{issue_link}], (#{issue_link}) and #{issue_link}.",
176 176 # changesets
177 177 'r1' => changeset_link,
178 178 'r1.' => "#{changeset_link}.",
179 179 'r1, r2' => "#{changeset_link}, #{changeset_link2}",
180 180 'r1,r2' => "#{changeset_link},#{changeset_link2}",
181 181 # documents
182 182 'document#1' => document_link,
183 183 'document:"Test document"' => document_link,
184 184 # versions
185 185 'version#2' => version_link,
186 186 'version:1.0' => version_link,
187 187 'version:"1.0"' => version_link,
188 188 # source
189 189 'source:/some/file' => link_to('source:/some/file', source_url, :class => 'source'),
190 190 'source:/some/file.' => link_to('source:/some/file', source_url, :class => 'source') + ".",
191 191 'source:/some/file.ext.' => link_to('source:/some/file.ext', source_url_with_ext, :class => 'source') + ".",
192 192 'source:/some/file. ' => link_to('source:/some/file', source_url, :class => 'source') + ".",
193 193 'source:/some/file.ext. ' => link_to('source:/some/file.ext', source_url_with_ext, :class => 'source') + ".",
194 194 'source:/some/file, ' => link_to('source:/some/file', source_url, :class => 'source') + ",",
195 195 'source:/some/file@52' => link_to('source:/some/file@52', source_url.merge(:rev => 52), :class => 'source'),
196 196 'source:/some/file.ext@52' => link_to('source:/some/file.ext@52', source_url_with_ext.merge(:rev => 52), :class => 'source'),
197 197 'source:/some/file#L110' => link_to('source:/some/file#L110', source_url.merge(:anchor => 'L110'), :class => 'source'),
198 198 'source:/some/file.ext#L110' => link_to('source:/some/file.ext#L110', source_url_with_ext.merge(:anchor => 'L110'), :class => 'source'),
199 199 'source:/some/file@52#L110' => link_to('source:/some/file@52#L110', source_url.merge(:rev => 52, :anchor => 'L110'), :class => 'source'),
200 200 'export:/some/file' => link_to('export:/some/file', source_url.merge(:format => 'raw'), :class => 'source download'),
201 201 # message
202 202 'message#4' => link_to('Post 2', message_url, :class => 'message'),
203 203 'message#5' => link_to('RE: post 2', message_url.merge(:anchor => 'message-5', :r => 5), :class => 'message'),
204 204 # project
205 205 'project#3' => link_to('eCookbook Subproject 1', project_url, :class => 'project'),
206 206 'project:subproject1' => link_to('eCookbook Subproject 1', project_url, :class => 'project'),
207 207 'project:"eCookbook subProject 1"' => link_to('eCookbook Subproject 1', project_url, :class => 'project'),
208 208 # escaping
209 209 '!#3.' => '#3.',
210 210 '!r1' => 'r1',
211 211 '!document#1' => 'document#1',
212 212 '!document:"Test document"' => 'document:"Test document"',
213 213 '!version#2' => 'version#2',
214 214 '!version:1.0' => 'version:1.0',
215 215 '!version:"1.0"' => 'version:"1.0"',
216 216 '!source:/some/file' => 'source:/some/file',
217 217 # not found
218 218 '#0123456789' => '#0123456789',
219 219 # invalid expressions
220 220 'source:' => 'source:',
221 221 # url hash
222 222 "http://foo.bar/FAQ#3" => '<a class="external" href="http://foo.bar/FAQ#3">http://foo.bar/FAQ#3</a>',
223 223 }
224 224 @project = Project.find(1)
225 225 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text), "#{text} failed" }
226 226 end
227 227
228 228 def test_cross_project_redmine_links
229 229 source_link = link_to('ecookbook:source:/some/file', {:controller => 'repositories', :action => 'entry', :id => 'ecookbook', :path => ['some', 'file']},
230 230 :class => 'source')
231 231
232 232 changeset_link = link_to('ecookbook:r2', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :rev => 2},
233 233 :class => 'changeset', :title => 'This commit fixes #1, #2 and references #1 & #3')
234 234
235 235 to_test = {
236 236 # documents
237 237 'document:"Test document"' => 'document:"Test document"',
238 238 'ecookbook:document:"Test document"' => '<a href="/documents/1" class="document">Test document</a>',
239 239 'invalid:document:"Test document"' => 'invalid:document:"Test document"',
240 240 # versions
241 241 'version:"1.0"' => 'version:"1.0"',
242 242 'ecookbook:version:"1.0"' => '<a href="/versions/show/2" class="version">1.0</a>',
243 243 'invalid:version:"1.0"' => 'invalid:version:"1.0"',
244 244 # changeset
245 245 'r2' => 'r2',
246 246 'ecookbook:r2' => changeset_link,
247 247 'invalid:r2' => 'invalid:r2',
248 248 # source
249 249 'source:/some/file' => 'source:/some/file',
250 250 'ecookbook:source:/some/file' => source_link,
251 251 'invalid:source:/some/file' => 'invalid:source:/some/file',
252 252 }
253 253 @project = Project.find(3)
254 254 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text), "#{text} failed" }
255 255 end
256 256
257 257 def test_redmine_links_git_commit
258 258 changeset_link = link_to('abcd',
259 259 {
260 260 :controller => 'repositories',
261 261 :action => 'revision',
262 262 :id => 'subproject1',
263 263 :rev => 'abcd',
264 264 },
265 265 :class => 'changeset', :title => 'test commit')
266 266 to_test = {
267 267 'commit:abcd' => changeset_link,
268 268 }
269 269 @project = Project.find(3)
270 270 r = Repository::Git.create!(:project => @project, :url => '/tmp/test/git')
271 271 assert r
272 272 c = Changeset.new(:repository => r,
273 273 :committed_on => Time.now,
274 274 :revision => 'abcd',
275 275 :scmid => 'abcd',
276 276 :comments => 'test commit')
277 277 assert( c.save )
278 278 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
279 279 end
280 280
281 281 # TODO: Bazaar commit id contains mail address, so it contains '@' and '_'.
282 282 def test_redmine_links_darcs_commit
283 283 changeset_link = link_to('20080308225258-98289-abcd456efg.gz',
284 284 {
285 285 :controller => 'repositories',
286 286 :action => 'revision',
287 287 :id => 'subproject1',
288 288 :rev => '123',
289 289 },
290 290 :class => 'changeset', :title => 'test commit')
291 291 to_test = {
292 292 'commit:20080308225258-98289-abcd456efg.gz' => changeset_link,
293 293 }
294 294 @project = Project.find(3)
295 295 r = Repository::Darcs.create!(
296 296 :project => @project, :url => '/tmp/test/darcs',
297 297 :log_encoding => 'UTF-8')
298 298 assert r
299 299 c = Changeset.new(:repository => r,
300 300 :committed_on => Time.now,
301 301 :revision => '123',
302 302 :scmid => '20080308225258-98289-abcd456efg.gz',
303 303 :comments => 'test commit')
304 304 assert( c.save )
305 305 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
306 306 end
307 307
308 308 def test_redmine_links_mercurial_commit
309 309 changeset_link_rev = link_to('r123',
310 310 {
311 311 :controller => 'repositories',
312 312 :action => 'revision',
313 313 :id => 'subproject1',
314 314 :rev => '123' ,
315 315 },
316 316 :class => 'changeset', :title => 'test commit')
317 317 changeset_link_commit = link_to('abcd',
318 318 {
319 319 :controller => 'repositories',
320 320 :action => 'revision',
321 321 :id => 'subproject1',
322 322 :rev => 'abcd' ,
323 323 },
324 324 :class => 'changeset', :title => 'test commit')
325 325 to_test = {
326 326 'r123' => changeset_link_rev,
327 327 'commit:abcd' => changeset_link_commit,
328 328 }
329 329 @project = Project.find(3)
330 330 r = Repository::Mercurial.create!(:project => @project, :url => '/tmp/test')
331 331 assert r
332 332 c = Changeset.new(:repository => r,
333 333 :committed_on => Time.now,
334 334 :revision => '123',
335 335 :scmid => 'abcd',
336 336 :comments => 'test commit')
337 337 assert( c.save )
338 338 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
339 339 end
340 340
341 341 def test_attachment_links
342 342 attachment_link = link_to('error281.txt', {:controller => 'attachments', :action => 'download', :id => '1'}, :class => 'attachment')
343 343 to_test = {
344 344 'attachment:error281.txt' => attachment_link
345 345 }
346 346 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text, :attachments => Issue.find(3).attachments), "#{text} failed" }
347 347 end
348 348
349 349 def test_wiki_links
350 350 to_test = {
351 351 '[[CookBook documentation]]' => '<a href="/projects/ecookbook/wiki/CookBook_documentation" class="wiki-page">CookBook documentation</a>',
352 352 '[[Another page|Page]]' => '<a href="/projects/ecookbook/wiki/Another_page" class="wiki-page">Page</a>',
353 353 # link with anchor
354 354 '[[CookBook documentation#One-section]]' => '<a href="/projects/ecookbook/wiki/CookBook_documentation#One-section" class="wiki-page">CookBook documentation</a>',
355 355 '[[Another page#anchor|Page]]' => '<a href="/projects/ecookbook/wiki/Another_page#anchor" class="wiki-page">Page</a>',
356 356 # page that doesn't exist
357 357 '[[Unknown page]]' => '<a href="/projects/ecookbook/wiki/Unknown_page" class="wiki-page new">Unknown page</a>',
358 358 '[[Unknown page|404]]' => '<a href="/projects/ecookbook/wiki/Unknown_page" class="wiki-page new">404</a>',
359 359 # link to another project wiki
360 360 '[[onlinestore:]]' => '<a href="/projects/onlinestore/wiki" class="wiki-page">onlinestore</a>',
361 361 '[[onlinestore:|Wiki]]' => '<a href="/projects/onlinestore/wiki" class="wiki-page">Wiki</a>',
362 362 '[[onlinestore:Start page]]' => '<a href="/projects/onlinestore/wiki/Start_page" class="wiki-page">Start page</a>',
363 363 '[[onlinestore:Start page|Text]]' => '<a href="/projects/onlinestore/wiki/Start_page" class="wiki-page">Text</a>',
364 364 '[[onlinestore:Unknown page]]' => '<a href="/projects/onlinestore/wiki/Unknown_page" class="wiki-page new">Unknown page</a>',
365 365 # striked through link
366 366 '-[[Another page|Page]]-' => '<del><a href="/projects/ecookbook/wiki/Another_page" class="wiki-page">Page</a></del>',
367 367 '-[[Another page|Page]] link-' => '<del><a href="/projects/ecookbook/wiki/Another_page" class="wiki-page">Page</a> link</del>',
368 368 # escaping
369 369 '![[Another page|Page]]' => '[[Another page|Page]]',
370 370 # project does not exist
371 371 '[[unknowproject:Start]]' => '[[unknowproject:Start]]',
372 372 '[[unknowproject:Start|Page title]]' => '[[unknowproject:Start|Page title]]',
373 373 }
374 374 @project = Project.find(1)
375 375 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
376 376 end
377 377
378 378 def test_html_tags
379 379 to_test = {
380 380 "<div>content</div>" => "<p>&lt;div&gt;content&lt;/div&gt;</p>",
381 381 "<div class=\"bold\">content</div>" => "<p>&lt;div class=\"bold\"&gt;content&lt;/div&gt;</p>",
382 382 "<script>some script;</script>" => "<p>&lt;script&gt;some script;&lt;/script&gt;</p>",
383 383 # do not escape pre/code tags
384 384 "<pre>\nline 1\nline2</pre>" => "<pre>\nline 1\nline2</pre>",
385 385 "<pre><code>\nline 1\nline2</code></pre>" => "<pre><code>\nline 1\nline2</code></pre>",
386 386 "<pre><div>content</div></pre>" => "<pre>&lt;div&gt;content&lt;/div&gt;</pre>",
387 387 "HTML comment: <!-- no comments -->" => "<p>HTML comment: &lt;!-- no comments --&gt;</p>",
388 388 "<!-- opening comment" => "<p>&lt;!-- opening comment</p>",
389 389 # remove attributes except class
390 390 "<pre class='foo'>some text</pre>" => "<pre class='foo'>some text</pre>",
391 391 '<pre class="foo">some text</pre>' => '<pre class="foo">some text</pre>',
392 392 "<pre class='foo bar'>some text</pre>" => "<pre class='foo bar'>some text</pre>",
393 393 '<pre class="foo bar">some text</pre>' => '<pre class="foo bar">some text</pre>',
394 394 "<pre onmouseover='alert(1)'>some text</pre>" => "<pre>some text</pre>",
395 395 # xss
396 396 '<pre><code class=""onmouseover="alert(1)">text</code></pre>' => '<pre><code>text</code></pre>',
397 397 '<pre class=""onmouseover="alert(1)">text</pre>' => '<pre>text</pre>',
398 398 }
399 399 to_test.each { |text, result| assert_equal result, textilizable(text) }
400 400 end
401 401
402 402 def test_allowed_html_tags
403 403 to_test = {
404 404 "<pre>preformatted text</pre>" => "<pre>preformatted text</pre>",
405 405 "<notextile>no *textile* formatting</notextile>" => "no *textile* formatting",
406 406 "<notextile>this is <tag>a tag</tag></notextile>" => "this is &lt;tag&gt;a tag&lt;/tag&gt;"
407 407 }
408 408 to_test.each { |text, result| assert_equal result, textilizable(text) }
409 409 end
410 410
411 411 def test_pre_tags
412 412 raw = <<-RAW
413 413 Before
414 414
415 415 <pre>
416 416 <prepared-statement-cache-size>32</prepared-statement-cache-size>
417 417 </pre>
418 418
419 419 After
420 420 RAW
421 421
422 422 expected = <<-EXPECTED
423 423 <p>Before</p>
424 424 <pre>
425 425 &lt;prepared-statement-cache-size&gt;32&lt;/prepared-statement-cache-size&gt;
426 426 </pre>
427 427 <p>After</p>
428 428 EXPECTED
429 429
430 430 assert_equal expected.gsub(%r{[\r\n\t]}, ''), textilizable(raw).gsub(%r{[\r\n\t]}, '')
431 431 end
432 432
433 433 def test_pre_content_should_not_parse_wiki_and_redmine_links
434 434 raw = <<-RAW
435 435 [[CookBook documentation]]
436 436
437 437 #1
438 438
439 439 <pre>
440 440 [[CookBook documentation]]
441 441
442 442 #1
443 443 </pre>
444 444 RAW
445 445
446 446 expected = <<-EXPECTED
447 447 <p><a href="/projects/ecookbook/wiki/CookBook_documentation" class="wiki-page">CookBook documentation</a></p>
448 448 <p><a href="/issues/1" class="issue status-1 priority-1" title="Can't print recipes (New)">#1</a></p>
449 449 <pre>
450 450 [[CookBook documentation]]
451 451
452 452 #1
453 453 </pre>
454 454 EXPECTED
455 455
456 456 @project = Project.find(1)
457 457 assert_equal expected.gsub(%r{[\r\n\t]}, ''), textilizable(raw).gsub(%r{[\r\n\t]}, '')
458 458 end
459 459
460 460 def test_non_closing_pre_blocks_should_be_closed
461 461 raw = <<-RAW
462 462 <pre><code>
463 463 RAW
464 464
465 465 expected = <<-EXPECTED
466 466 <pre><code>
467 467 </code></pre>
468 468 EXPECTED
469 469
470 470 @project = Project.find(1)
471 471 assert_equal expected.gsub(%r{[\r\n\t]}, ''), textilizable(raw).gsub(%r{[\r\n\t]}, '')
472 472 end
473 473
474 474 def test_syntax_highlight
475 475 raw = <<-RAW
476 476 <pre><code class="ruby">
477 477 # Some ruby code here
478 478 </code></pre>
479 479 RAW
480 480
481 481 expected = <<-EXPECTED
482 482 <pre><code class="ruby syntaxhl"><span class=\"CodeRay\"><span class="no">1</span> <span class="c"># Some ruby code here</span></span>
483 483 </code></pre>
484 484 EXPECTED
485 485
486 486 assert_equal expected.gsub(%r{[\r\n\t]}, ''), textilizable(raw).gsub(%r{[\r\n\t]}, '')
487 487 end
488 488
489 489 def test_wiki_links_in_tables
490 490 to_test = {"|[[Page|Link title]]|[[Other Page|Other title]]|\n|Cell 21|[[Last page]]|" =>
491 491 '<tr><td><a href="/projects/ecookbook/wiki/Page" class="wiki-page new">Link title</a></td>' +
492 492 '<td><a href="/projects/ecookbook/wiki/Other_Page" class="wiki-page new">Other title</a></td>' +
493 493 '</tr><tr><td>Cell 21</td><td><a href="/projects/ecookbook/wiki/Last_page" class="wiki-page new">Last page</a></td></tr>'
494 494 }
495 495 @project = Project.find(1)
496 496 to_test.each { |text, result| assert_equal "<table>#{result}</table>", textilizable(text).gsub(/[\t\n]/, '') }
497 497 end
498 498
499 499 def test_text_formatting
500 500 to_test = {'*_+bold, italic and underline+_*' => '<strong><em><ins>bold, italic and underline</ins></em></strong>',
501 501 '(_text within parentheses_)' => '(<em>text within parentheses</em>)',
502 502 'a *Humane Web* Text Generator' => 'a <strong>Humane Web</strong> Text Generator',
503 503 '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>',
504 504 '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',
505 505 }
506 506 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
507 507 end
508 508
509 509 def test_wiki_horizontal_rule
510 510 assert_equal '<hr />', textilizable('---')
511 511 assert_equal '<p>Dashes: ---</p>', textilizable('Dashes: ---')
512 512 end
513 513
514 514 def test_footnotes
515 515 raw = <<-RAW
516 516 This is some text[1].
517 517
518 518 fn1. This is the foot note
519 519 RAW
520 520
521 521 expected = <<-EXPECTED
522 522 <p>This is some text<sup><a href=\"#fn1\">1</a></sup>.</p>
523 523 <p id="fn1" class="footnote"><sup>1</sup> This is the foot note</p>
524 524 EXPECTED
525 525
526 526 assert_equal expected.gsub(%r{[\r\n\t]}, ''), textilizable(raw).gsub(%r{[\r\n\t]}, '')
527 527 end
528 528
529 529 def test_table_of_content
530 530 raw = <<-RAW
531 531 {{toc}}
532 532
533 533 h1. Title
534 534
535 535 Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas sed libero.
536 536
537 537 h2. Subtitle with a [[Wiki]] link
538 538
539 539 Nullam commodo metus accumsan nulla. Curabitur lobortis dui id dolor.
540 540
541 541 h2. Subtitle with [[Wiki|another Wiki]] link
542 542
543 543 h2. Subtitle with %{color:red}red text%
544 544
545 545 <pre>
546 546 some code
547 547 </pre>
548 548
549 549 h3. Subtitle with *some* _modifiers_
550 550
551 551 h1. Another title
552 552
553 553 h3. An "Internet link":http://www.redmine.org/ inside subtitle
554 554
555 555 h2. "Project Name !/attachments/1234/logo_small.gif! !/attachments/5678/logo_2.png!":/projects/projectname/issues
556 556
557 557 RAW
558 558
559 559 expected = '<ul class="toc">' +
560 560 '<li><a href="#Title">Title</a>' +
561 561 '<ul>' +
562 562 '<li><a href="#Subtitle-with-a-Wiki-link">Subtitle with a Wiki link</a></li>' +
563 563 '<li><a href="#Subtitle-with-another-Wiki-link">Subtitle with another Wiki link</a></li>' +
564 564 '<li><a href="#Subtitle-with-red-text">Subtitle with red text</a>' +
565 565 '<ul>' +
566 566 '<li><a href="#Subtitle-with-some-modifiers">Subtitle with some modifiers</a></li>' +
567 567 '</ul>' +
568 568 '</li>' +
569 569 '</ul>' +
570 570 '</li>' +
571 571 '<li><a href="#Another-title">Another title</a>' +
572 572 '<ul>' +
573 573 '<li>' +
574 574 '<ul>' +
575 575 '<li><a href="#An-Internet-link-inside-subtitle">An Internet link inside subtitle</a></li>' +
576 576 '</ul>' +
577 577 '</li>' +
578 578 '<li><a href="#Project-Name">Project Name</a></li>' +
579 579 '</ul>' +
580 580 '</li>' +
581 581 '</ul>'
582 582
583 583 @project = Project.find(1)
584 584 assert textilizable(raw).gsub("\n", "").include?(expected), textilizable(raw)
585 585 end
586 586
587 587 def test_table_of_content_should_contain_included_page_headings
588 588 raw = <<-RAW
589 589 {{toc}}
590 590
591 591 h1. Included
592 592
593 593 {{include(Child_1)}}
594 594 RAW
595 595
596 596 expected = '<ul class="toc">' +
597 597 '<li><a href="#Included">Included</a></li>' +
598 598 '<li><a href="#Child-page-1">Child page 1</a></li>' +
599 599 '</ul>'
600 600
601 601 @project = Project.find(1)
602 602 assert textilizable(raw).gsub("\n", "").include?(expected)
603 603 end
604 604
605 def test_blockquote
606 # orig raw text
607 raw = <<-RAW
608 John said:
609 > Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas sed libero.
610 > Nullam commodo metus accumsan nulla. Curabitur lobortis dui id dolor.
611 > * Donec odio lorem,
612 > * sagittis ac,
613 > * malesuada in,
614 > * adipiscing eu, dolor.
615 >
616 > >Nulla varius pulvinar diam. Proin id arcu id lorem scelerisque condimentum. Proin vehicula turpis vitae lacus.
617 > Proin a tellus. Nam vel neque.
618
619 He's right.
620 RAW
621
622 # expected html
623 expected = <<-EXPECTED
624 <p>John said:</p>
625 <blockquote>
626 Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas sed libero.
627 Nullam commodo metus accumsan nulla. Curabitur lobortis dui id dolor.
628 <ul>
629 <li>Donec odio lorem,</li>
630 <li>sagittis ac,</li>
631 <li>malesuada in,</li>
632 <li>adipiscing eu, dolor.</li>
633 </ul>
634 <blockquote>
635 <p>Nulla varius pulvinar diam. Proin id arcu id lorem scelerisque condimentum. Proin vehicula turpis vitae lacus.</p>
636 </blockquote>
637 <p>Proin a tellus. Nam vel neque.</p>
638 </blockquote>
639 <p>He's right.</p>
640 EXPECTED
641
642 assert_equal expected.gsub(%r{\s+}, ''), textilizable(raw).gsub(%r{\s+}, '')
643 end
644
645 def test_table
646 raw = <<-RAW
647 This is a table with empty cells:
648
649 |cell11|cell12||
650 |cell21||cell23|
651 |cell31|cell32|cell33|
652 RAW
653
654 expected = <<-EXPECTED
655 <p>This is a table with empty cells:</p>
656
657 <table>
658 <tr><td>cell11</td><td>cell12</td><td></td></tr>
659 <tr><td>cell21</td><td></td><td>cell23</td></tr>
660 <tr><td>cell31</td><td>cell32</td><td>cell33</td></tr>
661 </table>
662 EXPECTED
663
664 assert_equal expected.gsub(%r{\s+}, ''), textilizable(raw).gsub(%r{\s+}, '')
665 end
666
667 def test_table_with_line_breaks
668 raw = <<-RAW
669 This is a table with line breaks:
670
671 |cell11
672 continued|cell12||
673 |-cell21-||cell23
674 cell23 line2
675 cell23 *line3*|
676 |cell31|cell32
677 cell32 line2|cell33|
678
679 RAW
680
681 expected = <<-EXPECTED
682 <p>This is a table with line breaks:</p>
683
684 <table>
685 <tr>
686 <td>cell11<br />continued</td>
687 <td>cell12</td>
688 <td></td>
689 </tr>
690 <tr>
691 <td><del>cell21</del></td>
692 <td></td>
693 <td>cell23<br/>cell23 line2<br/>cell23 <strong>line3</strong></td>
694 </tr>
695 <tr>
696 <td>cell31</td>
697 <td>cell32<br/>cell32 line2</td>
698 <td>cell33</td>
699 </tr>
700 </table>
701 EXPECTED
702
703 assert_equal expected.gsub(%r{\s+}, ''), textilizable(raw).gsub(%r{\s+}, '')
704 end
705
706 def test_textile_should_not_mangle_brackets
707 assert_equal '<p>[msg1][msg2]</p>', textilizable('[msg1][msg2]')
708 end
709
710 605 def test_default_formatter
711 606 Setting.text_formatting = 'unknown'
712 607 text = 'a *link*: http://www.example.net/'
713 608 assert_equal '<p>a *link*: <a href="http://www.example.net/">http://www.example.net/</a></p>', textilizable(text)
714 609 Setting.text_formatting = 'textile'
715 610 end
716 611
717 612 def test_due_date_distance_in_words
718 613 to_test = { Date.today => 'Due in 0 days',
719 614 Date.today + 1 => 'Due in 1 day',
720 615 Date.today + 100 => 'Due in about 3 months',
721 616 Date.today + 20000 => 'Due in over 54 years',
722 617 Date.today - 1 => '1 day late',
723 618 Date.today - 100 => 'about 3 months late',
724 619 Date.today - 20000 => 'over 54 years late',
725 620 }
726 621 ::I18n.locale = :en
727 622 to_test.each do |date, expected|
728 623 assert_equal expected, due_date_distance_in_words(date)
729 624 end
730 625 end
731 626
732 627 def test_avatar
733 628 # turn on avatars
734 629 Setting.gravatar_enabled = '1'
735 630 assert avatar(User.find_by_mail('jsmith@somenet.foo')).include?(Digest::MD5.hexdigest('jsmith@somenet.foo'))
736 631 assert avatar('jsmith <jsmith@somenet.foo>').include?(Digest::MD5.hexdigest('jsmith@somenet.foo'))
737 632 assert_nil avatar('jsmith')
738 633 assert_nil avatar(nil)
739 634
740 635 # turn off avatars
741 636 Setting.gravatar_enabled = '0'
742 637 assert_equal '', avatar(User.find_by_mail('jsmith@somenet.foo'))
743 638 end
744 639
745 640 def test_link_to_user
746 641 user = User.find(2)
747 642 t = link_to_user(user)
748 643 assert_equal "<a href=\"/users/2\">#{ user.name }</a>", t
749 644 end
750 645
751 646 def test_link_to_user_should_not_link_to_locked_user
752 647 user = User.find(5)
753 648 assert user.locked?
754 649 t = link_to_user(user)
755 650 assert_equal user.name, t
756 651 end
757 652
758 653 def test_link_to_user_should_not_link_to_anonymous
759 654 user = User.anonymous
760 655 assert user.anonymous?
761 656 t = link_to_user(user)
762 657 assert_equal ::I18n.t(:label_user_anonymous), t
763 658 end
764 659
765 660 def test_link_to_project
766 661 project = Project.find(1)
767 662 assert_equal %(<a href="/projects/ecookbook">eCookbook</a>),
768 663 link_to_project(project)
769 664 assert_equal %(<a href="/projects/ecookbook/settings">eCookbook</a>),
770 665 link_to_project(project, :action => 'settings')
771 666 assert_equal %(<a href="http://test.host/projects/ecookbook?jump=blah">eCookbook</a>),
772 667 link_to_project(project, {:only_path => false, :jump => 'blah'})
773 668 assert_equal %(<a href="/projects/ecookbook/settings" class="project">eCookbook</a>),
774 669 link_to_project(project, {:action => 'settings'}, :class => "project")
775 670 end
776 671 end
@@ -1,102 +1,211
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2010 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require File.expand_path('../../../../../test_helper', __FILE__)
19 19
20 20 class Redmine::WikiFormatting::TextileFormatterTest < HelperTestCase
21 21
22 22 def setup
23 23 @formatter = Redmine::WikiFormatting::Textile::Formatter
24 24 end
25 25
26 26 MODIFIERS = {
27 27 "*" => 'strong', # bold
28 28 "_" => 'em', # italic
29 29 "+" => 'ins', # underline
30 30 "-" => 'del', # deleted
31 31 "^" => 'sup', # superscript
32 32 "~" => 'sub' # subscript
33 33 }
34 34
35 35 def test_modifiers
36 36 assert_html_output(
37 37 '*bold*' => '<strong>bold</strong>',
38 38 'before *bold*' => 'before <strong>bold</strong>',
39 39 '*bold* after' => '<strong>bold</strong> after',
40 40 '*two words*' => '<strong>two words</strong>',
41 41 '*two*words*' => '<strong>two*words</strong>',
42 42 '*two * words*' => '<strong>two * words</strong>',
43 43 '*two* *words*' => '<strong>two</strong> <strong>words</strong>',
44 44 '*(two)* *(words)*' => '<strong>(two)</strong> <strong>(words)</strong>',
45 45 # with class
46 46 '*(foo)two words*' => '<strong class="foo">two words</strong>'
47 47 )
48 48 end
49 49
50 50 def test_modifiers_combination
51 51 MODIFIERS.each do |m1, tag1|
52 52 MODIFIERS.each do |m2, tag2|
53 53 next if m1 == m2
54 54 text = "#{m2}#{m1}Phrase modifiers#{m1}#{m2}"
55 55 html = "<#{tag2}><#{tag1}>Phrase modifiers</#{tag1}></#{tag2}>"
56 56 assert_html_output text => html
57 57 end
58 58 end
59 59 end
60 60
61 61 def test_inline_code
62 62 assert_html_output(
63 63 'this is @some code@' => 'this is <code>some code</code>',
64 64 '@<Location /redmine>@' => '<code>&lt;Location /redmine&gt;</code>'
65 65 )
66 66 end
67 67
68 68 def test_escaping
69 69 assert_html_output(
70 70 'this is a <script>' => 'this is a &lt;script&gt;'
71 71 )
72 72 end
73 73
74 74 def test_use_of_backslashes_followed_by_numbers_in_headers
75 75 assert_html_output({
76 76 'h1. 2009\02\09' => '<h1>2009\02\09</h1>'
77 77 }, false)
78 78 end
79 79
80 80 def test_double_dashes_should_not_strikethrough
81 81 assert_html_output(
82 82 'double -- dashes -- test' => 'double -- dashes -- test',
83 83 'double -- *dashes* -- test' => 'double -- <strong>dashes</strong> -- test'
84 84 )
85 85 end
86 86
87 87 def test_acronyms
88 88 assert_html_output(
89 89 'this is an acronym: GPL(General Public License)' => 'this is an acronym: <acronym title="General Public License">GPL</acronym>',
90 90 '2 letters JP(Jean-Philippe) acronym' => '2 letters <acronym title="Jean-Philippe">JP</acronym> acronym',
91 91 'GPL(This is a double-quoted "title")' => '<acronym title="This is a double-quoted &quot;title&quot;">GPL</acronym>'
92 92 )
93 93 end
94 94
95 def test_blockquote
96 # orig raw text
97 raw = <<-RAW
98 John said:
99 > Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas sed libero.
100 > Nullam commodo metus accumsan nulla. Curabitur lobortis dui id dolor.
101 > * Donec odio lorem,
102 > * sagittis ac,
103 > * malesuada in,
104 > * adipiscing eu, dolor.
105 >
106 > >Nulla varius pulvinar diam. Proin id arcu id lorem scelerisque condimentum. Proin vehicula turpis vitae lacus.
107 > Proin a tellus. Nam vel neque.
108
109 He's right.
110 RAW
111
112 # expected html
113 expected = <<-EXPECTED
114 <p>John said:</p>
115 <blockquote>
116 Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas sed libero.
117 Nullam commodo metus accumsan nulla. Curabitur lobortis dui id dolor.
118 <ul>
119 <li>Donec odio lorem,</li>
120 <li>sagittis ac,</li>
121 <li>malesuada in,</li>
122 <li>adipiscing eu, dolor.</li>
123 </ul>
124 <blockquote>
125 <p>Nulla varius pulvinar diam. Proin id arcu id lorem scelerisque condimentum. Proin vehicula turpis vitae lacus.</p>
126 </blockquote>
127 <p>Proin a tellus. Nam vel neque.</p>
128 </blockquote>
129 <p>He's right.</p>
130 EXPECTED
131
132 assert_equal expected.gsub(%r{\s+}, ''), to_html(raw).gsub(%r{\s+}, '')
133 end
134
135 def test_table
136 raw = <<-RAW
137 This is a table with empty cells:
138
139 |cell11|cell12||
140 |cell21||cell23|
141 |cell31|cell32|cell33|
142 RAW
143
144 expected = <<-EXPECTED
145 <p>This is a table with empty cells:</p>
146
147 <table>
148 <tr><td>cell11</td><td>cell12</td><td></td></tr>
149 <tr><td>cell21</td><td></td><td>cell23</td></tr>
150 <tr><td>cell31</td><td>cell32</td><td>cell33</td></tr>
151 </table>
152 EXPECTED
153
154 assert_equal expected.gsub(%r{\s+}, ''), to_html(raw).gsub(%r{\s+}, '')
155 end
156
157 def test_table_with_line_breaks
158 raw = <<-RAW
159 This is a table with line breaks:
160
161 |cell11
162 continued|cell12||
163 |-cell21-||cell23
164 cell23 line2
165 cell23 *line3*|
166 |cell31|cell32
167 cell32 line2|cell33|
168
169 RAW
170
171 expected = <<-EXPECTED
172 <p>This is a table with line breaks:</p>
173
174 <table>
175 <tr>
176 <td>cell11<br />continued</td>
177 <td>cell12</td>
178 <td></td>
179 </tr>
180 <tr>
181 <td><del>cell21</del></td>
182 <td></td>
183 <td>cell23<br/>cell23 line2<br/>cell23 <strong>line3</strong></td>
184 </tr>
185 <tr>
186 <td>cell31</td>
187 <td>cell32<br/>cell32 line2</td>
188 <td>cell33</td>
189 </tr>
190 </table>
191 EXPECTED
192
193 assert_equal expected.gsub(%r{\s+}, ''), to_html(raw).gsub(%r{\s+}, '')
194 end
195
196 def test_textile_should_not_mangle_brackets
197 assert_equal '<p>[msg1][msg2]</p>', to_html('[msg1][msg2]')
198 end
199
95 200 private
96 201
97 202 def assert_html_output(to_test, expect_paragraph = true)
98 203 to_test.each do |text, expected|
99 204 assert_equal(( expect_paragraph ? "<p>#{expected}</p>" : expected ), @formatter.new(text).to_html, "Formatting the following text failed:\n===\n#{text}\n===\n")
100 205 end
101 206 end
207
208 def to_html(text)
209 @formatter.new(text).to_html
210 end
102 211 end
General Comments 0
You need to be logged in to leave comments. Login now