]> git.wincent.com - wikitext.git/blob - spec/pre_spec.rb
4f70ed24cf27d87e4dd8c9e070b3059f81fc0aca
[wikitext.git] / spec / pre_spec.rb
1 # encoding: utf-8
2 # Copyright 2007-2010 Wincent Colaiuta. All rights reserved.
3 #
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are met:
6 #
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.
12
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.
24
25 require File.join(File.dirname(__FILE__), 'spec_helper.rb')
26
27 describe Wikitext::Parser, 'parsing PRE blocks' do
28   before do
29     @parser = Wikitext::Parser.new
30   end
31
32   it 'should recognize a single-line <pre> block' do
33     @parser.parse(' foo').should == "<pre>foo</pre>\n"
34   end
35
36   it 'should recognize a multiline <pre> block' do
37     @parser.parse(" foo\n bar").should == "<pre>foo\nbar</pre>\n"
38   end
39
40   it 'should handle "empty" lines in the middle of multiline PRE blocks' do
41     input = dedent <<-END
42        foo
43        
44        bar
45     END
46     expected = dedent <<-END
47       <pre>foo
48       
49       bar</pre>
50     END
51     @parser.parse(input).should == expected
52   end
53
54   it 'should render an empty block for an empty PRE block' do
55     @parser.parse(' ').should == "<pre></pre>\n"
56   end
57
58   it 'should sanely handle a leading empty line' do
59     @parser.parse(" \n foo").should == "<pre>\nfoo</pre>\n"
60   end
61
62   it 'should sanely handle a trailing empty line' do
63     @parser.parse(" foo\n \n").should == "<pre>foo\n</pre>\n"
64     @parser.parse(" foo\n ").should == "<pre>foo\n</pre>\n"
65   end
66
67   it 'should allow nesting inside a <blockquote> block' do
68     # nesting inside single blockquotes
69     @parser.parse(">  foo").should == "<blockquote>\n  <pre>foo</pre>\n</blockquote>\n"
70
71     # same, but continued over multiple lines
72     @parser.parse(">  foo\n>  bar").should == "<blockquote>\n  <pre>foo\nbar</pre>\n</blockquote>\n"
73
74     # nesting inside double blockquotes
75     expected = dedent <<-END
76       <blockquote>
77         <blockquote>
78           <pre>foo</pre>
79         </blockquote>
80       </blockquote>
81     END
82     @parser.parse("> >  foo").should == expected
83
84     # same, but continued over multiple lines
85     expected = dedent <<-END
86       <blockquote>
87         <blockquote>
88           <pre>foo
89       bar</pre>
90         </blockquote>
91       </blockquote>
92     END
93     @parser.parse("> >  foo\n> >  bar").should == expected
94   end
95
96   it 'should automatically close preceding blocks at the same depth' do
97     @parser.parse("> foo\n bar").should == "<blockquote>\n  <p>foo</p>\n</blockquote>\n<pre>bar</pre>\n"
98     expected = dedent <<-END
99       <blockquote>
100         <blockquote>
101           <p>foo</p>
102         </blockquote>
103       </blockquote>
104       <pre>bar</pre>
105     END
106     @parser.parse("> > foo\n bar").should == expected
107   end
108
109   it 'should pass <tt> and </tt> tags through without any special meaning' do
110     @parser.parse(' foo <tt>bar</tt>').should == "<pre>foo &lt;tt&gt;bar&lt;/tt&gt;</pre>\n"
111   end
112
113   it 'should pass <em> and </em> tags through without any special meaning' do
114     @parser.parse(" foo ''bar''").should == "<pre>foo ''bar''</pre>\n"
115   end
116
117   it 'should pass <strong> and </strong> tags through without any special meaning' do
118     @parser.parse(" foo '''bar'''").should == "<pre>foo '''bar'''</pre>\n"
119   end
120
121   it 'should pass combined <strong>/<em> and </strong>/</em> tags through without any special meaning' do
122     @parser.parse(" foo '''''bar'''''").should == "<pre>foo '''''bar'''''</pre>\n"
123   end
124
125   it 'should pass named entities through unchanged' do
126     @parser.parse(' &euro;').should == "<pre>&euro;</pre>\n"
127   end
128
129   it 'should pass numeric (decimal) entities through unchanged' do
130     @parser.parse(' &#8364;').should == "<pre>&#8364;</pre>\n"
131   end
132
133   it 'should pass numeric (hexadecimal) entities through unchanged' do
134     @parser.parse(' &#x20ac;').should == "<pre>&#x20ac;</pre>\n"
135     @parser.parse(' &#X20aC;').should == "<pre>&#x20ac;</pre>\n"
136   end
137
138   it 'should convert non-ASCII characters to numeric entities' do
139     @parser.parse(' €').should == "<pre>&#x20ac;</pre>\n"
140   end
141 end
142
143 describe Wikitext::Parser, 'parsing PRE_START/PRE_END blocks' do
144   before do
145     @parser = Wikitext::Parser.new
146   end
147
148   it 'should accept PRE_START/PRE_END as an alternative to the standard syntax' do
149     @parser.parse('<pre>foo</pre>').should == "<pre>foo</pre>\n"
150   end
151
152   it 'should pass through PRE unchanged in PRE_START/PRE_END blocks' do
153     input = dedent <<-END
154       <pre>line 1
155        next line</pre>
156     END
157     expected = dedent <<-END
158       <pre>line 1
159        next line</pre>
160     END
161     @parser.parse(input).should == expected
162   end
163
164   it 'should pass through short BLOCKQUOTE tokens as named entities in PRE_START/PRE_END blocks' do
165     input = dedent <<-END
166       <pre>line 1
167       >next line</pre>
168     END
169     expected = dedent <<-END
170       <pre>line 1
171       &gt;next line</pre>
172     END
173     @parser.parse(input).should == expected
174   end
175
176   it 'should pass through long BLOCKQUOTE tokens as named entities in PRE_START/PRE_END blocks' do
177     input = dedent <<-END
178       <pre>line 1
179       > next line</pre>
180     END
181     expected = dedent <<-END
182       <pre>line 1
183       &gt; next line</pre>
184     END
185     @parser.parse(input).should == expected
186   end
187
188   it 'should pass through EM unchanged in PRE_START/PRE_END blocks' do
189     @parser.parse("<pre>''</pre>").should == "<pre>''</pre>\n"
190   end
191
192   it 'should pass through STRONG unchanged in PRE_START/PRE_END blocks' do
193     @parser.parse("<pre>'''</pre>").should == "<pre>'''</pre>\n"
194   end
195
196   it 'should pass through STRONG_EM unchanged in PRE_START/PRE_END blocks' do
197     @parser.parse("<pre>'''''</pre>").should == "<pre>'''''</pre>\n"
198   end
199
200   it 'should pass through EM_START escaped in PRE_START/PRE_END blocks' do
201     @parser.parse("<pre><em></pre>").should == "<pre>&lt;em&gt;</pre>\n"
202   end
203
204   it 'should pass through EM_END escaped in PRE_START/PRE_END blocks' do
205     @parser.parse("<pre></em></pre>").should == "<pre>&lt;/em&gt;</pre>\n"
206   end
207
208   it 'should pass through STRONG_START escaped in PRE_START/PRE_END blocks' do
209     @parser.parse("<pre><strong></pre>").should == "<pre>&lt;strong&gt;</pre>\n"
210   end
211
212   it 'should pass through STRONG_END escaped in PRE_START/PRE_END blocks' do
213     @parser.parse("<pre></strong></pre>").should == "<pre>&lt;/strong&gt;</pre>\n"
214   end
215
216   it 'should pass through TT unchanged in PRE_START/PRE_END blocks' do
217     @parser.parse("<pre>`</pre>").should == "<pre>`</pre>\n"
218   end
219
220   it 'should pass through TT_START escaped in PRE_START/PRE_END blocks' do
221     @parser.parse("<pre><tt></pre>").should == "<pre>&lt;tt&gt;</pre>\n"
222   end
223
224   it 'should pass through TT_END escaped in PRE_START/PRE_END blocks' do
225     @parser.parse("<pre></tt></pre>").should == "<pre>&lt;/tt&gt;</pre>\n"
226   end
227
228   it 'should pass through UL unchanged in PRE_START/PRE_END blocks' do
229     @parser.parse("<pre>\n#</pre>").should == "<pre>\n#</pre>\n"
230   end
231
232   it 'should pass through OL unchanged in PRE_START/PRE_END blocks' do
233     @parser.parse("<pre>\n*</pre>").should == "<pre>\n*</pre>\n"
234   end
235
236   it 'should ignore PRE_START inside <nowiki> spans' do
237     @parser.parse('<nowiki><pre></nowiki>').should == "<p>&lt;pre&gt;</p>\n"
238   end
239
240   it 'should ignore PRE_END inside <nowiki> spans' do
241     @parser.parse('<nowiki></pre></nowiki>').should == "<p>&lt;/pre&gt;</p>\n"
242   end
243
244   it 'should ignore PRE_START inside standard PRE blocks' do
245     @parser.parse(' <pre>').should == "<pre>&lt;pre&gt;</pre>\n"
246   end
247
248   it 'should ignore PRE_END inside standard PRE blocks' do
249     @parser.parse(' </pre>').should == "<pre>&lt;/pre&gt;</pre>\n"
250   end
251
252   it 'should ignore PRE_START inside already open PRE_START blocks' do
253     @parser.parse('<pre><pre></pre>').should == "<pre>&lt;pre&gt;</pre>\n"
254   end
255
256   it 'should ignore PRE_START inside BLOCKQUOTE blocks' do
257     expected = dedent <<-END
258       <blockquote>
259         <p>&lt;pre&gt;</p>
260       </blockquote>
261     END
262     @parser.parse('> <pre>').should == expected
263   end
264
265   it 'should ignore PRE_END inside BLOCKQUOTE blocks' do
266     expected = dedent <<-END
267       <blockquote>
268         <p>&lt;/pre&gt;</p>
269       </blockquote>
270     END
271     @parser.parse('> </pre>').should == expected
272   end
273
274   it 'should break out of UL blocks on seeing PRE_START' do
275     expected = dedent <<-END
276       <ul>
277         <li>foo</li>
278       </ul>
279       <pre>bar</pre>
280     END
281     @parser.parse('* foo<pre>bar</pre>').should == expected
282   end
283
284   it 'should ignore PRE_END inside UL blocks' do
285     expected = dedent <<-END
286       <ul>
287         <li>&lt;/pre&gt;</li>
288       </ul>
289     END
290     @parser.parse('* </pre>').should == expected
291   end
292
293   it 'should break out of OL blocks on seeing PRE_START' do
294     expected = dedent <<-END
295       <ol>
296         <li>foo</li>
297       </ol>
298       <pre>bar</pre>
299     END
300     @parser.parse('# foo<pre>bar</pre>').should == expected
301   end
302
303   it 'should ignore PRE_END inside OL blocks' do
304     expected = dedent <<-END
305       <ol>
306         <li>&lt;/pre&gt;</li>
307       </ol>
308     END
309     @parser.parse('# </pre>').should == expected
310   end
311
312   it 'should break out of H1 blocks on seeing PRE_START' do
313     expected = dedent <<-END
314       <h1>foo</h1>
315       <pre>bar</pre>
316       <p> =</p>
317     END
318     @parser.parse('= foo<pre>bar</pre> =').should == expected
319   end
320
321   it 'should ignore PRE_END inside H1 blocks' do
322     @parser.parse('= </pre> =').should == "<h1>&lt;/pre&gt;</h1>\n"
323   end
324
325   it 'should break out of H2 blocks on seeing PRE_START' do
326     expected = dedent <<-END
327       <h2>foo</h2>
328       <pre>bar</pre>
329       <p> ==</p>
330     END
331     @parser.parse('== foo<pre>bar</pre> ==').should == expected
332   end
333
334   it 'should ignore PRE_END inside H2 blocks' do
335     @parser.parse('== </pre> ==').should == "<h2>&lt;/pre&gt;</h2>\n"
336   end
337
338   it 'should break out of H3 blocks on seeing PRE_START' do
339     expected = dedent <<-END
340       <h3>foo</h3>
341       <pre>bar</pre>
342       <p> ===</p>
343     END
344     @parser.parse('=== foo<pre>bar</pre> ===').should == expected
345   end
346
347   it 'should ignore PRE_END inside H3 blocks' do
348     @parser.parse('=== </pre> ===').should == "<h3>&lt;/pre&gt;</h3>\n"
349   end
350
351   it 'should break out of H4 blocks on seeing PRE_START' do
352     expected = dedent <<-END
353       <h4>foo</h4>
354       <pre>bar</pre>
355       <p> ====</p>
356     END
357     @parser.parse('==== foo<pre>bar</pre> ====').should == expected
358   end
359
360   it 'should ignore PRE_END inside H4 blocks' do
361     @parser.parse('==== </pre> ====').should == "<h4>&lt;/pre&gt;</h4>\n"
362   end
363
364   it 'should break out of H5 blocks on seeing PRE_START' do
365     expected = dedent <<-END
366       <h5>foo</h5>
367       <pre>bar</pre>
368       <p> =====</p>
369     END
370     @parser.parse('===== foo<pre>bar</pre> =====').should == expected
371   end
372
373   it 'should ignore PRE_END inside H5 blocks' do
374     @parser.parse('===== </pre> =====').should == "<h5>&lt;/pre&gt;</h5>\n"
375   end
376
377   it 'should break out of H6 blocks on seeing PRE_START' do
378     expected = dedent <<-END
379       <h6>foo</h6>
380       <pre>bar</pre>
381       <p> ======</p>
382     END
383     @parser.parse('====== foo<pre>bar</pre> ======').should == expected
384   end
385
386   it 'should ignore PRE_END inside H6 blocks' do
387     @parser.parse('====== </pre> ======').should == "<h6>&lt;/pre&gt;</h6>\n"
388   end
389
390   it 'should start a <pre> block on seeing PRE_START partway through a P block' do
391     # the trailing space after "hello" is preserved just like it would be if the input were "hello " and nothing else
392     expected = dedent <<-END
393       <p>hello </p>
394       <pre>world</pre>
395     END
396     @parser.parse('hello <pre>world</pre>').should == expected
397   end
398
399   it 'should close any open spans while starting a <pre> block on seeing PRE_START partway through a P block' do
400     # ''
401     expected = dedent <<-END
402       <p>hello <em>my </em></p>
403       <pre>world</pre>
404     END
405     @parser.parse("hello ''my <pre>world</pre>").should == expected
406
407     # '''
408     expected = dedent <<-END
409       <p>hello <strong>my </strong></p>
410       <pre>world</pre>
411     END
412     @parser.parse("hello '''my <pre>world</pre>").should == expected
413
414     # '''''
415     expected = dedent <<-END
416       <p>hello <strong><em>my </em></strong></p>
417       <pre>world</pre>
418     END
419     @parser.parse("hello '''''my <pre>world</pre>").should == expected
420
421     # `
422     expected = dedent <<-END
423       <p>hello <tt>my </tt></p>
424       <pre>world</pre>
425     END
426     @parser.parse("hello `my <pre>world</pre>").should == expected
427
428     # <em>
429     expected = dedent <<-END
430       <p>hello <em>my </em></p>
431       <pre>world</pre>
432     END
433     @parser.parse("hello <em>my <pre>world</pre>").should == expected
434
435     # <strong>
436     expected = dedent <<-END
437       <p>hello <strong>my </strong></p>
438       <pre>world</pre>
439     END
440     @parser.parse("hello <strong>my <pre>world</pre>").should == expected
441
442     # <strong><em>
443     expected = dedent <<-END
444       <p>hello <strong><em>my </em></strong></p>
445       <pre>world</pre>
446     END
447     @parser.parse("hello <strong><em>my <pre>world</pre>").should == expected
448
449     # <tt>
450     expected = dedent <<-END
451       <p>hello <tt>my </tt></p>
452       <pre>world</pre>
453     END
454     @parser.parse("hello <tt>my <pre>world</pre>").should == expected
455   end
456
457   it 'should rollback open internal link spans on encountering a PRE_START in the link target' do
458     expected = dedent <<-END
459       <p>[[hello </p>
460       <pre>world</pre>
461       <p>]]</p>
462     END
463     @parser.parse('[[hello <pre>world</pre>]]').should == expected
464   end
465
466   it 'should rollback open internal link spans on encountering a PRE_START in the link text' do
467     expected = dedent <<-END
468       <p>[[hello | there</p>
469       <pre>world</pre>
470       <p>]]</p>
471     END
472     @parser.parse('[[hello | there<pre>world</pre>]]').should == expected
473   end
474
475   it 'should automatically close open PRE_START blocks on hitting the end-of-file' do
476     @parser.parse('<pre>foo').should == "<pre>foo</pre>\n"
477   end
478
479   it 'should handle an optional "lang" attribute' do
480     @parser.parse('<pre lang="ruby">foo</pre>').should == %Q{<pre class="ruby-syntax">foo</pre>\n}
481   end
482
483   it 'should reject excess internal whitespace in PRE_START tags which have a "lang" attribute' do
484     @parser.parse('<pre  lang="ruby">foo</pre>').should == %Q{<p>&lt;pre  lang=&quot;ruby&quot;&gt;foo&lt;/pre&gt;</p>\n}
485     @parser.parse('<pre lang ="ruby">foo</pre>').should == %Q{<p>&lt;pre lang =&quot;ruby&quot;&gt;foo&lt;/pre&gt;</p>\n}
486     @parser.parse('<pre lang= "ruby">foo</pre>').should == %Q{<p>&lt;pre lang= &quot;ruby&quot;&gt;foo&lt;/pre&gt;</p>\n}
487     @parser.parse('<pre lang="ruby" >foo</pre>').should == %Q{<p>&lt;pre lang=&quot;ruby&quot; &gt;foo&lt;/pre&gt;</p>\n}
488   end
489
490   it 'should reject non-alpha characters in "lang" attribute' do
491     @parser.parse('<pre lang="obj-c">foo</pre>').should == %Q{<p>&lt;pre lang=&quot;obj-c&quot;&gt;foo&lt;/pre&gt;</p>\n}
492   end
493
494   it 'should reject empty "lang" attributes' do
495     @parser.parse('<pre lang="">foo</pre>').should == %Q{<p>&lt;pre lang=&quot;&quot;&gt;foo&lt;/pre&gt;</p>\n}
496   end
497 end