]> git.wincent.com - wikitext.git/blob - spec/internal_link_spec.rb
5e4d5886e12276ca4289f24204944c59c6a9942b
[wikitext.git] / spec / internal_link_spec.rb
1 #!/usr/bin/env ruby
2 # encoding: utf-8
3 # Copyright 2007-2009 Wincent Colaiuta. All rights reserved.
4 #
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions are met:
7 #
8 # 1. Redistributions of source code must retain the above copyright notice,
9 #    this list of conditions and the following disclaimer.
10 # 2. Redistributions in binary form must reproduce the above copyright notice,
11 #    this list of conditions and the following disclaimer in the documentation
12 #    and/or other materials provided with the distribution.
13
14 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
18 # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 # POSSIBILITY OF SUCH DAMAGE.
25
26 require File.join(File.dirname(__FILE__), 'spec_helper.rb')
27 require 'wikitext'
28
29 describe Wikitext::Parser, 'internal links (space to underscore off)' do
30   before do
31     @parser = Wikitext::Parser.new :space_to_underscore => false
32   end
33
34   it 'should pass through unexpected link end tokens literally' do
35     @parser.parse('foo ]] bar').should == "<p>foo ]] bar</p>\n"                                     # in plain scope
36     @parser.parse("foo '']]'' bar").should == "<p>foo <em>]]</em> bar</p>\n"                        # in EM scope
37     @parser.parse("foo ''']]''' bar").should == "<p>foo <strong>]]</strong> bar</p>\n"              # in STRONG scope
38     @parser.parse("foo ''''']]''''' bar").should == "<p>foo <strong><em>]]</em></strong> bar</p>\n" # in STRONG_EM scope
39     @parser.parse('foo <tt>]]</tt> bar').should == "<p>foo <tt>]]</tt> bar</p>\n"                   # in TT scope
40     @parser.parse('= foo ]] bar =').should == "<h1>foo ]] bar</h1>\n"                               # in H1 scope
41     @parser.parse('== foo ]] bar ==').should == "<h2>foo ]] bar</h2>\n"                             # in H2 scope
42     @parser.parse('=== foo ]] bar ===').should == "<h3>foo ]] bar</h3>\n"                           # in H3 scope
43     @parser.parse('==== foo ]] bar ====').should == "<h4>foo ]] bar</h4>\n"                         # in H4 scope
44     @parser.parse('===== foo ]] bar =====').should == "<h5>foo ]] bar</h5>\n"                       # in H5 scope
45     @parser.parse('====== foo ]] bar ======').should == "<h6>foo ]] bar</h6>\n"                     # in H6 scope
46     @parser.parse('> ]]').should == "<blockquote>\n  <p>]]</p>\n</blockquote>\n"                    # in BLOCKQUOTE scope
47   end
48
49   it 'should turn single words into links' do
50     @parser.parse('[[foo]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n}
51   end
52
53   it 'should turn multiple words into links' do
54     @parser.parse('[[foo bar]]').should == %Q{<p><a href="/wiki/foo%20bar">foo bar</a></p>\n}
55   end
56
57   it 'should trim leading whitespace' do
58     @parser.parse('[[ foo]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n}
59     @parser.parse('[[  foo]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n}
60     @parser.parse('[[   foo]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n}
61     @parser.parse('[[    foo]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n}
62   end
63
64   it 'should trim trailing whitespace' do
65     @parser.parse('[[foo ]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n}
66     @parser.parse('[[foo  ]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n}
67     @parser.parse('[[foo   ]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n}
68     @parser.parse('[[foo    ]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n}   # was a bug (exception)
69     @parser.parse('[[foo     ]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n}  # was a bug (crash)
70   end
71
72   it 'should trim leading and trailing whitespace (combined)' do
73     @parser.parse('[[ foo    ]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n}
74     @parser.parse('[[  foo   ]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n}
75     @parser.parse('[[   foo  ]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n}
76     @parser.parse('[[    foo ]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n}
77   end
78
79   it 'should leave embedded whitespace intact' do
80     @parser.parse('[[ foo bar ]]').should == %Q{<p><a href="/wiki/foo%20bar">foo bar</a></p>\n}
81     @parser.parse('[[foo bar ]]').should == %Q{<p><a href="/wiki/foo%20bar">foo bar</a></p>\n}
82     @parser.parse('[[ foo bar ]]').should == %Q{<p><a href="/wiki/foo%20bar">foo bar</a></p>\n}
83   end
84
85   it 'should encode and sanitize quotes' do
86     # note how percent encoding is used in the href, and named entities in the link text
87     @parser.parse('[[hello "world"]]').should == %Q{<p><a href="/wiki/hello%20%22world%22">hello &quot;world&quot;</a></p>\n}
88   end
89
90   it 'should encode and sanitize ampersands' do
91     @parser.parse('[[a & b]]').should == %Q{<p><a href="/wiki/a%20%26%20b">a &amp; b</a></p>\n}
92   end
93
94   it 'should allow ampersand entities (special exception)' do
95     @parser.parse('[[a &amp; b]]').should == %Q{<p><a href="/wiki/a%20%26%20b">a &amp; b</a></p>\n}
96   end
97
98   it 'should allow quote entities (special exception)' do
99     @parser.parse('[[a &quot; b]]').should == %Q{<p><a href="/wiki/a%20%22%20b">a &quot; b</a></p>\n}
100   end
101
102   it 'should handle mixed scenarios (quotes, ampersands, non-ASCII characers)' do
103     expected = %Q{<p><a href="/wiki/foo%2c%20%22bar%22%20%26%20baz%20%e2%82%ac">foo, &quot;bar&quot; &amp; baz &#x20ac;</a></p>\n}
104     @parser.parse('[[foo, "bar" & baz €]]').should == expected
105   end
106
107   it 'should handle embedded paths' do
108     expected = %Q{<p><a href="/wiki/foo%2fbar">foo/bar</a></p>\n}
109     @parser.parse('[[foo/bar]]').should == expected
110   end
111
112   it 'should handle links in paragraph flows' do
113     expected = %Q{<p>foo <a href="/wiki/bar">bar</a> baz</p>\n}
114     @parser.parse('foo [[bar]] baz').should == expected # was a bug
115   end
116
117   describe 'custom link text' do
118     it 'should recognize link text placed after the separator' do
119       @parser.parse('[[foo|bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
120     end
121
122     it 'should trim whitespace to the left of the separator' do
123       @parser.parse('[[foo |bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
124       @parser.parse('[[foo  |bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
125       @parser.parse('[[foo   |bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
126       @parser.parse('[[foo    |bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
127       @parser.parse('[[foo     |bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
128       @parser.parse('[[foo      |bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
129     end
130
131     it 'should trim whitespace to the right of the separator' do
132       @parser.parse('[[foo| bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
133       @parser.parse('[[foo|  bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
134       @parser.parse('[[foo|   bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
135       @parser.parse('[[foo|    bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
136       @parser.parse('[[foo|     bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
137       @parser.parse('[[foo|      bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
138     end
139
140     it 'should trim whitespace on both sides of the separator (at the same time)' do
141       @parser.parse('[[foo      | bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
142       @parser.parse('[[foo     |  bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
143       @parser.parse('[[foo    |   bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
144       @parser.parse('[[foo   |    bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
145       @parser.parse('[[foo  |     bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
146       @parser.parse('[[foo |      bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
147     end
148
149     it 'should trim trailing whitespace from the link text' do
150       @parser.parse('[[foo|bar ]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
151       @parser.parse('[[foo|bar  ]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
152       @parser.parse('[[foo|bar   ]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
153       @parser.parse('[[foo|bar    ]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
154       @parser.parse('[[foo|bar     ]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
155       @parser.parse('[[foo|bar      ]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
156     end
157
158     it 'should trim leading and trailing whitespace from the link text' do
159       @parser.parse('[[foo|      bar ]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
160       @parser.parse('[[foo|     bar  ]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
161       @parser.parse('[[foo|    bar   ]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
162       @parser.parse('[[foo|   bar    ]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
163       @parser.parse('[[foo|  bar     ]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
164       @parser.parse('[[foo| bar      ]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
165     end
166
167     it 'should treat a separator inside the link text as part of the link text' do
168       @parser.parse('[[foo|bar|baz]]').should == %Q{<p><a href="/wiki/foo">bar|baz</a></p>\n}
169     end
170
171     it 'should treat separators outside of links as normal text' do
172       @parser.parse('foo|bar').should == %Q{<p>foo|bar</p>\n}
173     end
174
175     it 'should allow em markup in the custom link text' do
176       expected = %Q{<p><a href="/wiki/foo">bar <em>baz</em></a></p>\n}
177       @parser.parse("[[foo|bar ''baz'']]").should == expected
178     end
179
180     it 'should automatically close unclosed em markup in the custom link text' do
181       expected = %Q{<p><a href="/wiki/foo">bar <em>baz</em></a></p>\n}
182       @parser.parse("[[foo|bar ''baz]]").should == expected
183     end
184
185     it 'should allow strong markup in the custom link text' do
186       expected = %Q{<p><a href="/wiki/foo">bar <strong>baz</strong></a></p>\n}
187       @parser.parse("[[foo|bar '''baz''']]").should == expected
188     end
189
190     it 'should automatically close unclosed strong markup in the custom link text' do
191       expected = %Q{<p><a href="/wiki/foo">bar <strong>baz</strong></a></p>\n}
192       @parser.parse("[[foo|bar '''baz]]").should == expected
193     end
194
195     it 'should allow strong/em markup in the custom link text' do
196       expected = %Q{<p><a href="/wiki/foo">bar <strong><em>baz</em></strong></a></p>\n}
197       @parser.parse("[[foo|bar '''''baz''''']]").should == expected
198     end
199
200     it 'should automatically close unclosed strong/em markup in the custom link text' do
201       expected = %Q{<p><a href="/wiki/foo">bar <strong><em>baz</em></strong></a></p>\n}
202       @parser.parse("[[foo|bar '''''baz]]").should == expected
203     end
204
205     it 'should allow tt markup in the custom link text' do
206       expected = %Q{<p><a href="/wiki/foo">bar <tt>baz</tt></a></p>\n}
207       @parser.parse('[[foo|bar <tt>baz</tt>]]').should == expected
208     end
209
210     it 'should automatically close unclosed tt markup in the custom link text' do
211       expected = %Q{<p><a href="/wiki/foo">bar <tt>baz</tt></a></p>\n}
212       @parser.parse('[[foo|bar <tt>baz]]').should == expected
213     end
214
215     it 'should allow named entities in the custom link text' do
216       expected = %Q{<p><a href="/wiki/foo">bar &copy;</a></p>\n}
217       @parser.parse('[[foo|bar &copy;]]').should == expected
218
219       # explicitly test &quot; because it is tokenized separately from the other named entities
220       expected = %Q{<p><a href="/wiki/foo">bar &quot;</a></p>\n}
221       @parser.parse('[[foo|bar &quot;]]').should == expected
222
223       # explicitly test &amp; because it is tokenized separately from the other named entities
224       expected = %Q{<p><a href="/wiki/foo">bar &amp;</a></p>\n}
225       @parser.parse('[[foo|bar &amp;]]').should == expected
226     end
227
228     it 'should allow decimal entities in the custom link text' do
229       expected = %Q{<p><a href="/wiki/foo">bar &#8364;</a></p>\n}
230       @parser.parse('[[foo|bar &#8364;]]').should == expected
231     end
232
233     it 'should allow hexadecimal entities in the custom link text' do
234       expected = %Q{<p><a href="/wiki/foo">bar &#x20ac;</a></p>\n}
235       @parser.parse('[[foo|bar &#x20ac;]]').should == expected
236     end
237
238     it 'should sanitize non-ASCII characters in the custom link text' do
239       expected = %Q{<p><a href="/wiki/foo">bar &#x20ac;</a></p>\n}
240       @parser.parse('[[foo|bar €]]').should == expected
241     end
242
243     it 'should sanitize characters that have special meaning in HTML in the custom link text' do
244       expected = %Q{<p><a href="/wiki/foo">bar &lt;</a></p>\n}
245       @parser.parse('[[foo|bar <]]').should == expected
246
247       expected = %Q{<p><a href="/wiki/foo">bar &gt;</a></p>\n}
248       @parser.parse('[[foo|bar >]]').should == expected
249
250       expected = %Q{<p><a href="/wiki/foo">bar &amp;</a></p>\n}
251       @parser.parse('[[foo|bar &]]').should == expected
252
253       expected = %Q{<p><a href="/wiki/foo">bar &quot;baz&quot;</a></p>\n}
254       @parser.parse('[[foo|bar "baz"]]').should == expected
255     end
256
257     it 'should allow nowiki markup in the custom link text' do
258       expected = %Q{<p><a href="/wiki/foo">bar [[</a></p>\n}
259       @parser.parse("[[foo|bar <nowiki>[[</nowiki>]]").should == expected
260
261       expected = %Q{<p><a href="/wiki/foo">bar [</a></p>\n}
262       @parser.parse("[[foo|bar <nowiki>[</nowiki>]]").should == expected
263
264       expected = %Q{<p><a href="/wiki/foo">bar ]]</a></p>\n}
265       @parser.parse("[[foo|bar <nowiki>]]</nowiki>]]").should == expected
266
267       expected = %Q{<p><a href="/wiki/foo">bar ]</a></p>\n}
268       @parser.parse("[[foo|bar <nowiki>]</nowiki>]]").should == expected
269     end
270
271     it 'should handle paths in custom link text' do
272       expected = %Q{<p><a href="/wiki/hello%2fworld">foo/bar</a></p>\n}
273       @parser.parse('[[hello/world|foo/bar]]').should == expected
274     end
275   end
276
277   describe 'overriding the link prefix' do
278     it 'should be able to override the link prefix' do
279       @parser.internal_link_prefix = '/custom/'
280       @parser.parse('[[foo]]').should == %Q{<p><a href="/custom/foo">foo</a></p>\n}
281     end
282
283     it 'should interpet a nil link prefix as meaning no prefix' do
284       @parser.internal_link_prefix = nil
285       @parser.parse('[[foo]]').should == %Q{<p><a href="foo">foo</a></p>\n}
286     end
287   end
288
289   # "special links" existed in internal links up to and including wikitext version 1.3.2
290   # from version 1.4.0 onwards this feature was changed to instead work with external links
291   # as such, all of these specs have been updated to make sure that the old behaviour was removed
292   describe 'special links' do
293     it 'should no longer recognize links of the form "bug/10" as special links' do
294       @parser.parse('[[bug/10]]').should    == %Q{<p><a href="/wiki/bug%2f10">bug/10</a></p>\n}
295       @parser.parse('[[issue/25]]').should  == %Q{<p><a href="/wiki/issue%2f25">issue/25</a></p>\n}
296       @parser.parse('[[post/7]]').should    == %Q{<p><a href="/wiki/post%2f7">post/7</a></p>\n}
297     end
298
299     it 'should no longer accept custom link text in conjunction with special links' do
300       @parser.parse('[[bug/10|bug #10]]').should == %Q{<p><a href="/wiki/bug%2f10">bug #10</a></p>\n}
301     end
302
303     it 'should not emit special links regardless of custom internal link prefix overrides' do
304       @parser.internal_link_prefix = '/custom/'
305       @parser.parse('[[bug/10]]').should == %Q{<p><a href="/custom/bug%2f10">bug/10</a></p>\n}
306     end
307
308     it 'should (still) not classify links as special merely because of the presence of a slash' do
309       @parser.parse('[[foo/bar]]').should == %Q{<p><a href="/wiki/foo%2fbar">foo/bar</a></p>\n}
310     end
311
312     it 'should (still) not accept special links which have a leading forward slash' do
313       @parser.parse('[[/bug/10]]').should == %Q{<p><a href="/wiki/%2fbug%2f10">/bug/10</a></p>\n}
314     end
315   end
316
317   describe 'invalid links' do
318     it 'should not allow entities in the link text' do
319       @parser.parse('[[a &euro; b]]').should == "<p>[[a &euro; b]]</p>\n"
320     end
321
322     it 'should not allow URIs in the link text' do
323       expected = %Q{<p>[[hello <a href="http://example.com/" class="external">http://example.com/</a> world]]</p>\n}
324       @parser.parse('[[hello http://example.com/ world]]').should == expected
325     end
326
327     it 'should handle embedded [[ inside links' do
328       # note how first part "[[foo " in itself is invalid and so gets rejected and echoed literally
329       expected = %Q{<p>[[foo <a href="/wiki/bar">bar</a></p>\n}
330       @parser.parse('[[foo [[bar]]').should == expected
331     end
332
333     it 'should handled embedded ]] inside links' do
334       # note how the link gets terminated early and the trailing part is rejected and echoed literally
335       expected = %Q{<p><a href="/wiki/foo">foo</a>bar]]</p>\n}
336       @parser.parse('[[foo ]]bar]]').should == expected
337     end
338
339     it 'should handle embedded [ inside links' do
340       # [ is not allowed at all so the entire link is rendered invalid
341       expected = "<p>[[foo [bar]]</p>\n"
342       @parser.parse('[[foo [bar]]').should == expected
343     end
344
345     it 'should handle embedded ] inside links' do
346       # [ is not allowed at all so the entire link is rendered invalid
347       expected = "<p>[[foo ]bar]]</p>\n"
348       @parser.parse('[[foo ]bar]]').should == expected
349     end
350
351     describe 'unterminated link targets (end-of-file)' do
352       it 'should rollback and show the unterminated link' do
353         @parser.parse('[[foo').should == %Q{<p>[[foo</p>\n}
354       end
355
356       it 'should not trim leading whitespace when rolling back' do
357         @parser.parse('[[ foo').should    == %Q{<p>[[ foo</p>\n}
358         @parser.parse('[[  foo').should   == %Q{<p>[[  foo</p>\n}
359         @parser.parse('[[   foo').should  == %Q{<p>[[   foo</p>\n}
360         @parser.parse('[[    foo').should == %Q{<p>[[    foo</p>\n}
361       end
362
363       it 'should not trim trailing whitespace when rolling back' do
364         @parser.parse('[[foo ').should    == %Q{<p>[[foo </p>\n}
365         @parser.parse('[[foo  ').should   == %Q{<p>[[foo  </p>\n}
366         @parser.parse('[[foo   ').should  == %Q{<p>[[foo   </p>\n}
367         @parser.parse('[[foo    ').should == %Q{<p>[[foo    </p>\n}
368       end
369
370       it 'should not trim leadig and trailing whitespace (combined) when rolling back' do
371         @parser.parse('[[    foo ').should == %Q{<p>[[    foo </p>\n}
372         @parser.parse('[[   foo  ').should == %Q{<p>[[   foo  </p>\n}
373         @parser.parse('[[  foo   ').should == %Q{<p>[[  foo   </p>\n}
374         @parser.parse('[[ foo    ').should == %Q{<p>[[ foo    </p>\n}
375       end
376     end
377
378     describe 'unterminated link targets (end-of-line)' do
379       it 'should rollback and show the unterminated link' do
380         @parser.parse("[[foo\n").should == %Q{<p>[[foo</p>\n}
381       end
382
383       it 'should not trim leading whitespace when rolling back' do
384         @parser.parse("[[ foo\n").should    == %Q{<p>[[ foo</p>\n}
385         @parser.parse("[[  foo\n").should   == %Q{<p>[[  foo</p>\n}
386         @parser.parse("[[   foo\n").should  == %Q{<p>[[   foo</p>\n}
387         @parser.parse("[[    foo\n").should == %Q{<p>[[    foo</p>\n}
388       end
389
390       it 'should not trim trailing whitespace when rolling back' do
391         @parser.parse("[[foo \n").should    == %Q{<p>[[foo </p>\n}
392         @parser.parse("[[foo  \n").should   == %Q{<p>[[foo  </p>\n}
393         @parser.parse("[[foo   \n").should  == %Q{<p>[[foo   </p>\n}
394         @parser.parse("[[foo    \n").should == %Q{<p>[[foo    </p>\n}
395       end
396
397       it 'should not trim leading and trailing whitespace (combined) when rolling back' do
398         @parser.parse("[[ foo    \n").should == %Q{<p>[[ foo    </p>\n}
399         @parser.parse("[[  foo   \n").should == %Q{<p>[[  foo   </p>\n}
400         @parser.parse("[[   foo  \n").should == %Q{<p>[[   foo  </p>\n}
401         @parser.parse("[[    foo \n").should == %Q{<p>[[    foo </p>\n}
402       end
403     end
404
405     describe 'missing link text' do
406       it 'should use link target' do
407         @parser.parse('[[foo|]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n}
408       end
409     end
410
411     describe 'link cut off at separator (end-of-file)' do
412       it 'should rollback and show the unterminated link' do
413         @parser.parse('[[foo|').should == %Q{<p>[[foo|</p>\n}
414         @parser.parse('[[foo| ').should == %Q{<p>[[foo| </p>\n}
415         @parser.parse('[[foo|  ').should == %Q{<p>[[foo|  </p>\n}
416         @parser.parse('[[foo|   ').should == %Q{<p>[[foo|   </p>\n}
417         @parser.parse('[[foo|    ').should == %Q{<p>[[foo|    </p>\n}
418         @parser.parse('[[foo|     ').should == %Q{<p>[[foo|     </p>\n}
419         @parser.parse('[[foo|      ').should == %Q{<p>[[foo|      </p>\n}
420       end
421     end
422
423     describe 'link cut off at separator (end-of-line)' do
424       it 'should rollback and show the unterminated link' do
425         @parser.parse("[[foo|\n").should == %Q{<p>[[foo|</p>\n}
426         @parser.parse("[[foo| \n").should == %Q{<p>[[foo| </p>\n}
427         @parser.parse("[[foo|  \n").should == %Q{<p>[[foo|  </p>\n}
428         @parser.parse("[[foo|   \n").should == %Q{<p>[[foo|   </p>\n}
429         @parser.parse("[[foo|    \n").should == %Q{<p>[[foo|    </p>\n}
430         @parser.parse("[[foo|     \n").should == %Q{<p>[[foo|     </p>\n}
431         @parser.parse("[[foo|      \n").should == %Q{<p>[[foo|      </p>\n}
432       end
433     end
434
435     describe 'unterminated link text (end-of-file)' do
436       it 'should rollback and show the unterminated link' do
437         @parser.parse('[[foo|hello').should == %Q{<p>[[foo|hello</p>\n}
438         @parser.parse('[[foo|hello ').should == %Q{<p>[[foo|hello </p>\n}
439         @parser.parse('[[foo|hello  ').should == %Q{<p>[[foo|hello  </p>\n}
440         @parser.parse('[[foo|hello   ').should == %Q{<p>[[foo|hello   </p>\n}
441         @parser.parse('[[foo|hello    ').should == %Q{<p>[[foo|hello    </p>\n}
442         @parser.parse('[[foo|hello     ').should == %Q{<p>[[foo|hello     </p>\n}
443         @parser.parse('[[foo|hello      ').should == %Q{<p>[[foo|hello      </p>\n}
444       end
445     end
446
447     describe 'unterminated link text (end-of-line)' do
448       it 'should rollback and show the unterminated link' do
449         @parser.parse("[[foo|hello\n").should == %Q{<p>[[foo|hello</p>\n}
450         @parser.parse("[[foo|hello \n").should == %Q{<p>[[foo|hello </p>\n}
451         @parser.parse("[[foo|hello  \n").should == %Q{<p>[[foo|hello  </p>\n}
452         @parser.parse("[[foo|hello   \n").should == %Q{<p>[[foo|hello   </p>\n}
453         @parser.parse("[[foo|hello    \n").should == %Q{<p>[[foo|hello    </p>\n}
454         @parser.parse("[[foo|hello     \n").should == %Q{<p>[[foo|hello     </p>\n}
455         @parser.parse("[[foo|hello      \n").should == %Q{<p>[[foo|hello      </p>\n}
456       end
457     end
458   end
459 end
460
461 describe Wikitext::Parser, 'internal links (space to underscore on)' do
462   before do
463     @parser = Wikitext::Parser.new
464   end
465
466   it 'should pass through unexpected link end tokens literally' do
467     @parser.parse('foo ]] bar').should == "<p>foo ]] bar</p>\n"                                     # in plain scope
468     @parser.parse("foo '']]'' bar").should == "<p>foo <em>]]</em> bar</p>\n"                        # in EM scope
469     @parser.parse("foo ''']]''' bar").should == "<p>foo <strong>]]</strong> bar</p>\n"              # in STRONG scope
470     @parser.parse("foo ''''']]''''' bar").should == "<p>foo <strong><em>]]</em></strong> bar</p>\n" # in STRONG_EM scope
471     @parser.parse('foo <tt>]]</tt> bar').should == "<p>foo <tt>]]</tt> bar</p>\n"                   # in TT scope
472     @parser.parse('= foo ]] bar =').should == "<h1>foo ]] bar</h1>\n"                               # in H1 scope
473     @parser.parse('== foo ]] bar ==').should == "<h2>foo ]] bar</h2>\n"                             # in H2 scope
474     @parser.parse('=== foo ]] bar ===').should == "<h3>foo ]] bar</h3>\n"                           # in H3 scope
475     @parser.parse('==== foo ]] bar ====').should == "<h4>foo ]] bar</h4>\n"                         # in H4 scope
476     @parser.parse('===== foo ]] bar =====').should == "<h5>foo ]] bar</h5>\n"                       # in H5 scope
477     @parser.parse('====== foo ]] bar ======').should == "<h6>foo ]] bar</h6>\n"                     # in H6 scope
478     @parser.parse('> ]]').should == "<blockquote>\n  <p>]]</p>\n</blockquote>\n"                    # in BLOCKQUOTE scope
479   end
480
481   it 'should turn single words into links' do
482     @parser.parse('[[foo]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n}
483   end
484
485   it 'should turn multiple words into links, converting spaces into underscores' do
486     @parser.parse('[[foo bar]]').should == %Q{<p><a href="/wiki/foo_bar">foo bar</a></p>\n}
487   end
488
489   it 'should trim leading whitespace' do
490     @parser.parse('[[ foo]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n}
491     @parser.parse('[[  foo]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n}
492     @parser.parse('[[   foo]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n}
493     @parser.parse('[[    foo]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n}
494   end
495
496   it 'should trim trailing whitespace' do
497     @parser.parse('[[foo ]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n}
498     @parser.parse('[[foo  ]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n}
499     @parser.parse('[[foo   ]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n}
500     @parser.parse('[[foo    ]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n}   # was a bug (exception)
501     @parser.parse('[[foo     ]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n}  # was a bug (crash)
502   end
503
504   it 'should trim leading and trailing whitespace (combined)' do
505     @parser.parse('[[ foo    ]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n}
506     @parser.parse('[[  foo   ]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n}
507     @parser.parse('[[   foo  ]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n}
508     @parser.parse('[[    foo ]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n}
509   end
510
511   it 'should convert embedded whitespace into underscores' do
512     @parser.parse('[[ foo bar ]]').should == %Q{<p><a href="/wiki/foo_bar">foo bar</a></p>\n}
513     @parser.parse('[[foo bar ]]').should == %Q{<p><a href="/wiki/foo_bar">foo bar</a></p>\n}
514     @parser.parse('[[ foo bar ]]').should == %Q{<p><a href="/wiki/foo_bar">foo bar</a></p>\n}
515   end
516
517   it 'should encode and sanitize quotes' do
518     # note how percent encoding is used in the href, and named entities in the link text
519     @parser.parse('[[hello "world"]]').should == %Q{<p><a href="/wiki/hello_%22world%22">hello &quot;world&quot;</a></p>\n}
520   end
521
522   it 'should encode and sanitize ampersands' do
523     @parser.parse('[[a & b]]').should == %Q{<p><a href="/wiki/a_%26_b">a &amp; b</a></p>\n}
524   end
525
526   it 'should allow ampersand entities (special exception)' do
527     @parser.parse('[[a &amp; b]]').should == %Q{<p><a href="/wiki/a_%26_b">a &amp; b</a></p>\n}
528   end
529
530   it 'should allow quote entities (special exception)' do
531     @parser.parse('[[a &quot; b]]').should == %Q{<p><a href="/wiki/a_%22_b">a &quot; b</a></p>\n}
532   end
533
534   it 'should handle mixed scenarios (quotes, ampersands, non-ASCII characers)' do
535     expected = %Q{<p><a href="/wiki/foo%2c_%22bar%22_%26_baz_%e2%82%ac">foo, &quot;bar&quot; &amp; baz &#x20ac;</a></p>\n}
536     @parser.parse('[[foo, "bar" & baz €]]').should == expected
537   end
538
539   it 'should handle links in paragraph flows' do
540     expected = %Q{<p>foo <a href="/wiki/bar">bar</a> baz</p>\n}
541     @parser.parse('foo [[bar]] baz').should == expected # was a bug
542   end
543
544   describe 'custom link text' do
545     it 'should recognize link text placed after the separator' do
546       @parser.parse('[[foo|bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
547     end
548
549     it 'should trim whitespace to the left of the separator' do
550       @parser.parse('[[foo |bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
551       @parser.parse('[[foo  |bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
552       @parser.parse('[[foo   |bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
553       @parser.parse('[[foo    |bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
554       @parser.parse('[[foo     |bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
555       @parser.parse('[[foo      |bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
556     end
557
558     it 'should trim whitespace to the right of the separator' do
559       @parser.parse('[[foo| bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
560       @parser.parse('[[foo|  bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
561       @parser.parse('[[foo|   bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
562       @parser.parse('[[foo|    bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
563       @parser.parse('[[foo|     bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
564       @parser.parse('[[foo|      bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
565     end
566
567     it 'should trim whitespace on both sides of the separator (at the same time)' do
568       @parser.parse('[[foo      | bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
569       @parser.parse('[[foo     |  bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
570       @parser.parse('[[foo    |   bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
571       @parser.parse('[[foo   |    bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
572       @parser.parse('[[foo  |     bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
573       @parser.parse('[[foo |      bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
574     end
575
576     it 'should trim trailing whitespace from the link text' do
577       @parser.parse('[[foo|bar ]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
578       @parser.parse('[[foo|bar  ]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
579       @parser.parse('[[foo|bar   ]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
580       @parser.parse('[[foo|bar    ]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
581       @parser.parse('[[foo|bar     ]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
582       @parser.parse('[[foo|bar      ]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
583     end
584
585     it 'should trim leading and trailing whitespace from the link text' do
586       @parser.parse('[[foo|      bar ]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
587       @parser.parse('[[foo|     bar  ]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
588       @parser.parse('[[foo|    bar   ]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
589       @parser.parse('[[foo|   bar    ]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
590       @parser.parse('[[foo|  bar     ]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
591       @parser.parse('[[foo| bar      ]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
592     end
593
594     it 'should treat a separator inside the link text as part of the link text' do
595       @parser.parse('[[foo|bar|baz]]').should == %Q{<p><a href="/wiki/foo">bar|baz</a></p>\n}
596     end
597
598     it 'should treat separators outside of links as normal text' do
599       @parser.parse('foo|bar').should == %Q{<p>foo|bar</p>\n}
600     end
601
602     it 'should allow em markup in the custom link text' do
603       expected = %Q{<p><a href="/wiki/foo">bar <em>baz</em></a></p>\n}
604       @parser.parse("[[foo|bar ''baz'']]").should == expected
605     end
606
607     it 'should automatically close unclosed em markup in the custom link text' do
608       expected = %Q{<p><a href="/wiki/foo">bar <em>baz</em></a></p>\n}
609       @parser.parse("[[foo|bar ''baz]]").should == expected
610     end
611
612     it 'should allow strong markup in the custom link text' do
613       expected = %Q{<p><a href="/wiki/foo">bar <strong>baz</strong></a></p>\n}
614       @parser.parse("[[foo|bar '''baz''']]").should == expected
615     end
616
617     it 'should automatically close unclosed strong markup in the custom link text' do
618       expected = %Q{<p><a href="/wiki/foo">bar <strong>baz</strong></a></p>\n}
619       @parser.parse("[[foo|bar '''baz]]").should == expected
620     end
621
622     it 'should allow strong/em markup in the custom link text' do
623       expected = %Q{<p><a href="/wiki/foo">bar <strong><em>baz</em></strong></a></p>\n}
624       @parser.parse("[[foo|bar '''''baz''''']]").should == expected
625     end
626
627     it 'should automatically close unclosed strong/em markup in the custom link text' do
628       expected = %Q{<p><a href="/wiki/foo">bar <strong><em>baz</em></strong></a></p>\n}
629       @parser.parse("[[foo|bar '''''baz]]").should == expected
630     end
631
632     it 'should allow tt markup in the custom link text' do
633       expected = %Q{<p><a href="/wiki/foo">bar <tt>baz</tt></a></p>\n}
634       @parser.parse('[[foo|bar <tt>baz</tt>]]').should == expected
635     end
636
637     it 'should automatically close unclosed tt markup in the custom link text' do
638       expected = %Q{<p><a href="/wiki/foo">bar <tt>baz</tt></a></p>\n}
639       @parser.parse('[[foo|bar <tt>baz]]').should == expected
640     end
641
642     it 'should allow named entities in the custom link text' do
643       expected = %Q{<p><a href="/wiki/foo">bar &copy;</a></p>\n}
644       @parser.parse('[[foo|bar &copy;]]').should == expected
645
646       # explicitly test &quot; because it is tokenized separately from the other named entities
647       expected = %Q{<p><a href="/wiki/foo">bar &quot;</a></p>\n}
648       @parser.parse('[[foo|bar &quot;]]').should == expected
649
650       # explicitly test &amp; because it is tokenized separately from the other named entities
651       expected = %Q{<p><a href="/wiki/foo">bar &amp;</a></p>\n}
652       @parser.parse('[[foo|bar &amp;]]').should == expected
653     end
654
655     it 'should allow decimal entities in the custom link text' do
656       expected = %Q{<p><a href="/wiki/foo">bar &#8364;</a></p>\n}
657       @parser.parse('[[foo|bar &#8364;]]').should == expected
658     end
659
660     it 'should allow hexadecimal entities in the custom link text' do
661       expected = %Q{<p><a href="/wiki/foo">bar &#x20ac;</a></p>\n}
662       @parser.parse('[[foo|bar &#x20ac;]]').should == expected
663     end
664
665     it 'should sanitize non-ASCII characters in the custom link text' do
666       expected = %Q{<p><a href="/wiki/foo">bar &#x20ac;</a></p>\n}
667       @parser.parse('[[foo|bar €]]').should == expected
668     end
669
670     it 'should sanitize characters that have special meaning in HTML in the custom link text' do
671       expected = %Q{<p><a href="/wiki/foo">bar &lt;</a></p>\n}
672       @parser.parse('[[foo|bar <]]').should == expected
673
674       expected = %Q{<p><a href="/wiki/foo">bar &gt;</a></p>\n}
675       @parser.parse('[[foo|bar >]]').should == expected
676
677       expected = %Q{<p><a href="/wiki/foo">bar &amp;</a></p>\n}
678       @parser.parse('[[foo|bar &]]').should == expected
679
680       expected = %Q{<p><a href="/wiki/foo">bar &quot;baz&quot;</a></p>\n}
681       @parser.parse('[[foo|bar "baz"]]').should == expected
682     end
683
684     it 'should allow nowiki markup in the custom link text' do
685       expected = %Q{<p><a href="/wiki/foo">bar [[</a></p>\n}
686       @parser.parse("[[foo|bar <nowiki>[[</nowiki>]]").should == expected
687
688       expected = %Q{<p><a href="/wiki/foo">bar [</a></p>\n}
689       @parser.parse("[[foo|bar <nowiki>[</nowiki>]]").should == expected
690
691       expected = %Q{<p><a href="/wiki/foo">bar ]]</a></p>\n}
692       @parser.parse("[[foo|bar <nowiki>]]</nowiki>]]").should == expected
693
694       expected = %Q{<p><a href="/wiki/foo">bar ]</a></p>\n}
695       @parser.parse("[[foo|bar <nowiki>]</nowiki>]]").should == expected
696     end
697   end
698
699   describe 'overriding the link prefix' do
700     it 'should be able to override the link prefix' do
701       @parser.internal_link_prefix = '/custom/'
702       @parser.parse('[[foo]]').should == %Q{<p><a href="/custom/foo">foo</a></p>\n}
703     end
704
705     it 'should interpet a nil link prefix as meaning no prefix' do
706       @parser.internal_link_prefix = nil
707       @parser.parse('[[foo]]').should == %Q{<p><a href="foo">foo</a></p>\n}
708     end
709   end
710
711   # see note above about "special links" being removed from internal links from 1.4.0 onwards
712   describe 'special links' do
713     it 'should no longer recognize links of the form "bug/10" as special links' do
714       @parser.parse('[[bug/10]]').should    == %Q{<p><a href="/wiki/bug%2f10">bug/10</a></p>\n}
715       @parser.parse('[[issue/25]]').should  == %Q{<p><a href="/wiki/issue%2f25">issue/25</a></p>\n}
716       @parser.parse('[[post/7]]').should    == %Q{<p><a href="/wiki/post%2f7">post/7</a></p>\n}
717     end
718
719     it 'should no longer accept custom link text in conjunction with special links' do
720       @parser.parse('[[bug/10|bug #10]]').should == %Q{<p><a href="/wiki/bug%2f10">bug #10</a></p>\n}
721     end
722
723     it 'should not emit special links regardless of custom internal link prefix overrides' do
724       @parser.internal_link_prefix = '/custom/'
725       @parser.parse('[[bug/10]]').should == %Q{<p><a href="/custom/bug%2f10">bug/10</a></p>\n}
726     end
727
728     it 'should (still) not classify links as special merely because of the presence of a slash' do
729       @parser.parse('[[foo/bar]]').should == %Q{<p><a href="/wiki/foo%2fbar">foo/bar</a></p>\n}
730     end
731
732     it 'should (still) not accept special links which have a leading forward slash' do
733       @parser.parse('[[/bug/10]]').should == %Q{<p><a href="/wiki/%2fbug%2f10">/bug/10</a></p>\n}
734     end
735   end
736
737   describe 'invalid links' do
738     it 'should not allow entities in the link text' do
739       @parser.parse('[[a &euro; b]]').should == "<p>[[a &euro; b]]</p>\n"
740     end
741
742     it 'should not allow URIs in the link text' do
743       expected = %Q{<p>[[hello <a href="http://example.com/" class="external">http://example.com/</a> world]]</p>\n}
744       @parser.parse('[[hello http://example.com/ world]]').should == expected
745     end
746
747     it 'should handle embedded [[ inside links' do
748       # note how first part "[[foo " in itself is invalid and so gets rejected and echoed literally
749       expected = %Q{<p>[[foo <a href="/wiki/bar">bar</a></p>\n}
750       @parser.parse('[[foo [[bar]]').should == expected
751     end
752
753     it 'should handled embedded ]] inside links' do
754       # note how the link gets terminated early and the trailing part is rejected and echoed literally
755       expected = %Q{<p><a href="/wiki/foo">foo</a>bar]]</p>\n}
756       @parser.parse('[[foo ]]bar]]').should == expected
757     end
758
759     it 'should handle embedded [ inside links' do
760       # [ is not allowed at all so the entire link is rendered invalid
761       expected = "<p>[[foo [bar]]</p>\n"
762       @parser.parse('[[foo [bar]]').should == expected
763     end
764
765     it 'should handle embedded ] inside links' do
766       # [ is not allowed at all so the entire link is rendered invalid
767       expected = "<p>[[foo ]bar]]</p>\n"
768       @parser.parse('[[foo ]bar]]').should == expected
769     end
770
771     describe 'unterminated link targets (end-of-file)' do
772       it 'should rollback and show the unterminated link' do
773         @parser.parse('[[foo').should == %Q{<p>[[foo</p>\n}
774       end
775
776       it 'should not trim leading whitespace when rolling back' do
777         @parser.parse('[[ foo').should    == %Q{<p>[[ foo</p>\n}
778         @parser.parse('[[  foo').should   == %Q{<p>[[  foo</p>\n}
779         @parser.parse('[[   foo').should  == %Q{<p>[[   foo</p>\n}
780         @parser.parse('[[    foo').should == %Q{<p>[[    foo</p>\n}
781       end
782
783       it 'should not trim trailing whitespace when rolling back' do
784         @parser.parse('[[foo ').should    == %Q{<p>[[foo </p>\n}
785         @parser.parse('[[foo  ').should   == %Q{<p>[[foo  </p>\n}
786         @parser.parse('[[foo   ').should  == %Q{<p>[[foo   </p>\n}
787         @parser.parse('[[foo    ').should == %Q{<p>[[foo    </p>\n}
788       end
789
790       it 'should not trim leadig and trailing whitespace (combined) when rolling back' do
791         @parser.parse('[[    foo ').should == %Q{<p>[[    foo </p>\n}
792         @parser.parse('[[   foo  ').should == %Q{<p>[[   foo  </p>\n}
793         @parser.parse('[[  foo   ').should == %Q{<p>[[  foo   </p>\n}
794         @parser.parse('[[ foo    ').should == %Q{<p>[[ foo    </p>\n}
795       end
796     end
797
798     describe 'unterminated link targets (end-of-line)' do
799       it 'should rollback and show the unterminated link' do
800         @parser.parse("[[foo\n").should == %Q{<p>[[foo</p>\n}
801       end
802
803       it 'should not trim leading whitespace when rolling back' do
804         @parser.parse("[[ foo\n").should    == %Q{<p>[[ foo</p>\n}
805         @parser.parse("[[  foo\n").should   == %Q{<p>[[  foo</p>\n}
806         @parser.parse("[[   foo\n").should  == %Q{<p>[[   foo</p>\n}
807         @parser.parse("[[    foo\n").should == %Q{<p>[[    foo</p>\n}
808       end
809
810       it 'should not trim trailing whitespace when rolling back' do
811         @parser.parse("[[foo \n").should    == %Q{<p>[[foo </p>\n}
812         @parser.parse("[[foo  \n").should   == %Q{<p>[[foo  </p>\n}
813         @parser.parse("[[foo   \n").should  == %Q{<p>[[foo   </p>\n}
814         @parser.parse("[[foo    \n").should == %Q{<p>[[foo    </p>\n}
815       end
816
817       it 'should not trim leading and trailing whitespace (combined) when rolling back' do
818         @parser.parse("[[ foo    \n").should == %Q{<p>[[ foo    </p>\n}
819         @parser.parse("[[  foo   \n").should == %Q{<p>[[  foo   </p>\n}
820         @parser.parse("[[   foo  \n").should == %Q{<p>[[   foo  </p>\n}
821         @parser.parse("[[    foo \n").should == %Q{<p>[[    foo </p>\n}
822       end
823     end
824
825     describe 'missing link text' do
826       it 'should use link target (zero-width link text)' do
827         @parser.parse('[[foo|]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n}
828       end
829
830       # was a bug in version <= 1.6
831       # emitted: <p><a href="/wiki/foo"></a></p>\n
832       it 'should use link target (blank link text)' do
833         @parser.parse('[[foo| ]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n}
834       end
835     end
836
837     describe 'link cut off at separator (end-of-file)' do
838       it 'should rollback and show the unterminated link' do
839         @parser.parse('[[foo|').should == %Q{<p>[[foo|</p>\n}
840         @parser.parse('[[foo| ').should == %Q{<p>[[foo| </p>\n}
841         @parser.parse('[[foo|  ').should == %Q{<p>[[foo|  </p>\n}
842         @parser.parse('[[foo|   ').should == %Q{<p>[[foo|   </p>\n}
843         @parser.parse('[[foo|    ').should == %Q{<p>[[foo|    </p>\n}
844         @parser.parse('[[foo|     ').should == %Q{<p>[[foo|     </p>\n}
845         @parser.parse('[[foo|      ').should == %Q{<p>[[foo|      </p>\n}
846       end
847     end
848
849     describe 'link cut off at separator (end-of-line)' do
850       it 'should rollback and show the unterminated link' do
851         @parser.parse("[[foo|\n").should == %Q{<p>[[foo|</p>\n}
852         @parser.parse("[[foo| \n").should == %Q{<p>[[foo| </p>\n}
853         @parser.parse("[[foo|  \n").should == %Q{<p>[[foo|  </p>\n}
854         @parser.parse("[[foo|   \n").should == %Q{<p>[[foo|   </p>\n}
855         @parser.parse("[[foo|    \n").should == %Q{<p>[[foo|    </p>\n}
856         @parser.parse("[[foo|     \n").should == %Q{<p>[[foo|     </p>\n}
857         @parser.parse("[[foo|      \n").should == %Q{<p>[[foo|      </p>\n}
858       end
859     end
860
861     describe 'unterminated link text (end-of-file)' do
862       it 'should rollback and show the unterminated link' do
863         @parser.parse('[[foo|hello').should == %Q{<p>[[foo|hello</p>\n}
864         @parser.parse('[[foo|hello ').should == %Q{<p>[[foo|hello </p>\n}
865         @parser.parse('[[foo|hello  ').should == %Q{<p>[[foo|hello  </p>\n}
866         @parser.parse('[[foo|hello   ').should == %Q{<p>[[foo|hello   </p>\n}
867         @parser.parse('[[foo|hello    ').should == %Q{<p>[[foo|hello    </p>\n}
868         @parser.parse('[[foo|hello     ').should == %Q{<p>[[foo|hello     </p>\n}
869         @parser.parse('[[foo|hello      ').should == %Q{<p>[[foo|hello      </p>\n}
870       end
871     end
872
873     describe 'unterminated link text (end-of-line)' do
874       it 'should rollback and show the unterminated link' do
875         @parser.parse("[[foo|hello\n").should == %Q{<p>[[foo|hello</p>\n}
876         @parser.parse("[[foo|hello \n").should == %Q{<p>[[foo|hello </p>\n}
877         @parser.parse("[[foo|hello  \n").should == %Q{<p>[[foo|hello  </p>\n}
878         @parser.parse("[[foo|hello   \n").should == %Q{<p>[[foo|hello   </p>\n}
879         @parser.parse("[[foo|hello    \n").should == %Q{<p>[[foo|hello    </p>\n}
880         @parser.parse("[[foo|hello     \n").should == %Q{<p>[[foo|hello     </p>\n}
881         @parser.parse("[[foo|hello      \n").should == %Q{<p>[[foo|hello      </p>\n}
882       end
883     end
884   end
885 end