]> git.wincent.com - wikitext.git/blob - spec/pre_spec.rb
Add :pre_code option
[wikitext.git] / spec / pre_spec.rb
1 # Copyright 2007-present Greg Hurrell. All rights reserved.
2 #
3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions are met:
5 #
6 # 1. Redistributions of source code must retain the above copyright notice,
7 #    this list of conditions and the following disclaimer.
8 # 2. Redistributions in binary form must reproduce the above copyright notice,
9 #    this list of conditions and the following disclaimer in the documentation
10 #    and/or other materials provided with the distribution.
11 #
12 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
13 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
15 # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
16 # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
17 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
18 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
19 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
20 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
21 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
22 # POSSIBILITY OF SUCH DAMAGE.
23
24 require 'spec_helper'
25
26 describe Wikitext::Parser, 'parsing PRE blocks' do
27   before do
28     @parser = Wikitext::Parser.new
29   end
30
31   it 'should recognize a single-line <pre> block' do
32     @parser.parse(' foo').should == "<pre>foo</pre>\n"
33   end
34
35   it 'should recognize a multiline <pre> block' do
36     @parser.parse(" foo\n bar").should == "<pre>foo\nbar</pre>\n"
37   end
38
39   it 'should handle "empty" lines in the middle of multiline PRE blocks' do
40     input = dedent <<-END
41        foo
42        
43        bar
44     END
45     expected = dedent <<-END
46       <pre>foo
47       
48       bar</pre>
49     END
50     @parser.parse(input).should == expected
51   end
52
53   it 'should render an empty block for an empty PRE block' do
54     @parser.parse(' ').should == "<pre></pre>\n"
55   end
56
57   it 'assumes PRE blocks are code when :pre_code is set' do
58     Wikitext::Parser.
59       new(:pre_code => true).
60       parse(' foo').
61       should == "<pre><code>foo</code></pre>\n"
62   end
63
64   it 'should sanely handle a leading empty line' do
65     @parser.parse(" \n foo").should == "<pre>\nfoo</pre>\n"
66   end
67
68   it 'should sanely handle a trailing empty line' do
69     @parser.parse(" foo\n \n").should == "<pre>foo\n</pre>\n"
70     @parser.parse(" foo\n ").should == "<pre>foo\n</pre>\n"
71   end
72
73   it 'should allow nesting inside a <blockquote> block' do
74     # nesting inside single blockquotes
75     @parser.parse(">  foo").should == "<blockquote>\n  <pre>foo</pre>\n</blockquote>\n"
76
77     # same, but continued over multiple lines
78     @parser.parse(">  foo\n>  bar").should == "<blockquote>\n  <pre>foo\nbar</pre>\n</blockquote>\n"
79
80     # nesting inside double blockquotes
81     expected = dedent <<-END
82       <blockquote>
83         <blockquote>
84           <pre>foo</pre>
85         </blockquote>
86       </blockquote>
87     END
88     @parser.parse("> >  foo").should == expected
89
90     # same, but continued over multiple lines
91     expected = dedent <<-END
92       <blockquote>
93         <blockquote>
94           <pre>foo
95       bar</pre>
96         </blockquote>
97       </blockquote>
98     END
99     @parser.parse("> >  foo\n> >  bar").should == expected
100   end
101
102   it 'should automatically close preceding blocks at the same depth' do
103     @parser.parse("> foo\n bar").should == "<blockquote>\n  <p>foo</p>\n</blockquote>\n<pre>bar</pre>\n"
104     expected = dedent <<-END
105       <blockquote>
106         <blockquote>
107           <p>foo</p>
108         </blockquote>
109       </blockquote>
110       <pre>bar</pre>
111     END
112     @parser.parse("> > foo\n bar").should == expected
113   end
114
115   it 'should pass <tt> and </tt> tags through without any special meaning' do
116     @parser.parse(' foo <tt>bar</tt>').should == "<pre>foo &lt;tt&gt;bar&lt;/tt&gt;</pre>\n"
117   end
118
119   it 'should pass <em> and </em> tags through without any special meaning' do
120     @parser.parse(" foo ''bar''").should == "<pre>foo ''bar''</pre>\n"
121   end
122
123   it 'should pass <strong> and </strong> tags through without any special meaning' do
124     @parser.parse(" foo '''bar'''").should == "<pre>foo '''bar'''</pre>\n"
125   end
126
127   it 'should pass combined <strong>/<em> and </strong>/</em> tags through without any special meaning' do
128     @parser.parse(" foo '''''bar'''''").should == "<pre>foo '''''bar'''''</pre>\n"
129   end
130
131   it 'should pass named entities through unchanged' do
132     @parser.parse(' &euro;').should == "<pre>&euro;</pre>\n"
133   end
134
135   it 'should pass numeric (decimal) entities through unchanged' do
136     @parser.parse(' &#8364;').should == "<pre>&#8364;</pre>\n"
137   end
138
139   it 'should pass numeric (hexadecimal) entities through unchanged' do
140     @parser.parse(' &#x20ac;').should == "<pre>&#x20ac;</pre>\n"
141     @parser.parse(' &#X20aC;').should == "<pre>&#x20ac;</pre>\n"
142   end
143
144   it 'should convert non-ASCII characters to numeric entities' do
145     @parser.parse(' €').should == "<pre>&#x20ac;</pre>\n"
146   end
147 end
148
149 describe Wikitext::Parser, 'parsing PRE_START/PRE_END blocks' do
150   before do
151     @parser = Wikitext::Parser.new
152   end
153
154   it 'should accept PRE_START/PRE_END as an alternative to the standard syntax' do
155     @parser.parse('<pre>foo</pre>').should == "<pre>foo</pre>\n"
156   end
157
158   it 'assumes PRE_START/PRE_END blocks are code when :pre_code is set' do
159     Wikitext::Parser.
160       new(:pre_code => true).
161       parse('<pre>foo</pre>').
162       should == "<pre><code>foo</code></pre>\n"
163   end
164
165   it 'should pass through PRE unchanged in PRE_START/PRE_END blocks' do
166     input = dedent <<-END
167       <pre>line 1
168        next line</pre>
169     END
170     expected = dedent <<-END
171       <pre>line 1
172        next line</pre>
173     END
174     @parser.parse(input).should == expected
175   end
176
177   it 'should pass through short BLOCKQUOTE tokens as named entities in PRE_START/PRE_END blocks' do
178     input = dedent <<-END
179       <pre>line 1
180       >next line</pre>
181     END
182     expected = dedent <<-END
183       <pre>line 1
184       &gt;next line</pre>
185     END
186     @parser.parse(input).should == expected
187   end
188
189   it 'should pass through long BLOCKQUOTE tokens as named entities in PRE_START/PRE_END blocks' do
190     input = dedent <<-END
191       <pre>line 1
192       > next line</pre>
193     END
194     expected = dedent <<-END
195       <pre>line 1
196       &gt; next line</pre>
197     END
198     @parser.parse(input).should == expected
199   end
200
201   it 'should pass through EM unchanged in PRE_START/PRE_END blocks' do
202     @parser.parse("<pre>''</pre>").should == "<pre>''</pre>\n"
203   end
204
205   it 'should pass through STRONG unchanged in PRE_START/PRE_END blocks' do
206     @parser.parse("<pre>'''</pre>").should == "<pre>'''</pre>\n"
207   end
208
209   it 'should pass through STRONG_EM unchanged in PRE_START/PRE_END blocks' do
210     @parser.parse("<pre>'''''</pre>").should == "<pre>'''''</pre>\n"
211   end
212
213   it 'should pass through EM_START escaped in PRE_START/PRE_END blocks' do
214     @parser.parse("<pre><em></pre>").should == "<pre>&lt;em&gt;</pre>\n"
215   end
216
217   it 'should pass through EM_END escaped in PRE_START/PRE_END blocks' do
218     @parser.parse("<pre></em></pre>").should == "<pre>&lt;/em&gt;</pre>\n"
219   end
220
221   it 'should pass through STRONG_START escaped in PRE_START/PRE_END blocks' do
222     @parser.parse("<pre><strong></pre>").should == "<pre>&lt;strong&gt;</pre>\n"
223   end
224
225   it 'should pass through STRONG_END escaped in PRE_START/PRE_END blocks' do
226     @parser.parse("<pre></strong></pre>").should == "<pre>&lt;/strong&gt;</pre>\n"
227   end
228
229   it 'should pass through TT unchanged in PRE_START/PRE_END blocks' do
230     @parser.parse("<pre>`</pre>").should == "<pre>`</pre>\n"
231   end
232
233   it 'should pass through TT_START escaped in PRE_START/PRE_END blocks' do
234     @parser.parse("<pre><tt></pre>").should == "<pre>&lt;tt&gt;</pre>\n"
235   end
236
237   it 'should pass through TT_END escaped in PRE_START/PRE_END blocks' do
238     @parser.parse("<pre></tt></pre>").should == "<pre>&lt;/tt&gt;</pre>\n"
239   end
240
241   it 'should pass through UL unchanged in PRE_START/PRE_END blocks' do
242     @parser.parse("<pre>\n#</pre>").should == "<pre>\n#</pre>\n"
243   end
244
245   it 'should pass through OL unchanged in PRE_START/PRE_END blocks' do
246     @parser.parse("<pre>\n*</pre>").should == "<pre>\n*</pre>\n"
247   end
248
249   it 'should ignore PRE_START inside <nowiki> spans' do
250     @parser.parse('<nowiki><pre></nowiki>').should == "<p>&lt;pre&gt;</p>\n"
251   end
252
253   it 'should ignore PRE_END inside <nowiki> spans' do
254     @parser.parse('<nowiki></pre></nowiki>').should == "<p>&lt;/pre&gt;</p>\n"
255   end
256
257   it 'should ignore PRE_START inside standard PRE blocks' do
258     @parser.parse(' <pre>').should == "<pre>&lt;pre&gt;</pre>\n"
259   end
260
261   it 'should ignore PRE_END inside standard PRE blocks' do
262     @parser.parse(' </pre>').should == "<pre>&lt;/pre&gt;</pre>\n"
263   end
264
265   it 'should ignore PRE_START inside already open PRE_START blocks' do
266     @parser.parse('<pre><pre></pre>').should == "<pre>&lt;pre&gt;</pre>\n"
267   end
268
269   it 'should ignore PRE_START inside BLOCKQUOTE blocks' do
270     expected = dedent <<-END
271       <blockquote>
272         <p>&lt;pre&gt;</p>
273       </blockquote>
274     END
275     @parser.parse('> <pre>').should == expected
276   end
277
278   it 'should ignore PRE_END inside BLOCKQUOTE blocks' do
279     expected = dedent <<-END
280       <blockquote>
281         <p>&lt;/pre&gt;</p>
282       </blockquote>
283     END
284     @parser.parse('> </pre>').should == expected
285   end
286
287   it 'should break out of UL blocks on seeing PRE_START' do
288     expected = dedent <<-END
289       <ul>
290         <li>foo</li>
291       </ul>
292       <pre>bar</pre>
293     END
294     @parser.parse('* foo<pre>bar</pre>').should == expected
295   end
296
297   it 'should ignore PRE_END inside UL blocks' do
298     expected = dedent <<-END
299       <ul>
300         <li>&lt;/pre&gt;</li>
301       </ul>
302     END
303     @parser.parse('* </pre>').should == expected
304   end
305
306   it 'should break out of OL blocks on seeing PRE_START' do
307     expected = dedent <<-END
308       <ol>
309         <li>foo</li>
310       </ol>
311       <pre>bar</pre>
312     END
313     @parser.parse('# foo<pre>bar</pre>').should == expected
314   end
315
316   it 'should ignore PRE_END inside OL blocks' do
317     expected = dedent <<-END
318       <ol>
319         <li>&lt;/pre&gt;</li>
320       </ol>
321     END
322     @parser.parse('# </pre>').should == expected
323   end
324
325   it 'should break out of H1 blocks on seeing PRE_START' do
326     expected = dedent <<-END
327       <h1>foo</h1>
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 H1 blocks' do
335     @parser.parse('= </pre> =').should == "<h1>&lt;/pre&gt;</h1>\n"
336   end
337
338   it 'should break out of H2 blocks on seeing PRE_START' do
339     expected = dedent <<-END
340       <h2>foo</h2>
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 H2 blocks' do
348     @parser.parse('== </pre> ==').should == "<h2>&lt;/pre&gt;</h2>\n"
349   end
350
351   it 'should break out of H3 blocks on seeing PRE_START' do
352     expected = dedent <<-END
353       <h3>foo</h3>
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 H3 blocks' do
361     @parser.parse('=== </pre> ===').should == "<h3>&lt;/pre&gt;</h3>\n"
362   end
363
364   it 'should break out of H4 blocks on seeing PRE_START' do
365     expected = dedent <<-END
366       <h4>foo</h4>
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 H4 blocks' do
374     @parser.parse('==== </pre> ====').should == "<h4>&lt;/pre&gt;</h4>\n"
375   end
376
377   it 'should break out of H5 blocks on seeing PRE_START' do
378     expected = dedent <<-END
379       <h5>foo</h5>
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 H5 blocks' do
387     @parser.parse('===== </pre> =====').should == "<h5>&lt;/pre&gt;</h5>\n"
388   end
389
390   it 'should break out of H6 blocks on seeing PRE_START' do
391     expected = dedent <<-END
392       <h6>foo</h6>
393       <pre>bar</pre>
394       <p> ======</p>
395     END
396     @parser.parse('====== foo<pre>bar</pre> ======').should == expected
397   end
398
399   it 'should ignore PRE_END inside H6 blocks' do
400     @parser.parse('====== </pre> ======').should == "<h6>&lt;/pre&gt;</h6>\n"
401   end
402
403   it 'should start a <pre> block on seeing PRE_START partway through a P block' do
404     # the trailing space after "hello" is preserved just like it would be if the input were "hello " and nothing else
405     expected = dedent <<-END
406       <p>hello </p>
407       <pre>world</pre>
408     END
409     @parser.parse('hello <pre>world</pre>').should == expected
410   end
411
412   it 'should close any open spans while starting a <pre> block on seeing PRE_START partway through a P block' do
413     # ''
414     expected = dedent <<-END
415       <p>hello <em>my </em></p>
416       <pre>world</pre>
417     END
418     @parser.parse("hello ''my <pre>world</pre>").should == expected
419
420     # '''
421     expected = dedent <<-END
422       <p>hello <strong>my </strong></p>
423       <pre>world</pre>
424     END
425     @parser.parse("hello '''my <pre>world</pre>").should == expected
426
427     # '''''
428     expected = dedent <<-END
429       <p>hello <strong><em>my </em></strong></p>
430       <pre>world</pre>
431     END
432     @parser.parse("hello '''''my <pre>world</pre>").should == expected
433
434     # `
435     expected = dedent <<-END
436       <p>hello <code>my </code></p>
437       <pre>world</pre>
438     END
439     @parser.parse("hello `my <pre>world</pre>").should == expected
440
441     # <em>
442     expected = dedent <<-END
443       <p>hello <em>my </em></p>
444       <pre>world</pre>
445     END
446     @parser.parse("hello <em>my <pre>world</pre>").should == expected
447
448     # <strong>
449     expected = dedent <<-END
450       <p>hello <strong>my </strong></p>
451       <pre>world</pre>
452     END
453     @parser.parse("hello <strong>my <pre>world</pre>").should == expected
454
455     # <strong><em>
456     expected = dedent <<-END
457       <p>hello <strong><em>my </em></strong></p>
458       <pre>world</pre>
459     END
460     @parser.parse("hello <strong><em>my <pre>world</pre>").should == expected
461
462     # <tt>
463     expected = dedent <<-END
464       <p>hello <code>my </code></p>
465       <pre>world</pre>
466     END
467     @parser.parse("hello <tt>my <pre>world</pre>").should == expected
468   end
469
470   it 'should rollback open internal link spans on encountering a PRE_START in the link target' do
471     expected = dedent <<-END
472       <p>[[hello </p>
473       <pre>world</pre>
474       <p>]]</p>
475     END
476     @parser.parse('[[hello <pre>world</pre>]]').should == expected
477   end
478
479   it 'should rollback open internal link spans on encountering a PRE_START in the link text' do
480     expected = dedent <<-END
481       <p>[[hello | there</p>
482       <pre>world</pre>
483       <p>]]</p>
484     END
485     @parser.parse('[[hello | there<pre>world</pre>]]').should == expected
486   end
487
488   it 'should automatically close open PRE_START blocks on hitting the end-of-file' do
489     @parser.parse('<pre>foo').should == "<pre>foo</pre>\n"
490   end
491
492   it 'should handle an optional "lang" attribute' do
493     @parser.parse('<pre lang="ruby">foo</pre>').should == %Q{<pre class="ruby-syntax">foo</pre>\n}
494   end
495
496   it 'should reject excess internal whitespace in PRE_START tags which have a "lang" attribute' do
497     @parser.parse('<pre  lang="ruby">foo</pre>').should == %Q{<p>&lt;pre  lang=&quot;ruby&quot;&gt;foo&lt;/pre&gt;</p>\n}
498     @parser.parse('<pre lang ="ruby">foo</pre>').should == %Q{<p>&lt;pre lang =&quot;ruby&quot;&gt;foo&lt;/pre&gt;</p>\n}
499     @parser.parse('<pre lang= "ruby">foo</pre>').should == %Q{<p>&lt;pre lang= &quot;ruby&quot;&gt;foo&lt;/pre&gt;</p>\n}
500     @parser.parse('<pre lang="ruby" >foo</pre>').should == %Q{<p>&lt;pre lang=&quot;ruby&quot; &gt;foo&lt;/pre&gt;</p>\n}
501   end
502
503   it 'should reject non-alpha characters in "lang" attribute' do
504     @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}
505   end
506
507   it 'should reject empty "lang" attributes' do
508     @parser.parse('<pre lang="">foo</pre>').should == %Q{<p>&lt;pre lang=&quot;&quot;&gt;foo&lt;/pre&gt;</p>\n}
509   end
510 end