2 # Copyright 2007-2012 Wincent Colaiuta. All rights reserved.
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are met:
7 # 1. Redistributions of source code must retain the above copyright notice,
8 # this list of conditions and the following disclaimer.
9 # 2. Redistributions in binary form must reproduce the above copyright notice,
10 # this list of conditions and the following disclaimer in the documentation
11 # and/or other materials provided with the distribution.
13 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
17 # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
23 # POSSIBILITY OF SUCH DAMAGE.
27 describe Wikitext::Parser, 'external links' do
29 @parser = Wikitext::Parser.new
32 it 'should format valid external HTTP links' do
33 expected = %Q{<p><a href="http://google.com/" class="external">Google</a></p>\n}
34 @parser.parse('[http://google.com/ Google]').should == expected
37 it 'should format valid external HTTPS links' do
38 expected = %Q{<p><a href="https://google.com/" class="external">Google</a></p>\n}
39 @parser.parse('[https://google.com/ Google]').should == expected
42 it 'should format valid external FTP links' do
43 expected = %Q{<p><a href="ftp://google.com/" class="external">Google</a></p>\n}
44 @parser.parse('[ftp://google.com/ Google]').should == expected
47 it 'should format valid external SVN links' do
48 expected = %Q{<p><a href="svn://google.com/" class="external">Google</a></p>\n}
49 @parser.parse('[svn://google.com/ Google]').should == expected
52 it 'formats valid external mailto links' do
53 expected = %{<p><a href="mailto:user@example.com" class="mailto">john</a></p>\n}
54 @parser.parse('[mailto:user@example.com john]').should == expected
57 it 'does not treat raw email addresses as valid link targets' do
58 expected = %{<p>[<a href="mailto:user@example.com" class="mailto">user@example.com</a> john]</p>\n}
59 @parser.parse('[user@example.com john]').should == expected
62 it 'formats external mailto links where the linktext is itself an email' do
63 # reported here: https://wincent.com/issues/1955
64 expected = %{<p><a href="mailto:user@example.com" class="mailto">user@example.com</a></p>\n}
65 @parser.parse('[mailto:user@example.com user@example.com]').should == expected
67 # just in case that example seems a little contrived and trivial (you could
68 # work around it by instead just writing "user@example.com" in your markup),
69 # here's a more obviously useful one
70 expected = %{<p><a href="mailto:user@example.com" class="mailto">email me at user@example.com for more info</a></p>\n}
71 @parser.parse('[mailto:user@example.com email me at user@example.com for more info]').should == expected
74 it 'allows email addreses in link text' do
75 # more general case of bug reported here: https://wincent.com/issues/1955
76 expected = %{<p><a href="http://google.com/?q=user@example.com" class="external">Google for user@example.com</a></p>\n}
77 @parser.parse('[http://google.com/?q=user@example.com Google for user@example.com]').should == expected
81 it 'should format absolute path links' do
82 expected = %Q{<p><a href="/foo/bar">fb</a></p>\n} # note no "external" class
83 @parser.parse('[/foo/bar fb]').should == expected
86 it 'should format deeply nested absolute path links' do
87 expected = %Q{<p><a href="/foo/bar/baz/bing">fb</a></p>\n} # note no "external" class
88 @parser.parse('[/foo/bar/baz/bing fb]').should == expected
91 it 'should format minimal absolute path links' do
92 expected = %Q{<p><a href="/">fb</a></p>\n} # note no "external" class
93 @parser.parse('[/ fb]').should == expected
96 it 'should format absolute path links with trailing slashes' do
97 expected = %Q{<p><a href="/foo/bar/">fb</a></p>\n} # note no "external" class
98 @parser.parse('[/foo/bar/ fb]').should == expected
101 it 'should not format relative path links' do
102 # relative paths don't make sense in wikitext because
103 # they could be displayed anywhere (eg. /wiki/article, /dashboard/ etc)
104 expected = %Q{<p>[foo/bar fb]</p>\n}
105 @parser.parse('[foo/bar fb]').should == expected
108 it 'should treat runs of spaces after the link target as a single space' do
109 expected = %Q{<p><a href="http://google.com/" class="external">Google</a></p>\n}
110 @parser.parse('[http://google.com/ Google]').should == expected
113 it 'should not treat runs of spaces within the link text as a single space' do
114 expected = %Q{<p><a href="http://google.com/" class="external">Google search</a></p>\n}
115 @parser.parse('[http://google.com/ Google search]').should == expected
118 it 'should format a link with emphasis in the link text' do
119 expected = %Q{<p><a href="http://google.com/" class="external">Google <em>rocks</em></a></p>\n}
120 @parser.parse("[http://google.com/ Google ''rocks'']").should == expected
123 it "should automatically close unmatched '' tags in the link text" do
124 expected = %Q{<p><a href="http://google.com/" class="external">Google <em>SOC</em></a></p>\n}
125 @parser.parse("[http://google.com/ Google ''SOC]").should == expected
128 it 'should format a link with strong formatting in the link text' do
129 expected = %Q{<p><a href="http://google.com/" class="external"><strong>Google</strong> rocks</a></p>\n}
130 @parser.parse("[http://google.com/ '''Google''' rocks]").should == expected
133 it "should automatically close unmatched ''' tags in the link text" do
134 expected = %Q{<p><a href="http://google.com/" class="external">Google <strong>SOC</strong></a></p>\n}
135 @parser.parse("[http://google.com/ Google '''SOC]").should == expected
138 it 'should format a link with <tt></tt> tags in the link text' do
139 expected = %Q{<p><a href="http://google.com/" class="external">Google <code>SOC</code></a></p>\n}
140 @parser.parse("[http://google.com/ Google <tt>SOC</tt>]").should == expected
143 it 'should automatically close unmatched <tt> tags in the link text' do
144 expected = %Q{<p><a href="http://google.com/" class="external">Google <code>SOC</code></a></p>\n}
145 @parser.parse("[http://google.com/ Google <tt>SOC]").should == expected
148 it 'should format a link with strong and emphasis in the link text' do
149 expected = %Q{<p><a href="http://google.com/" class="external">Google <strong><em>rocks</em></strong></a></p>\n}
150 @parser.parse("[http://google.com/ Google '''''rocks''''']").should == expected
153 it "should automatically close unmatched ''''' tags in the link text" do
154 expected = %Q{<p><a href="http://google.com/" class="external">Google <strong><em>SOC</em></strong></a></p>\n}
155 @parser.parse("[http://google.com/ Google '''''SOC]").should == expected
158 it 'should respect "<nowiki></nowiki>" tags inside the link text' do
159 expected = %Q{<p><a href="http://google.com/" class="external">Google ] rocks</a></p>\n}
160 @parser.parse("[http://google.com/ Google <nowiki>]</nowiki> rocks]").should == expected # was a bug
162 expected = %Q{<p><a href="http://google.com/" class="external">Google [ rocks</a></p>\n}
163 @parser.parse("[http://google.com/ Google <nowiki>[</nowiki> rocks]").should == expected # was a bug
166 it 'should pass "[" in link text through literally' do
167 expected = %Q{<p><a href="http://google.com/" class="external">Google [ rocks</a></p>\n}
168 @parser.parse("[http://google.com/ Google [ rocks]").should == expected # was a bug
171 it 'should pass "[[" in link text through literally' do
172 expected = %Q{<p><a href="http://google.com/" class="external">Google [[ rocks</a></p>\n}
173 @parser.parse("[http://google.com/ Google [[ rocks]").should == expected # was a bug
176 it 'should pass "]]" in link text through literally' do
177 # note how "]]" is treated as a single token, not as a "]" which closes the link followed by another ("] rocks]")
178 expected = %Q{<p><a href="http://google.com/" class="external">Google ]] rocks</a></p>\n}
179 @parser.parse("[http://google.com/ Google ]] rocks]").should == expected # was a bug
182 it 'should pass through ASCII entities in the link text' do
183 expected = %Q{<p><a href="http://google.com/" class="external">Google "SOC"</a></p>\n} # QUOT
184 @parser.parse(%Q{[http://google.com/ Google "SOC"]}).should == expected
185 expected = %Q{<p><a href="http://google.com/" class="external">Google <SOC></a></p>\n} # LESS, GREATER
186 @parser.parse(%Q{[http://google.com/ Google <SOC>]}).should == expected
187 expected = %Q{<p><a href="http://google.com/" class="external">Google & SOC</a></p>\n} # AMP
188 @parser.parse(%Q{[http://google.com/ Google & SOC]}).should == expected
191 it 'should pass through named entities in the link text' do
192 expected = %Q{<p><a href="http://google.com/" class="external">Google €</a></p>\n}
193 @parser.parse(%Q{[http://google.com/ Google €]}).should == expected
196 it 'should pass through decimal entities in the link text' do
197 expected = %Q{<p><a href="http://google.com/" class="external">Google €</a></p>\n}
198 @parser.parse(%Q{[http://google.com/ Google €]}).should == expected
201 it 'should pass through hexadecimal entities in the link text' do
202 expected = %Q{<p><a href="http://google.com/" class="external">Google €</a></p>\n}
203 @parser.parse(%Q{[http://google.com/ Google €]}).should == expected
206 it 'should convert non-ASCII characters in the link text into entities' do
207 expected = %Q{<p><a href="http://google.com/" class="external">Google €</a></p>\n}
208 @parser.parse(%Q{[http://google.com/ Google €]}).should == expected
211 it 'should pass through unexpected external link end tokens literally' do
212 @parser.parse('foo ] bar').should == "<p>foo ] bar</p>\n" # in plain scope
213 @parser.parse("foo '']'' bar").should == "<p>foo <em>]</em> bar</p>\n" # in EM scope
214 @parser.parse("foo ''']''' bar").should == "<p>foo <strong>]</strong> bar</p>\n" # in STRONG scope
215 @parser.parse("foo ''''']''''' bar").should == "<p>foo <strong><em>]</em></strong> bar</p>\n" # in STRONG_EM scope
216 @parser.parse('foo <tt>]</tt> bar').should == "<p>foo <code>]</code> bar</p>\n" # in TT scope
217 @parser.parse('= foo ] bar =').should == "<h1>foo ] bar</h1>\n" # in H1 scope
218 @parser.parse('== foo ] bar ==').should == "<h2>foo ] bar</h2>\n" # in H2 scope
219 @parser.parse('=== foo ] bar ===').should == "<h3>foo ] bar</h3>\n" # in H3 scope
220 @parser.parse('==== foo ] bar ====').should == "<h4>foo ] bar</h4>\n" # in H4 scope
221 @parser.parse('===== foo ] bar =====').should == "<h5>foo ] bar</h5>\n" # in H5 scope
222 @parser.parse('====== foo ] bar ======').should == "<h6>foo ] bar</h6>\n" # in H6 scope
223 @parser.parse('> ]').should == "<blockquote>\n <p>]</p>\n</blockquote>\n" # in BLOCKQUOTE scope
226 describe '#external_link_rel attribute' do
227 it 'defaults to nil (external links do not have a rel attribute)' do
228 @parser.parse('http://google.com/').should == \
229 %Q{<p><a href="http://google.com/" class="external">http://google.com/</a></p>\n}
232 context 'set at parse time' do
233 it 'uses the rel attribute in external links' do
234 @parser.parse('http://google.com/', :external_link_rel => 'nofollow').should == \
235 %Q{<p><a href="http://google.com/" class="external" rel="nofollow">http://google.com/</a></p>\n}
239 context 'set at initialization time' do
240 let (:parser) { Wikitext::Parser.new :external_link_rel => 'nofollow' }
242 it 'uses the rel attribute in external links' do
243 parser.parse('http://google.com/').should == \
244 %Q{<p><a href="http://google.com/" class="external" rel="nofollow">http://google.com/</a></p>\n}
247 it 'is overrideable' do
248 parser.parse('http://google.com/', :external_link_rel => nil).should == \
249 %Q{<p><a href="http://google.com/" class="external">http://google.com/</a></p>\n}
253 context 'set via an accessor' do
255 parser = Wikitext::Parser.new
256 parser.external_link_rel = 'nofollow'
260 it 'uses the rel attribute in external links' do
261 parser.parse('http://google.com/').should == \
262 %Q{<p><a href="http://google.com/" class="external" rel="nofollow">http://google.com/</a></p>\n}
267 describe 'questionable links' do
268 it 'should handle links which contain an embedded [ character' do
269 # note that [ is allowed in the link text, although the result may be unexpected to the user
270 expected = %Q{<p><a href="http://google.com/" class="external">[hello</a></p>\n}
271 @parser.parse("[http://google.com/ [hello]").should == expected
274 it 'should handle links which contain an embedded ] character' do
275 # note how the first ] terminates the link
276 expected = %Q{<p><a href="http://google.com/" class="external">[hello</a> world]</p>\n}
277 @parser.parse("[http://google.com/ [hello] world]").should == expected
280 it 'should handle links which contain an embedded [[ character' do
281 # note that [[ is allowed in the link text
282 expected = %Q{<p><a href="http://google.com/" class="external">[[hello</a></p>\n}
283 @parser.parse("[http://google.com/ [[hello]").should == expected
286 it 'should handle links which contain an embedded ]] character' do
287 # note how this time ]] does not terminate the link because it is tokenized as LINK_END rather than EXT_LINK_END
288 expected = %Q{<p><a href="http://google.com/" class="external">[[hello]] world</a></p>\n}
289 @parser.parse("[http://google.com/ [[hello]] world]").should == expected
292 it 'should allow URIs in the link text' do
293 # not sure why you'd want to do this, but...
294 expected = %Q{<p><a href="http://example.net/" class="external">hello http://example.com/ world</a></p>\n}
295 @parser.parse('[http://example.net/ hello http://example.com/ world]').should == expected
299 describe 'invalid links' do
300 it "should pass through links which don't have a valid target" do
301 expected = "<p>[well]</p>\n"
302 @parser.parse("[well]").should == expected
305 it "should pass through links which don't have any target" do
306 expected = "<p>[]</p>\n"
307 @parser.parse('[]').should == expected
310 it 'should pass through unterminated links (EOF)' do
311 expected = "<p>[</p>\n"
312 @parser.parse('[').should == expected
314 expected = "<p>[well</p>\n"
315 @parser.parse("[well").should == expected
317 expected = %Q{<p>[<a href="http://example.com/" class="external">http://example.com/</a></p>\n}
318 @parser.parse("[http://example.com/").should == expected
320 expected = %Q{<p>[<a href="http://example.com/" class="external">http://example.com/</a> </p>\n}
321 @parser.parse("[http://example.com/ ").should == expected
323 expected = %Q{<p>[<a href="http://example.com/" class="external">http://example.com/</a> visit</p>\n}
324 @parser.parse("[http://example.com/ visit").should == expected # was a bug
326 expected = %Q{<h6>[<a href="http://example.com/" class="external">http://example.com/</a> visit</h6>\n}
327 @parser.parse("====== [http://example.com/ visit").should == expected # was a bug
329 expected = %Q{<h5>[<a href="http://example.com/" class="external">http://example.com/</a> visit</h5>\n}
330 @parser.parse("===== [http://example.com/ visit").should == expected # was a bug
332 expected = %Q{<h4>[<a href="http://example.com/" class="external">http://example.com/</a> visit</h4>\n}
333 @parser.parse("==== [http://example.com/ visit").should == expected # was a bug
335 expected = %Q{<h3>[<a href="http://example.com/" class="external">http://example.com/</a> visit</h3>\n}
336 @parser.parse("=== [http://example.com/ visit").should == expected # was a bug
338 expected = %Q{<h2>[<a href="http://example.com/" class="external">http://example.com/</a> visit</h2>\n}
339 @parser.parse("== [http://example.com/ visit").should == expected # was a bug
341 expected = %Q{<h1>[<a href="http://example.com/" class="external">http://example.com/</a> visit</h1>\n}
342 @parser.parse("= [http://example.com/ visit").should == expected # was a bug
344 expected = %Q{<p>[<a href="http://example.com/" class="external">http://example.com/</a> ...</p>\n}
345 @parser.parse("[http://example.com/ <nowiki>...\n").should == expected
348 it 'should pass through unterminated links (end-of-line)' do
349 expected = "<p>[</p>\n"
350 @parser.parse("[\n").should == expected
352 expected = "<p>[well</p>\n"
353 @parser.parse("[well\n").should == expected
355 expected = %Q{<p>[<a href="http://example.com/" class="external">http://example.com/</a></p>\n}
356 @parser.parse("[http://example.com/\n").should == expected
358 expected = %Q{<p>[<a href="http://example.com/" class="external">http://example.com/</a> </p>\n}
359 @parser.parse("[http://example.com/ \n").should == expected
361 expected = %Q{<p>[<a href="http://example.com/" class="external">http://example.com/</a> visit</p>\n}
362 @parser.parse("[http://example.com/ visit\n").should == expected # was a bug
364 expected = %Q{<h6>[<a href="http://example.com/" class="external">http://example.com/</a> visit</h6>\n}
365 @parser.parse("====== [http://example.com/ visit\n").should == expected # was a bug
367 expected = %Q{<h5>[<a href="http://example.com/" class="external">http://example.com/</a> visit</h5>\n}
368 @parser.parse("===== [http://example.com/ visit\n").should == expected # was a bug
370 expected = %Q{<h4>[<a href="http://example.com/" class="external">http://example.com/</a> visit</h4>\n}
371 @parser.parse("==== [http://example.com/ visit\n").should == expected # was a bug
373 expected = %Q{<h3>[<a href="http://example.com/" class="external">http://example.com/</a> visit</h3>\n}
374 @parser.parse("=== [http://example.com/ visit\n").should == expected # was a bug
376 expected = %Q{<h2>[<a href="http://example.com/" class="external">http://example.com/</a> visit</h2>\n}
377 @parser.parse("== [http://example.com/ visit\n").should == expected # was a bug
379 expected = %Q{<h1>[<a href="http://example.com/" class="external">http://example.com/</a> visit</h1>\n}
380 @parser.parse("= [http://example.com/ visit\n").should == expected # was a bug
382 # here's a slightly more complicated example using a blockquote
383 expected = %Q{<blockquote>\n <p>[<a href="http://google.com/" class="external">http://google.com/</a></p>\n</blockquote>\n}
384 @parser.parse("> [http://google.com/\n").should == expected # was a bug
388 describe 'regressions' do
390 it 'should not turn failed absolute links into external hyperlinks' do
391 # was emitting: <p>[<a href="/hello" class="external">/hello</a> this</p>\n
392 expected = %Q{<p>[<a href="/hello">/hello</a> this</p>\n}
393 @parser.parse('[/hello this').should == expected
395 # was emitting: <p>[<a href="/hello" class="external">/hello</a> </p>\n
396 expected = %Q{<p>[<a href="/hello">/hello</a> </p>\n}
397 @parser.parse('[/hello ').should == expected
399 # was emitting: <h1>hello [<a href="/hello" class="external">/hello</a> </h1>\n
400 expected = %Q{<h1>hello [<a href="/hello">/hello</a> </h1>\n}
401 @parser.parse('= hello [/hello =').should == expected