all repos — grayfriday @ 2b87b0e786d9ce5961b3c7f74df8a87ff1b01838

blackfriday fork with a few changes

block_test.go (view raw)

  1//
  2// Blackfriday Markdown Processor
  3// Available at http://github.com/russross/blackfriday
  4//
  5// Copyright © 2011 Russ Ross <russ@russross.com>.
  6// Distributed under the Simplified BSD License.
  7// See README.md for details.
  8//
  9
 10//
 11// Unit tests for block parsing
 12//
 13
 14package blackfriday
 15
 16import (
 17	"testing"
 18)
 19
 20func runMarkdownBlock(input string, extensions int) string {
 21	htmlFlags := 0
 22	htmlFlags |= HTML_USE_XHTML
 23
 24	renderer := HtmlRenderer(htmlFlags, "", "")
 25
 26	return string(Markdown([]byte(input), renderer, extensions))
 27}
 28
 29func doTestsBlock(t *testing.T, tests []string, extensions int) {
 30	// catch and report panics
 31	var candidate string
 32	defer func() {
 33		if err := recover(); err != nil {
 34			t.Errorf("\npanic while processing [%#v]\n", candidate)
 35		}
 36	}()
 37
 38	for i := 0; i+1 < len(tests); i += 2 {
 39		input := tests[i]
 40		candidate = input
 41		expected := tests[i+1]
 42		actual := runMarkdownBlock(candidate, extensions)
 43		if actual != expected {
 44			t.Errorf("\nInput   [%#v]\nExpected[%#v]\nActual  [%#v]",
 45				candidate, expected, actual)
 46		}
 47
 48		// now test every substring to stress test bounds checking
 49		if !testing.Short() {
 50			for start := 0; start < len(input); start++ {
 51				for end := start + 1; end <= len(input); end++ {
 52					candidate = input[start:end]
 53					_ = runMarkdownBlock(candidate, extensions)
 54				}
 55			}
 56		}
 57	}
 58}
 59
 60func TestPrefixHeaderNoExtensions(t *testing.T) {
 61	var tests = []string{
 62		"# Header 1\n",
 63		"<h1>Header 1</h1>\n",
 64
 65		"## Header 2\n",
 66		"<h2>Header 2</h2>\n",
 67
 68		"### Header 3\n",
 69		"<h3>Header 3</h3>\n",
 70
 71		"#### Header 4\n",
 72		"<h4>Header 4</h4>\n",
 73
 74		"##### Header 5\n",
 75		"<h5>Header 5</h5>\n",
 76
 77		"###### Header 6\n",
 78		"<h6>Header 6</h6>\n",
 79
 80		"####### Header 7\n",
 81		"<h6># Header 7</h6>\n",
 82
 83		"#Header 1\n",
 84		"<h1>Header 1</h1>\n",
 85
 86		"##Header 2\n",
 87		"<h2>Header 2</h2>\n",
 88
 89		"###Header 3\n",
 90		"<h3>Header 3</h3>\n",
 91
 92		"####Header 4\n",
 93		"<h4>Header 4</h4>\n",
 94
 95		"#####Header 5\n",
 96		"<h5>Header 5</h5>\n",
 97
 98		"######Header 6\n",
 99		"<h6>Header 6</h6>\n",
100
101		"#######Header 7\n",
102		"<h6>#Header 7</h6>\n",
103
104		"Hello\n# Header 1\nGoodbye\n",
105		"<p>Hello</p>\n\n<h1>Header 1</h1>\n\n<p>Goodbye</p>\n",
106
107		"* List\n# Header\n* List\n",
108		"<ul>\n<li><p>List</p>\n\n<h1>Header</h1></li>\n\n<li><p>List</p></li>\n</ul>\n",
109
110		"* List\n#Header\n* List\n",
111		"<ul>\n<li><p>List</p>\n\n<h1>Header</h1></li>\n\n<li><p>List</p></li>\n</ul>\n",
112
113		"*   List\n    * Nested list\n    # Nested header\n",
114		"<ul>\n<li><p>List</p>\n\n<ul>\n<li><p>Nested list</p>\n\n" +
115			"<h1>Nested header</h1></li>\n</ul></li>\n</ul>\n",
116	}
117	doTestsBlock(t, tests, 0)
118}
119
120func TestPrefixHeaderSpaceExtension(t *testing.T) {
121	var tests = []string{
122		"# Header 1\n",
123		"<h1>Header 1</h1>\n",
124
125		"## Header 2\n",
126		"<h2>Header 2</h2>\n",
127
128		"### Header 3\n",
129		"<h3>Header 3</h3>\n",
130
131		"#### Header 4\n",
132		"<h4>Header 4</h4>\n",
133
134		"##### Header 5\n",
135		"<h5>Header 5</h5>\n",
136
137		"###### Header 6\n",
138		"<h6>Header 6</h6>\n",
139
140		"####### Header 7\n",
141		"<p>####### Header 7</p>\n",
142
143		"#Header 1\n",
144		"<p>#Header 1</p>\n",
145
146		"##Header 2\n",
147		"<p>##Header 2</p>\n",
148
149		"###Header 3\n",
150		"<p>###Header 3</p>\n",
151
152		"####Header 4\n",
153		"<p>####Header 4</p>\n",
154
155		"#####Header 5\n",
156		"<p>#####Header 5</p>\n",
157
158		"######Header 6\n",
159		"<p>######Header 6</p>\n",
160
161		"#######Header 7\n",
162		"<p>#######Header 7</p>\n",
163
164		"Hello\n# Header 1\nGoodbye\n",
165		"<p>Hello</p>\n\n<h1>Header 1</h1>\n\n<p>Goodbye</p>\n",
166
167		"* List\n# Header\n* List\n",
168		"<ul>\n<li><p>List</p>\n\n<h1>Header</h1></li>\n\n<li><p>List</p></li>\n</ul>\n",
169
170		"* List\n#Header\n* List\n",
171		"<ul>\n<li>List\n#Header</li>\n<li>List</li>\n</ul>\n",
172
173		"*   List\n    * Nested list\n    # Nested header\n",
174		"<ul>\n<li><p>List</p>\n\n<ul>\n<li><p>Nested list</p>\n\n" +
175			"<h1>Nested header</h1></li>\n</ul></li>\n</ul>\n",
176	}
177	doTestsBlock(t, tests, EXTENSION_SPACE_HEADERS)
178}
179
180func TestUnderlineHeaders(t *testing.T) {
181	var tests = []string{
182		"Header 1\n========\n",
183		"<h1>Header 1</h1>\n",
184
185		"Header 2\n--------\n",
186		"<h2>Header 2</h2>\n",
187
188		"A\n=\n",
189		"<h1>A</h1>\n",
190
191		"B\n-\n",
192		"<h2>B</h2>\n",
193
194		"Paragraph\nHeader\n=\n",
195		"<p>Paragraph</p>\n\n<h1>Header</h1>\n",
196
197		"Header\n===\nParagraph\n",
198		"<h1>Header</h1>\n\n<p>Paragraph</p>\n",
199
200		"Header\n===\nAnother header\n---\n",
201		"<h1>Header</h1>\n\n<h2>Another header</h2>\n",
202
203		"   Header\n======\n",
204		"<h1>Header</h1>\n",
205
206		"    Code\n========\n",
207		"<pre><code>Code\n</code></pre>\n\n<p>========</p>\n",
208
209		"Header with *inline*\n=====\n",
210		"<h1>Header with <em>inline</em></h1>\n",
211
212		"*   List\n    * Sublist\n    Not a header\n    ------\n",
213		"<ul>\n<li>List\n\n<ul>\n<li>Sublist\nNot a header\n------</li>\n</ul></li>\n</ul>\n",
214
215		"Paragraph\n\n\n\n\nHeader\n===\n",
216		"<p>Paragraph</p>\n\n<h1>Header</h1>\n",
217
218		"Trailing space \n====        \n\n",
219		"<h1>Trailing space</h1>\n",
220
221		"Trailing spaces\n====        \n\n",
222		"<h1>Trailing spaces</h1>\n",
223
224		"Double underline\n=====\n=====\n",
225		"<h1>Double underline</h1>\n\n<p>=====</p>\n",
226	}
227	doTestsBlock(t, tests, 0)
228}
229
230func TestHorizontalRule(t *testing.T) {
231	var tests = []string{
232		"-\n",
233		"<p>-</p>\n",
234
235		"--\n",
236		"<p>--</p>\n",
237
238		"---\n",
239		"<hr />\n",
240
241		"----\n",
242		"<hr />\n",
243
244		"*\n",
245		"<p>*</p>\n",
246
247		"**\n",
248		"<p>**</p>\n",
249
250		"***\n",
251		"<hr />\n",
252
253		"****\n",
254		"<hr />\n",
255
256		"_\n",
257		"<p>_</p>\n",
258
259		"__\n",
260		"<p>__</p>\n",
261
262		"___\n",
263		"<hr />\n",
264
265		"____\n",
266		"<hr />\n",
267
268		"-*-\n",
269		"<p>-*-</p>\n",
270
271		"- - -\n",
272		"<hr />\n",
273
274		"* * *\n",
275		"<hr />\n",
276
277		"_ _ _\n",
278		"<hr />\n",
279
280		"-----*\n",
281		"<p>-----*</p>\n",
282
283		"   ------   \n",
284		"<hr />\n",
285
286		"Hello\n***\n",
287		"<p>Hello</p>\n\n<hr />\n",
288
289		"---\n***\n___\n",
290		"<hr />\n\n<hr />\n\n<hr />\n",
291	}
292	doTestsBlock(t, tests, 0)
293}
294
295func TestUnorderedList(t *testing.T) {
296	var tests = []string{
297		"* Hello\n",
298		"<ul>\n<li>Hello</li>\n</ul>\n",
299
300		"* Yin\n* Yang\n",
301		"<ul>\n<li>Yin</li>\n<li>Yang</li>\n</ul>\n",
302
303		"* Ting\n* Bong\n* Goo\n",
304		"<ul>\n<li>Ting</li>\n<li>Bong</li>\n<li>Goo</li>\n</ul>\n",
305
306		"* Yin\n\n* Yang\n",
307		"<ul>\n<li><p>Yin</p></li>\n\n<li><p>Yang</p></li>\n</ul>\n",
308
309		"* Ting\n\n* Bong\n* Goo\n",
310		"<ul>\n<li><p>Ting</p></li>\n\n<li><p>Bong</p></li>\n\n<li><p>Goo</p></li>\n</ul>\n",
311
312		"+ Hello\n",
313		"<ul>\n<li>Hello</li>\n</ul>\n",
314
315		"+ Yin\n+ Yang\n",
316		"<ul>\n<li>Yin</li>\n<li>Yang</li>\n</ul>\n",
317
318		"+ Ting\n+ Bong\n+ Goo\n",
319		"<ul>\n<li>Ting</li>\n<li>Bong</li>\n<li>Goo</li>\n</ul>\n",
320
321		"+ Yin\n\n+ Yang\n",
322		"<ul>\n<li><p>Yin</p></li>\n\n<li><p>Yang</p></li>\n</ul>\n",
323
324		"+ Ting\n\n+ Bong\n+ Goo\n",
325		"<ul>\n<li><p>Ting</p></li>\n\n<li><p>Bong</p></li>\n\n<li><p>Goo</p></li>\n</ul>\n",
326
327		"- Hello\n",
328		"<ul>\n<li>Hello</li>\n</ul>\n",
329
330		"- Yin\n- Yang\n",
331		"<ul>\n<li>Yin</li>\n<li>Yang</li>\n</ul>\n",
332
333		"- Ting\n- Bong\n- Goo\n",
334		"<ul>\n<li>Ting</li>\n<li>Bong</li>\n<li>Goo</li>\n</ul>\n",
335
336		"- Yin\n\n- Yang\n",
337		"<ul>\n<li><p>Yin</p></li>\n\n<li><p>Yang</p></li>\n</ul>\n",
338
339		"- Ting\n\n- Bong\n- Goo\n",
340		"<ul>\n<li><p>Ting</p></li>\n\n<li><p>Bong</p></li>\n\n<li><p>Goo</p></li>\n</ul>\n",
341
342		"*Hello\n",
343		"<p>*Hello</p>\n",
344
345		"*   Hello \n",
346		"<ul>\n<li>Hello</li>\n</ul>\n",
347
348		"*   Hello \n    Next line \n",
349		"<ul>\n<li>Hello\nNext line</li>\n</ul>\n",
350
351		"Paragraph\n* No linebreak\n",
352		"<p>Paragraph\n* No linebreak</p>\n",
353
354		"Paragraph\n\n* Linebreak\n",
355		"<p>Paragraph</p>\n\n<ul>\n<li>Linebreak</li>\n</ul>\n",
356
357		"*   List\n    * Nested list\n",
358		"<ul>\n<li>List\n\n<ul>\n<li>Nested list</li>\n</ul></li>\n</ul>\n",
359
360		"*   List\n\n    * Nested list\n",
361		"<ul>\n<li><p>List</p>\n\n<ul>\n<li>Nested list</li>\n</ul></li>\n</ul>\n",
362
363		"*   List\n    Second line\n\n    + Nested\n",
364		"<ul>\n<li><p>List\nSecond line</p>\n\n<ul>\n<li>Nested</li>\n</ul></li>\n</ul>\n",
365
366		"*   List\n    + Nested\n\n    Continued\n",
367		"<ul>\n<li><p>List</p>\n\n<ul>\n<li>Nested</li>\n</ul>\n\n<p>Continued</p></li>\n</ul>\n",
368
369		"*   List\n   * shallow indent\n",
370		"<ul>\n<li>List\n\n<ul>\n<li>shallow indent</li>\n</ul></li>\n</ul>\n",
371
372		"* List\n" +
373			" * shallow indent\n" +
374			"  * part of second list\n" +
375			"   * still second\n" +
376			"    * almost there\n" +
377			"     * third level\n",
378		"<ul>\n" +
379			"<li>List\n\n" +
380			"<ul>\n" +
381			"<li>shallow indent</li>\n" +
382			"<li>part of second list</li>\n" +
383			"<li>still second</li>\n" +
384			"<li>almost there\n\n" +
385			"<ul>\n" +
386			"<li>third level</li>\n" +
387			"</ul></li>\n" +
388			"</ul></li>\n" +
389			"</ul>\n",
390
391		"* List\n        extra indent, same paragraph\n",
392		"<ul>\n<li>List\n    extra indent, same paragraph</li>\n</ul>\n",
393
394		"* List\n\n        code block\n",
395		"<ul>\n<li><p>List</p>\n\n<pre><code>code block\n</code></pre></li>\n</ul>\n",
396
397		"* List\n\n          code block with spaces\n",
398		"<ul>\n<li><p>List</p>\n\n<pre><code>  code block with spaces\n</code></pre></li>\n</ul>\n",
399	}
400	doTestsBlock(t, tests, 0)
401}
402
403func TestOrderedList(t *testing.T) {
404	var tests = []string{
405		"1. Hello\n",
406		"<ol>\n<li>Hello</li>\n</ol>\n",
407
408		"1. Yin\n2. Yang\n",
409		"<ol>\n<li>Yin</li>\n<li>Yang</li>\n</ol>\n",
410
411		"1. Ting\n2. Bong\n3. Goo\n",
412		"<ol>\n<li>Ting</li>\n<li>Bong</li>\n<li>Goo</li>\n</ol>\n",
413
414		"1. Yin\n\n2. Yang\n",
415		"<ol>\n<li><p>Yin</p></li>\n\n<li><p>Yang</p></li>\n</ol>\n",
416
417		"1. Ting\n\n2. Bong\n3. Goo\n",
418		"<ol>\n<li><p>Ting</p></li>\n\n<li><p>Bong</p></li>\n\n<li><p>Goo</p></li>\n</ol>\n",
419
420		"1 Hello\n",
421		"<p>1 Hello</p>\n",
422
423		"1.Hello\n",
424		"<p>1.Hello</p>\n",
425
426		"1.  Hello \n",
427		"<ol>\n<li>Hello</li>\n</ol>\n",
428
429		"1.  Hello \n    Next line \n",
430		"<ol>\n<li>Hello\nNext line</li>\n</ol>\n",
431
432		"Paragraph\n1. No linebreak\n",
433		"<p>Paragraph\n1. No linebreak</p>\n",
434
435		"Paragraph\n\n1. Linebreak\n",
436		"<p>Paragraph</p>\n\n<ol>\n<li>Linebreak</li>\n</ol>\n",
437
438		"1.  List\n    1. Nested list\n",
439		"<ol>\n<li>List\n\n<ol>\n<li>Nested list</li>\n</ol></li>\n</ol>\n",
440
441		"1.  List\n\n    1. Nested list\n",
442		"<ol>\n<li><p>List</p>\n\n<ol>\n<li>Nested list</li>\n</ol></li>\n</ol>\n",
443
444		"1.  List\n    Second line\n\n    1. Nested\n",
445		"<ol>\n<li><p>List\nSecond line</p>\n\n<ol>\n<li>Nested</li>\n</ol></li>\n</ol>\n",
446
447		"1.  List\n    1. Nested\n\n    Continued\n",
448		"<ol>\n<li><p>List</p>\n\n<ol>\n<li>Nested</li>\n</ol>\n\n<p>Continued</p></li>\n</ol>\n",
449
450		"1.  List\n   1. shallow indent\n",
451		"<ol>\n<li>List\n\n<ol>\n<li>shallow indent</li>\n</ol></li>\n</ol>\n",
452
453		"1. List\n" +
454			" 1. shallow indent\n" +
455			"  2. part of second list\n" +
456			"   3. still second\n" +
457			"    4. almost there\n" +
458			"     1. third level\n",
459		"<ol>\n" +
460			"<li>List\n\n" +
461			"<ol>\n" +
462			"<li>shallow indent</li>\n" +
463			"<li>part of second list</li>\n" +
464			"<li>still second</li>\n" +
465			"<li>almost there\n\n" +
466			"<ol>\n" +
467			"<li>third level</li>\n" +
468			"</ol></li>\n" +
469			"</ol></li>\n" +
470			"</ol>\n",
471
472		"1. List\n        extra indent, same paragraph\n",
473		"<ol>\n<li>List\n    extra indent, same paragraph</li>\n</ol>\n",
474
475		"1. List\n\n        code block\n",
476		"<ol>\n<li><p>List</p>\n\n<pre><code>code block\n</code></pre></li>\n</ol>\n",
477
478		"1. List\n\n          code block with spaces\n",
479		"<ol>\n<li><p>List</p>\n\n<pre><code>  code block with spaces\n</code></pre></li>\n</ol>\n",
480
481		"1. List\n    * Mixted list\n",
482		"<ol>\n<li>List\n\n<ul>\n<li>Mixted list</li>\n</ul></li>\n</ol>\n",
483
484		"1. List\n * Mixed list\n",
485		"<ol>\n<li>List\n\n<ul>\n<li>Mixed list</li>\n</ul></li>\n</ol>\n",
486
487		"* Start with unordered\n 1. Ordered\n",
488		"<ul>\n<li>Start with unordered\n\n<ol>\n<li>Ordered</li>\n</ol></li>\n</ul>\n",
489
490		"* Start with unordered\n    1. Ordered\n",
491		"<ul>\n<li>Start with unordered\n\n<ol>\n<li>Ordered</li>\n</ol></li>\n</ul>\n",
492
493		"1. numbers\n1. are ignored\n",
494		"<ol>\n<li>numbers</li>\n<li>are ignored</li>\n</ol>\n",
495	}
496	doTestsBlock(t, tests, 0)
497}
498
499func TestPreformattedHtml(t *testing.T) {
500	var tests = []string{
501		"<div></div>\n",
502		"<div></div>\n",
503
504		"<div>\n</div>\n",
505		"<div>\n</div>\n",
506
507		"<div>\n</div>\nParagraph\n",
508		"<p><div>\n</div>\nParagraph</p>\n",
509
510		"<div class=\"foo\">\n</div>\n",
511		"<div class=\"foo\">\n</div>\n",
512
513		"<div>\nAnything here\n</div>\n",
514		"<div>\nAnything here\n</div>\n",
515
516		"<div>\n  Anything here\n</div>\n",
517		"<div>\n  Anything here\n</div>\n",
518
519		"<div>\nAnything here\n  </div>\n",
520		"<div>\nAnything here\n  </div>\n",
521
522		"<div>\nThis is *not* &proceessed\n</div>\n",
523		"<div>\nThis is *not* &proceessed\n</div>\n",
524
525		"<faketag>\n  Something\n</faketag>\n",
526		"<p><faketag>\n  Something\n</faketag></p>\n",
527
528		"<div>\n  Something here\n</divv>\n",
529		"<p><div>\n  Something here\n</divv></p>\n",
530
531		"Paragraph\n<div>\nHere? >&<\n</div>\n",
532		"<p>Paragraph\n<div>\nHere? &gt;&amp;&lt;\n</div></p>\n",
533
534		"Paragraph\n\n<div>\nHow about here? >&<\n</div>\n",
535		"<p>Paragraph</p>\n\n<div>\nHow about here? >&<\n</div>\n",
536
537		"Paragraph\n<div>\nHere? >&<\n</div>\nAnd here?\n",
538		"<p>Paragraph\n<div>\nHere? &gt;&amp;&lt;\n</div>\nAnd here?</p>\n",
539
540		"Paragraph\n\n<div>\nHow about here? >&<\n</div>\nAnd here?\n",
541		"<p>Paragraph</p>\n\n<p><div>\nHow about here? &gt;&amp;&lt;\n</div>\nAnd here?</p>\n",
542
543		"Paragraph\n<div>\nHere? >&<\n</div>\n\nAnd here?\n",
544		"<p>Paragraph\n<div>\nHere? &gt;&amp;&lt;\n</div></p>\n\n<p>And here?</p>\n",
545
546		"Paragraph\n\n<div>\nHow about here? >&<\n</div>\n\nAnd here?\n",
547		"<p>Paragraph</p>\n\n<div>\nHow about here? >&<\n</div>\n\n<p>And here?</p>\n",
548	}
549	doTestsBlock(t, tests, 0)
550}
551
552func TestPreformattedHtmlLax(t *testing.T) {
553	var tests = []string{
554		"Paragraph\n<div>\nHere? >&<\n</div>\n",
555		"<p>Paragraph</p>\n\n<div>\nHere? >&<\n</div>\n",
556
557		"Paragraph\n\n<div>\nHow about here? >&<\n</div>\n",
558		"<p>Paragraph</p>\n\n<div>\nHow about here? >&<\n</div>\n",
559
560		"Paragraph\n<div>\nHere? >&<\n</div>\nAnd here?\n",
561		"<p>Paragraph</p>\n\n<div>\nHere? >&<\n</div>\n\n<p>And here?</p>\n",
562
563		"Paragraph\n\n<div>\nHow about here? >&<\n</div>\nAnd here?\n",
564		"<p>Paragraph</p>\n\n<div>\nHow about here? >&<\n</div>\n\n<p>And here?</p>\n",
565
566		"Paragraph\n<div>\nHere? >&<\n</div>\n\nAnd here?\n",
567		"<p>Paragraph</p>\n\n<div>\nHere? >&<\n</div>\n\n<p>And here?</p>\n",
568
569		"Paragraph\n\n<div>\nHow about here? >&<\n</div>\n\nAnd here?\n",
570		"<p>Paragraph</p>\n\n<div>\nHow about here? >&<\n</div>\n\n<p>And here?</p>\n",
571	}
572	doTestsBlock(t, tests, EXTENSION_LAX_HTML_BLOCKS)
573}
574
575func TestFencedCodeBlock(t *testing.T) {
576	var tests = []string{
577		"``` go\nfunc foo() bool {\n\treturn true;\n}\n```\n",
578		"<pre><code class=\"go\">func foo() bool {\n    return true;\n}\n</code></pre>\n",
579
580		"``` c\n/* special & char < > \" escaping */\n```\n",
581		"<pre><code class=\"c\">/* special &amp; char &lt; &gt; &quot; escaping */\n</code></pre>\n",
582
583		"``` c\nno *inline* processing ~~of text~~\n```\n",
584		"<pre><code class=\"c\">no *inline* processing ~~of text~~\n</code></pre>\n",
585
586		"```\nNo language\n```\n",
587		"<pre><code>No language\n</code></pre>\n",
588
589		"``` {ocaml}\nlanguage in braces\n```\n",
590		"<pre><code class=\"ocaml\">language in braces\n</code></pre>\n",
591
592		"```    {ocaml}      \nwith extra whitespace\n```\n",
593		"<pre><code class=\"ocaml\">with extra whitespace\n</code></pre>\n",
594
595		"```{   ocaml   }\nwith extra whitespace\n```\n",
596		"<pre><code class=\"ocaml\">with extra whitespace\n</code></pre>\n",
597
598		"~ ~~ java\nWith whitespace\n~~~\n",
599		"<p>~ ~~ java\nWith whitespace\n~~~</p>\n",
600
601		"~~\nonly two\n~~\n",
602		"<p>~~\nonly two\n~~</p>\n",
603
604		"```` python\nextra\n````\n",
605		"<pre><code class=\"python\">extra\n</code></pre>\n",
606
607		"~~~ perl\nthree to start, four to end\n~~~~\n",
608		"<p>~~~ perl\nthree to start, four to end\n~~~~</p>\n",
609
610		"~~~~ perl\nfour to start, three to end\n~~~\n",
611		"<p>~~~~ perl\nfour to start, three to end\n~~~</p>\n",
612
613		"~~~ bash\ntildes\n~~~\n",
614		"<pre><code class=\"bash\">tildes\n</code></pre>\n",
615
616		"``` lisp\nno ending\n",
617		"<p>``` lisp\nno ending</p>\n",
618
619		"~~~ lisp\nend with language\n~~~ lisp\n",
620		"<p>~~~ lisp\nend with language\n~~~ lisp</p>\n",
621
622		"```\nmismatched begin and end\n~~~\n",
623		"<p>```\nmismatched begin and end\n~~~</p>\n",
624
625		"~~~\nmismatched begin and end\n```\n",
626		"<p>~~~\nmismatched begin and end\n```</p>\n",
627
628		"   ``` oz\nleading spaces\n```\n",
629		"<pre><code class=\"oz\">leading spaces\n</code></pre>\n",
630
631		"  ``` oz\nleading spaces\n ```\n",
632		"<pre><code class=\"oz\">leading spaces\n</code></pre>\n",
633
634		" ``` oz\nleading spaces\n  ```\n",
635		"<pre><code class=\"oz\">leading spaces\n</code></pre>\n",
636
637		"``` oz\nleading spaces\n   ```\n",
638		"<pre><code class=\"oz\">leading spaces\n</code></pre>\n",
639
640		"    ``` oz\nleading spaces\n    ```\n",
641		"<pre><code>``` oz\n</code></pre>\n\n<p>leading spaces\n    ```</p>\n",
642	}
643	doTestsBlock(t, tests, EXTENSION_FENCED_CODE)
644}