]> git.wincent.com - wikitext.git/blob - spec/regressions_spec.rb
5ddb0d4e9e725565d3f1af01c4cb8f94bc02c313
[wikitext.git] / spec / regressions_spec.rb
1 #!/usr/bin/env ruby
2 # encoding: utf-8
3 # Copyright 2008-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 # this is a general-purpose file in which I'll add specs for former bugs to make sure that they don't regress
30 describe Wikitext::Parser, 'regressions' do
31   before do
32     @parser = Wikitext::Parser.new
33   end
34
35   # turns out that this was never a bug in wikitext -- it was a bug in the host application -- but keeping the test does no harm
36   it 'should correctly transform example #1' do
37     input = dedent <<-END
38       = Leopard =
39       
40       * punto 1
41       * punto 2
42       
43       Y [[otro articulo]].
44     END
45     expected = dedent <<-END
46       <h1>Leopard</h1>
47       <ul>
48         <li>punto 1</li>
49         <li>punto 2</li>
50       </ul>
51       <p>Y <a href="/wiki/otro_articulo">otro articulo</a>.</p>
52     END
53     @parser.parse(input).should == expected
54   end
55
56   # discovered at: http://rails.wincent.com/wiki/nginx_log_rotation
57   # fixed by 0a328f1
58   it 'should allow empty lines in PRE blocks marked up with a leading space' do
59     input = dedent <<-END
60        # -d turns on debug mode: output is verbose, no actual changes are made to the log files
61        sudo logrotate -d /etc/logrotate.d/nginx
62        
63        # if the debug output looks good, proceed with a real rotation (-v turns on verbose output)
64        sudo logrotate -v /etc/logrotate.d/nginx
65     END
66     expected = dedent <<-END
67       <pre># -d turns on debug mode: output is verbose, no actual changes are made to the log files
68       sudo logrotate -d /etc/logrotate.d/nginx
69       
70       # if the debug output looks good, proceed with a real rotation (-v turns on verbose output)
71       sudo logrotate -v /etc/logrotate.d/nginx</pre>
72     END
73     @parser.parse(input).should == expected
74   end
75
76   # discovered at: http://rails.wincent.com/wiki/Installing_Ragel_5.2.0_on_Mac_OS_X_Tiger
77   # fixed by a616841
78   it 'should handle PRE_START blocks which follow unordered lists' do
79     input = dedent <<-END
80       * Get link to latest source code from: http://www.cs.queensu.ca/~thurston/ragel/
81       
82       <pre>wget http://www.cs.queensu.ca/~thurston/ragel/ragel-5.20.tar.gz
83       tar xzvf ragel-5.20.tar.gz
84       cd ragel-5.20</pre>
85     END
86     expected = dedent <<-END
87       <ul>
88         <li>Get link to latest source code from: <a href="http://www.cs.queensu.ca/~thurston/ragel/" class="external">http://www.cs.queensu.ca/~thurston/ragel/</a></li>
89       </ul>
90       <pre>wget <a href="http://www.cs.queensu.ca/~thurston/ragel/ragel-5.20.tar.gz" class="external">http://www.cs.queensu.ca/~thurston/ragel/ragel-5.20.tar.gz</a>
91       tar xzvf ragel-5.20.tar.gz
92       cd ragel-5.20</pre>
93     END
94     @parser.parse(input).should == expected
95   end
96
97   # discovered at: http://rails.wincent.com/wiki/Movable_Type_security_notes
98   # fixed by a616841
99   it 'should handle PRE_START blocks which follow ordered lists' do
100     input = dedent <<-END
101       # Turn off the [[Movable Type]] search function; use Google instead (it's better anyway) with a form something like this:
102       
103       <pre><form method="get"...></pre>
104     END
105     expected = dedent <<-END
106       <ol>
107         <li>Turn off the <a href="/wiki/Movable_Type">Movable Type</a> search function; use Google instead (it's better anyway) with a form something like this:</li>
108       </ol>
109       <pre>&lt;form method=&quot;get&quot;...&gt;</pre>
110     END
111     @parser.parse(input).should == expected
112   end
113
114   # discovered at: http://rails.wincent.com/wiki/Movable_Type_security_notes
115   # fixed by 191b75d
116   it 'should respect additional indentation found inside PRE blocks' do
117     # note the two extra spaces on each line
118     input = dedent <<-END
119          <input type="text" name="q" size="20" maxlength="255" value="" />
120          <input type="hidden" name="hl" value="en" />
121     END
122
123     # problem is the spaces were being emitted _before_ the CRLF
124     expected = dedent <<-END
125       <pre>  &lt;input type=&quot;text&quot; name=&quot;q&quot; size=&quot;20&quot; maxlength=&quot;255&quot; value=&quot;&quot; /&gt;
126         &lt;input type=&quot;hidden&quot; name=&quot;hl&quot; value=&quot;en&quot; /&gt;</pre>
127     END
128     @parser.parse(input).should == expected
129   end
130
131   # this is the general case of the bug covered in the previous spec
132   # any token that appears as the first token after a PRE token can manifest this bug
133   # PRINTABLE didn't only because it called _Wikitext_start_para_if_necessary(), which handled the pending CRLF
134   it 'should emit pending newlines for all token types found inside PRE and PRE_START blocks' do
135     # PRE_START
136     input = dedent <<-END
137        foo
138        <pre>bar
139     END
140     expected = dedent <<-END
141       <pre>foo
142       &lt;pre&gt;bar</pre>
143     END
144     @parser.parse(input).should == expected
145
146     # PRE_END
147     input = dedent <<-END
148        foo
149        </pre>bar
150     END
151     expected = dedent <<-END
152       <pre>foo
153       &lt;/pre&gt;bar</pre>
154     END
155     @parser.parse(input).should == expected
156
157     # BLOCKQUOTE_START
158     input = dedent <<-END
159        foo
160        <blockquote>bar
161     END
162     expected = dedent <<-END
163       <pre>foo
164       &lt;blockquote&gt;bar</pre>
165     END
166     @parser.parse(input).should == expected
167
168     # BLOCKQUOTE_END
169     input = dedent <<-END
170        foo
171        </blockquote>bar
172     END
173     expected = dedent <<-END
174       <pre>foo
175       &lt;/blockquote&gt;bar</pre>
176     END
177     @parser.parse(input).should == expected
178
179     # NO_WIKI_START
180     input = dedent <<-END
181        foo
182        <nowiki>bar
183     END
184     expected = dedent <<-END
185       <pre>foo
186       &lt;nowiki&gt;bar</pre>
187     END
188     @parser.parse(input).should == expected
189
190     # STRONG_EM
191     input = dedent <<-END
192        foo
193        '''''bar
194     END
195     expected = dedent <<-END
196       <pre>foo
197       '''''bar</pre>
198     END
199     @parser.parse(input).should == expected
200
201     # STRONG
202     input = dedent <<-END
203        foo
204        '''bar
205     END
206     expected = dedent <<-END
207       <pre>foo
208       '''bar</pre>
209     END
210     @parser.parse(input).should == expected
211
212     # STRONG_START
213     input = dedent <<-END
214        foo
215        <strong>bar
216     END
217     expected = dedent <<-END
218       <pre>foo
219       &lt;strong&gt;bar</pre>
220     END
221     @parser.parse(input).should == expected
222
223     # STRONG_END
224     input = dedent <<-END
225        foo
226        </strong>bar
227     END
228     expected = dedent <<-END
229       <pre>foo
230       &lt;/strong&gt;bar</pre>
231     END
232     @parser.parse(input).should == expected
233
234     # EM
235     input = dedent <<-END
236        foo
237        ''bar
238     END
239     expected = dedent <<-END
240       <pre>foo
241       ''bar</pre>
242     END
243     @parser.parse(input).should == expected
244
245     # EM_START
246     input = dedent <<-END
247        foo
248        <em>bar
249     END
250     expected = dedent <<-END
251       <pre>foo
252       &lt;em&gt;bar</pre>
253     END
254     @parser.parse(input).should == expected
255
256     # EM_END
257     input = dedent <<-END
258        foo
259        </em>bar
260     END
261     expected = dedent <<-END
262       <pre>foo
263       &lt;/em&gt;bar</pre>
264     END
265     @parser.parse(input).should == expected
266
267     # TT
268     input = dedent <<-END
269        foo
270        `bar
271     END
272     expected = dedent <<-END
273       <pre>foo
274       `bar</pre>
275     END
276     @parser.parse(input).should == expected
277
278     # TT_START
279     input = dedent <<-END
280        foo
281        <tt>bar
282     END
283     expected = dedent <<-END
284       <pre>foo
285       &lt;tt&gt;bar</pre>
286     END
287     @parser.parse(input).should == expected
288
289     # TT_END
290     input = dedent <<-END
291        foo
292        </tt>bar
293     END
294     expected = dedent <<-END
295       <pre>foo
296       &lt;/tt&gt;bar</pre>
297     END
298     @parser.parse(input).should == expected
299
300     # H6_END
301     input = dedent <<-END
302        foo
303        ======
304        bar
305     END
306     expected = dedent <<-END
307       <pre>foo
308       ======
309       bar</pre>
310     END
311     @parser.parse(input).should == expected
312
313     # H5_END
314     input = dedent <<-END
315        foo
316        =====
317        bar
318     END
319     expected = dedent <<-END
320       <pre>foo
321       =====
322       bar</pre>
323     END
324     @parser.parse(input).should == expected
325
326     # H4_END
327     input = dedent <<-END
328        foo
329        ====
330        bar
331     END
332     expected = dedent <<-END
333       <pre>foo
334       ====
335       bar</pre>
336     END
337     @parser.parse(input).should == expected
338
339     # H3_END
340     input = dedent <<-END
341        foo
342        ===
343        bar
344     END
345     expected = dedent <<-END
346       <pre>foo
347       ===
348       bar</pre>
349     END
350     @parser.parse(input).should == expected
351
352     # H2_END
353     input = dedent <<-END
354        foo
355        ==
356        bar
357     END
358     expected = dedent <<-END
359       <pre>foo
360       ==
361       bar</pre>
362     END
363     @parser.parse(input).should == expected
364
365     # H1_END
366     input = dedent <<-END
367        foo
368        =
369        bar
370     END
371     expected = dedent <<-END
372       <pre>foo
373       =
374       bar</pre>
375     END
376     @parser.parse(input).should == expected
377
378     # MAIL
379     input = dedent <<-END
380        foo
381        bar@baz.com
382     END
383     expected = dedent <<-END
384       <pre>foo
385       bar@baz.com</pre>
386     END
387     @parser.parse(input).should == expected
388
389     # LINK_START
390     input = dedent <<-END
391        foo
392        [[bar
393     END
394     expected = dedent <<-END
395       <pre>foo
396       [[bar</pre>
397     END
398     @parser.parse(input).should == expected
399
400     # LINK_END
401     input = dedent <<-END
402        foo
403        ]]bar
404     END
405     expected = dedent <<-END
406       <pre>foo
407       ]]bar</pre>
408     END
409     @parser.parse(input).should == expected
410
411     # EXT_LINK_START
412     input = dedent <<-END
413        foo
414        [bar
415     END
416     expected = dedent <<-END
417       <pre>foo
418       [bar</pre>
419     END
420     @parser.parse(input).should == expected
421
422     # EXT_LINK_END
423     input = dedent <<-END
424        foo
425        ]bar
426     END
427     expected = dedent <<-END
428       <pre>foo
429       ]bar</pre>
430     END
431     @parser.parse(input).should == expected
432
433     # IMG_START
434     input = dedent <<-END
435        foo
436        {{bar
437     END
438     expected = dedent <<-END
439       <pre>foo
440       {{bar</pre>
441     END
442     @parser.parse(input).should == expected
443
444     # these tokens weren't affected by the bug, seeing as they either call _Wikitext_start_para_if_necessary()
445     # or they can only appear in PRE_START (not PRE) thanks to the tokenizer
446     # but we add specs for them to make sure that the issue never crops up for them in the future
447
448     # PRE (in PRE_START)
449     input = dedent <<-END
450       <pre>foo
451        bar</pre>
452     END
453     expected = dedent <<-END
454       <pre>foo
455        bar</pre>
456     END
457     @parser.parse(input).should == expected
458
459     # BLOCKQUOTE (in PRE_START)
460     input = dedent <<-END
461       <pre>foo
462       > bar</pre>
463     END
464     expected = dedent <<-END
465       <pre>foo
466       &gt; bar</pre>
467     END
468     @parser.parse(input).should == expected
469
470     # OL (in PRE_START)
471     input = dedent <<-END
472       <pre># foo
473       # bar</pre>
474     END
475     expected = dedent <<-END
476       <pre># foo
477       # bar</pre>
478     END
479     @parser.parse(input).should == expected
480
481     # UL (in PRE_START)
482     input = dedent <<-END
483       <pre>* foo
484       * bar</pre>
485     END
486     expected = dedent <<-END
487       <pre>* foo
488       * bar</pre>
489     END
490     @parser.parse(input).should == expected
491
492     # H6_START (in PRE_START)
493     input = dedent <<-END
494       <pre>foo
495       ====== bar
496       baz</pre>
497     END
498     expected = dedent <<-END
499       <pre>foo
500       ====== bar
501       baz</pre>
502     END
503     @parser.parse(input).should == expected
504
505     # H5_START (in PRE_START)
506     input = dedent <<-END
507       <pre>foo
508       ===== bar
509       baz</pre>
510     END
511     expected = dedent <<-END
512       <pre>foo
513       ===== bar
514       baz</pre>
515     END
516     @parser.parse(input).should == expected
517
518     # H4_START (in PRE_START)
519     input = dedent <<-END
520       <pre>foo
521       ==== bar
522       baz</pre>
523     END
524     expected = dedent <<-END
525       <pre>foo
526       ==== bar
527       baz</pre>
528     END
529     @parser.parse(input).should == expected
530
531     # H3_START (in PRE_START)
532     input = dedent <<-END
533       <pre>foo
534       === bar
535       baz</pre>
536     END
537     expected = dedent <<-END
538       <pre>foo
539       === bar
540       baz</pre>
541     END
542     @parser.parse(input).should == expected
543
544     # H2_START (in PRE_START)
545     input = dedent <<-END
546       <pre>foo
547       == bar
548       baz</pre>
549     END
550     expected = dedent <<-END
551       <pre>foo
552       == bar
553       baz</pre>
554     END
555     @parser.parse(input).should == expected
556
557     # H1_START (in PRE_START)
558     input = dedent <<-END
559       <pre>foo
560       = bar
561       baz</pre>
562     END
563     expected = dedent <<-END
564       <pre>foo
565       = bar
566       baz</pre>
567     END
568     @parser.parse(input).should == expected
569
570     # NO_WIKI_END
571     input = dedent <<-END
572        foo
573        </nowiki>bar
574     END
575     expected = dedent <<-END
576       <pre>foo
577       &lt;/nowiki&gt;bar</pre>
578     END
579     @parser.parse(input).should == expected
580
581     # SEPARATOR
582     input = dedent <<-END
583        foo
584        |bar
585     END
586     expected = dedent <<-END
587       <pre>foo
588       |bar</pre>
589     END
590     @parser.parse(input).should == expected
591
592     # QUOT_ENTITY
593     input = dedent <<-END
594        foo
595        &quot;bar
596     END
597     expected = dedent <<-END
598       <pre>foo
599       &quot;bar</pre>
600     END
601     @parser.parse(input).should == expected
602
603     # AMP_ENTITY
604     input = dedent <<-END
605        foo
606        &amp;bar
607     END
608     expected = dedent <<-END
609       <pre>foo
610       &amp;bar</pre>
611     END
612     @parser.parse(input).should == expected
613
614     # NAMED_ENTITY
615     input = dedent <<-END
616        foo
617        &raquo;bar
618     END
619     expected = dedent <<-END
620       <pre>foo
621       &raquo;bar</pre>
622     END
623     @parser.parse(input).should == expected
624
625     # DECIMAL_ENTITY
626     input = dedent <<-END
627        foo
628        &#1234;bar
629     END
630     expected = dedent <<-END
631       <pre>foo
632       &#1234;bar</pre>
633     END
634     @parser.parse(input).should == expected
635
636     # HEX_ENTITY
637     input = dedent <<-END
638        foo
639        &#x2022;bar
640     END
641     expected = dedent <<-END
642       <pre>foo
643       &#x2022;bar</pre>
644     END
645     @parser.parse(input).should == expected
646
647     # QUOT
648     input = dedent <<-END
649        foo
650        "bar
651     END
652     expected = dedent <<-END
653       <pre>foo
654       &quot;bar</pre>
655     END
656     @parser.parse(input).should == expected
657
658     # AMP
659     input = dedent <<-END
660        foo
661        &bar
662     END
663     expected = dedent <<-END
664       <pre>foo
665       &amp;bar</pre>
666     END
667     @parser.parse(input).should == expected
668
669     # LESS
670     input = dedent <<-END
671        foo
672        <bar
673     END
674     expected = dedent <<-END
675       <pre>foo
676       &lt;bar</pre>
677     END
678     @parser.parse(input).should == expected
679
680     # GREATER
681     input = dedent <<-END
682        foo
683        >bar
684     END
685     expected = dedent <<-END
686       <pre>foo
687       &gt;bar</pre>
688     END
689     @parser.parse(input).should == expected
690
691     # URI
692     input = dedent <<-END
693        foo
694        http://example.com/
695     END
696     expected = dedent <<-END
697       <pre>foo
698       <a href="http://example.com/" class="external">http://example.com/</a></pre>
699     END
700     @parser.parse(input).should == expected
701
702     # PRINTABLE
703     input = dedent <<-END
704        foo
705        bar
706     END
707     expected = dedent <<-END
708       <pre>foo
709       bar</pre>
710     END
711     @parser.parse(input).should == expected
712
713     # IMG_END
714     input = dedent <<-END
715        foo
716        }}bar
717     END
718     expected = dedent <<-END
719       <pre>foo
720       }}bar</pre>
721     END
722     @parser.parse(input).should == expected
723
724     # LEFT_CURLY
725     input = dedent <<-END
726        foo
727        {bar
728     END
729     expected = dedent <<-END
730       <pre>foo
731       {bar</pre>
732     END
733     @parser.parse(input).should == expected
734
735     # RIGHT_CURLY
736     input = dedent <<-END
737        foo
738        }bar
739     END
740     expected = dedent <<-END
741       <pre>foo
742       }bar</pre>
743     END
744     @parser.parse(input).should == expected
745
746     # DEFAULT
747     input = dedent <<-END
748        foo
749        €bar
750     END
751     expected = dedent <<-END
752       <pre>foo
753       &#x20ac;bar</pre>
754     END
755     @parser.parse(input).should == expected
756   end
757
758   # discovered at: http://rails.wincent.com/wiki/Testing_cookies_in_Rails
759   it 'should handle BLOCKQUOTE_START blocks which follow lists' do
760     # example text taken from wiki article and edited for brevity
761     input = dedent <<-END
762       * This article
763       <blockquote>The cookies</blockquote>
764     END
765     expected = dedent <<-END
766       <ul>
767         <li>This article</li>
768       </ul>
769       <blockquote>
770         <p>The cookies</p>
771       </blockquote>
772     END
773     @parser.parse(input).should == expected
774   end
775
776   # https://wincent.com/issues/818
777   it 'should handle BLOCKQUOTE_START blocks which follow BLOCKQUOTE shorthand' do
778     input = dedent <<-END
779       > foo
780       <blockquote>bar</blockquote>
781     END
782     expected = dedent <<-END
783       <blockquote>
784         <p>foo</p>
785       </blockquote>
786       <blockquote>
787         <p>bar</p>
788       </blockquote>
789     END
790     @parser.parse(input).should == expected
791   end
792
793   # https://wincent.com/issues/818
794   it 'should handle PRE_START blocks which follow BLOCKQUOTE shorthand' do
795     input = dedent <<-END
796       > foo
797       <pre>bar</pre>
798     END
799     expected = dedent <<-END
800       <blockquote>
801         <p>foo</p>
802       </blockquote>
803       <pre>bar</pre>
804     END
805     @parser.parse(input).should == expected
806   end
807
808   # https://wincent.com/issues/818
809   it 'should handle BLOCKQUOTE_START blocks which follow nested BLOCKQUOTE shorthand' do
810     input = dedent <<-END
811       >>> foo
812       <blockquote>bar</blockquote>
813     END
814     expected = dedent <<-END
815       <blockquote>
816         <blockquote>
817           <blockquote>
818             <p>foo</p>
819           </blockquote>
820         </blockquote>
821       </blockquote>
822       <blockquote>
823         <p>bar</p>
824       </blockquote>
825     END
826     @parser.parse(input).should == expected
827   end
828
829   # https://wincent.com/issues/818
830   it 'should handle PRE_START blocks which follow nested BLOCKQUOTE shorthand' do
831     input = dedent <<-END
832       >>> foo
833       <pre>bar</pre>
834     END
835     expected = dedent <<-END
836       <blockquote>
837         <blockquote>
838           <blockquote>
839             <p>foo</p>
840           </blockquote>
841         </blockquote>
842       </blockquote>
843       <pre>bar</pre>
844     END
845     @parser.parse(input).should == expected
846   end
847
848   # https://wincent.com/issues/1289
849   it 'should handle empty (zero-width) link targets' do
850     # these were badly broken (caused exceptions to be raised)
851     @parser.parse('[[]]').should == "<p>[[]]</p>\n"
852     @parser.parse('[[|]]').should == "<p>[[|]]</p>\n"
853     @parser.parse('[[|foo]]').should == "<p>[[|foo]]</p>\n"
854
855     # was working, but check here anyway to guard against regressions
856     @parser.parse('[[foo|]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n}
857   end
858
859   it 'should handle empty (whitespace only) link targets' do
860     # no exception raised, but clearly not desirable behaviour
861     # formerly these all returned: <p><a href="/wiki/"></a></p>\n
862     @parser.parse('[[ ]]').should == "<p>[[ ]]</p>\n"
863     @parser.parse('[[  ]]').should == "<p>[[  ]]</p>\n"
864     @parser.parse('[[  |]]').should == "<p>[[  |]]</p>\n"
865
866     # and this one returned: <p><a href="/wiki/">foo</a></p>\n
867     @parser.parse('[[  |foo]]').should == "<p>[[  |foo]]</p>\n"
868   end
869 end