PHP and Javascript implementations of a simple markdown parser
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

BlockTests.js 9.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. class BlockTests extends BaseTest {
  2. /** @type {Markdown} */
  3. parser;
  4. md(markdown) {
  5. return normalizeWhitespace(this.parser.toHTML(markdown));
  6. }
  7. setUp() {
  8. this.parser = Markdown.completeParser;
  9. }
  10. test_paragraphs() {
  11. let markdown = "Lorem ipsum\n\nDolor sit amet";
  12. let expected = "<p>Lorem ipsum</p> <p>Dolor sit amet</p>";
  13. let actual = this.md(markdown);
  14. this.assertEqual(actual, expected);
  15. }
  16. test_paragraph_lineGrouping() {
  17. let markdown = "Lorem ipsum\ndolor sit amet";
  18. let expected = "Lorem ipsum dolor sit amet";
  19. let actual = this.md(markdown);
  20. this.assertEqual(actual, expected);
  21. }
  22. test_header_underlineH1() {
  23. let markdown = "Header 1\n===\n\nLorem ipsum";
  24. let expected = "<h1>Header 1</h1> <p>Lorem ipsum</p>";
  25. let actual = this.md(markdown);
  26. this.assertEqual(actual, expected);
  27. }
  28. test_header_underlineH2() {
  29. let markdown = "Header 2\n---\n\nLorem ipsum";
  30. let expected = "<h2>Header 2</h2> <p>Lorem ipsum</p>";
  31. let actual = this.md(markdown);
  32. this.assertEqual(actual, expected);
  33. }
  34. test_header_hash() {
  35. let markdown = "# Header 1\n## Header 2\n### Header 3\n#### Header 4\n##### Header 5\n###### Header 6\n";
  36. let expected = '<h1>Header 1</h1> <h2>Header 2</h2> <h3>Header 3</h3> <h4>Header 4</h4> <h5>Header 5</h5> <h6>Header 6</h6>';
  37. let actual = this.md(markdown);
  38. this.assertEqual(actual, expected);
  39. }
  40. test_header_hash_trailing() {
  41. let markdown = "# Header 1 #\n## Header 2 ##\n### Header 3 ######";
  42. let expected = '<h1>Header 1</h1> <h2>Header 2</h2> <h3>Header 3</h3>';
  43. let actual = this.md(markdown);
  44. this.assertEqual(actual, expected);
  45. }
  46. test_unorderedList() {
  47. let markdown = "* Lorem\n* Ipsum\n* Dolor";
  48. let expected = '<ul> <li>Lorem</li> <li>Ipsum</li> <li>Dolor</li> </ul>';
  49. let actual = this.md(markdown);
  50. this.assertEqual(actual, expected);
  51. }
  52. test_unorderedList_nested() {
  53. let markdown = "* Lorem\n + Ipsum\n* Dolor";
  54. let expected = '<ul> <li>Lorem<ul> <li>Ipsum</li> </ul> </li> <li>Dolor</li> </ul>';
  55. let actual = this.md(markdown);
  56. this.assertEqual(actual, expected);
  57. }
  58. test_unorderedList_hitch() {
  59. // This incomplete bulleted list locked up the browser at one
  60. // point, not forever but a REALLY long time
  61. this.profile(1.0, () => {
  62. let markdown = "Testing\n\n* ";
  63. let expected = '<p>Testing</p> <ul> <li></li> </ul>';
  64. let actual = this.md(markdown);
  65. this.assertEqual(actual, expected);
  66. });
  67. }
  68. test_orderedList() {
  69. let markdown = "1. Lorem\n1. Ipsum\n5. Dolor";
  70. let expected = '<ol> <li>Lorem</li> <li>Ipsum</li> <li>Dolor</li> </ol>';
  71. let actual = this.md(markdown);
  72. this.assertEqual(actual, expected);
  73. }
  74. test_orderedList_numbering() {
  75. let markdown = "4. Lorem\n1. Ipsum\n9. Dolor";
  76. let expected = '<ol start="4"> <li>Lorem</li> <li>Ipsum</li> <li>Dolor</li> </ol>';
  77. let actual = this.md(markdown);
  78. this.assertEqual(actual, expected);
  79. }
  80. test_orderedList_nested1() {
  81. let markdown = "1. Lorem\n 1. Ipsum\n1. Dolor";
  82. let expected = '<ol> <li>Lorem<ol> <li>Ipsum</li> </ol> </li> <li>Dolor</li> </ol>';
  83. let actual = this.md(markdown);
  84. this.assertEqual(actual, expected);
  85. }
  86. test_orderedList_nested2() {
  87. let markdown = "1. Lorem\n 1. Ipsum\n 1. Dolor\n 1. Sit\n1. Amet";
  88. let expected = '<ol> <li>Lorem<ol> <li>Ipsum<ol> <li>Dolor</li> </ol> </li> <li>Sit</li> </ol> </li> <li>Amet</li> </ol>';
  89. let actual = this.md(markdown);
  90. this.assertEqual(actual, expected);
  91. }
  92. test_blockquote() {
  93. let markdown = '> Lorem ipsum dolor';
  94. let expected = '<blockquote>Lorem ipsum dolor</blockquote>';
  95. let actual = this.md(markdown);
  96. this.assertEqual(actual, expected);
  97. }
  98. test_blockquote_paragraphs() {
  99. let markdown = '> Lorem ipsum dolor\n>\n>Sit amet';
  100. let expected = '<blockquote> <p>Lorem ipsum dolor</p> <p>Sit amet</p> </blockquote>';
  101. let actual = this.md(markdown);
  102. this.assertEqual(actual, expected);
  103. }
  104. test_blockquote_list() {
  105. let markdown = '> 1. Lorem\n> 2. Ipsum';
  106. let expected = '<blockquote> <ol> <li>Lorem</li> <li>Ipsum</li> </ol> </blockquote>';
  107. let actual = this.md(markdown);
  108. this.assertEqual(actual, expected);
  109. }
  110. test_codeBlock_indented() {
  111. let markdown = "Code\n\n function foo() {\n return 'bar';\n }\n\nend";
  112. let expected = "<p>Code</p>\n\n<pre><code>function foo() {\n return 'bar';\n}</code></pre>\n\n<p>end</p>";
  113. let actual = this.parser.toHTML(markdown).trim(); // don't normalize whitespace
  114. this.assertEqual(actual.replace(/ /g, '⎵'), expected.replace(/ /g, '⎵'));
  115. }
  116. test_codeBlock_fenced() {
  117. let markdown = "Code\n\n```\nfunction foo() {\n return 'bar';\n}\n```\n\nend";
  118. let expected = "<p>Code</p>\n\n<pre><code>function foo() {\n return 'bar';\n}</code></pre>\n\n<p>end</p>";
  119. let actual = this.parser.toHTML(markdown).trim(); // don't normalize whitespace
  120. this.assertEqual(actual.replace(/ /g, '⎵'), expected.replace(/ /g, '⎵'));
  121. }
  122. test_codeBlock_fenced_language() {
  123. let markdown = "Code\n\n```javascript\nfunction foo() {\n return 'bar';\n}\n```\n\nend";
  124. let expected = "<p>Code</p>\n\n<pre><code class=\"language-javascript\">function foo() {\n return 'bar';\n}</code></pre>\n\n<p>end</p>";
  125. let actual = this.parser.toHTML(markdown).trim(); // don't normalize whitespace
  126. this.assertEqual(actual.replace(/ /g, '⎵'), expected.replace(/ /g, '⎵'));
  127. }
  128. test_horizontalRule() {
  129. let markdown = "Before\n\n---\n\n- - -\n\n***\n\n* * * * * * *\n\nafter";
  130. let expected = "<p>Before</p> <hr> <hr> <hr> <hr> <p>after</p>";
  131. let actual = this.md(markdown);
  132. this.assertEqual(actual, expected);
  133. }
  134. test_table_unfenced() {
  135. let markdown = "Column A | Column B | Column C\n--- | --- | ---\n1 | 2 | 3\n4 | 5 | 6";
  136. let expected = "<table> <thead> <tr> <th>Column A</th> <th>Column B</th> <th>Column C</th> </tr> </thead> <tbody> <tr> <td>1</td> <td>2</td> <td>3</td> </tr> <tr> <td>4</td> <td>5</td> <td>6</td> </tr> </tbody> </table>";
  137. let actual = this.md(markdown);
  138. this.assertEqual(actual, expected);
  139. }
  140. test_table_fenced() {
  141. let markdown = "| Column A | Column B | Column C |\n| --- | --- | --- |\n| 1 | 2 | 3\n4 | 5 | 6 |";
  142. let expected = "<table> <thead> <tr> <th>Column A</th> <th>Column B</th> <th>Column C</th> </tr> </thead> <tbody> <tr> <td>1</td> <td>2</td> <td>3</td> </tr> <tr> <td>4</td> <td>5</td> <td>6</td> </tr> </tbody> </table>";
  143. let actual = this.md(markdown);
  144. this.assertEqual(actual, expected);
  145. }
  146. test_table_alignment() {
  147. let markdown = 'Column A | Column B | Column C\n' +
  148. ':--- | :---: | ---:\n' +
  149. '1 | 2 | 3\n' +
  150. '4 | 5 | 6';
  151. let expected = '<table> ' +
  152. '<thead> ' +
  153. '<tr> ' +
  154. '<th style="text-align: left;">Column A</th> ' +
  155. '<th style="text-align: center;">Column B</th> ' +
  156. '<th style="text-align: right;">Column C</th> ' +
  157. '</tr> ' +
  158. '</thead> ' +
  159. '<tbody> ' +
  160. '<tr> ' +
  161. '<td style="text-align: left;">1</td> ' +
  162. '<td style="text-align: center;">2</td> ' +
  163. '<td style="text-align: right;">3</td> ' +
  164. '</tr> ' +
  165. '<tr> ' +
  166. '<td style="text-align: left;">4</td> ' +
  167. '<td style="text-align: center;">5</td> ' +
  168. '<td style="text-align: right;">6</td> ' +
  169. '</tr> ' +
  170. '</tbody> ' +
  171. '</table>';
  172. let actual = this.md(markdown);
  173. this.assertEqual(actual, expected);
  174. }
  175. test_table_holes() {
  176. let markdown = 'Column A||Column C\n' +
  177. '---|---|---\n' +
  178. '|1|2||\n' +
  179. '|4||6|\n' +
  180. '||8|9|';
  181. let expected = '<table> ' +
  182. '<thead> ' +
  183. '<tr> ' +
  184. '<th>Column A</th> ' +
  185. '<th></th> ' +
  186. '<th>Column C</th> ' +
  187. '</tr> ' +
  188. '</thead> ' +
  189. '<tbody> ' +
  190. '<tr> ' +
  191. '<td>1</td> ' +
  192. '<td>2</td> ' +
  193. '<td></td> ' +
  194. '</tr> ' +
  195. '<tr> ' +
  196. '<td>4</td> ' +
  197. '<td></td> ' +
  198. '<td>6</td> ' +
  199. '</tr> ' +
  200. '<tr> ' +
  201. '<td></td> ' +
  202. '<td>8</td> ' +
  203. '<td>9</td> ' +
  204. '</tr> ' +
  205. '</tbody> ' +
  206. '</table>';
  207. let actual = this.md(markdown);
  208. this.assertEqual(actual, expected);
  209. }
  210. test_definitionList() {
  211. let markdown = 'term\n' +
  212. ': definition\n' +
  213. 'another' +
  214. ' term\n' +
  215. ': def 1\n' +
  216. ' broken on next line\n' +
  217. ': def 2';
  218. let expected = '<dl> ' +
  219. '<dt>term</dt> ' +
  220. '<dd>definition</dd> ' +
  221. '<dt>another term</dt> ' +
  222. '<dd>def 1 broken on next line</dd> ' +
  223. '<dd>def 2</dd> ' +
  224. '</dl>';
  225. let actual = this.md(markdown);
  226. this.assertEqual(actual, expected);
  227. }
  228. test_footnotes() {
  229. let markdown = 'Lorem ipsum[^1] dolor[^abc] sit[^1] amet\n\n[^1]: A footnote\n[^abc]: Another footnote';
  230. let expected = '<p>Lorem ipsum<sup class="footnote" id="footnoteref_1"><a href="#footnote_1">1</a></sup> ' +
  231. 'dolor<sup class="footnote" id="footnoteref_2"><a href="#footnote_2">2</a></sup> ' +
  232. 'sit<sup class="footnote" id="footnoteref_3"><a href="#footnote_1">1</a></sup> amet</p> ' +
  233. '<div class="footnotes">' +
  234. '<ol>' +
  235. '<li value="1" id="footnote_1">A footnote <a href="#footnoteref_1" class="footnote-backref">↩︎</a> <a href="#footnoteref_3" class="footnote-backref">↩︎</a></li> ' +
  236. '<li value="2" id="footnote_2">Another footnote <a href="#footnoteref_2" class="footnote-backref">↩︎</a></li> ' +
  237. '</ol>' +
  238. '</div>';
  239. let actual = this.md(markdown);
  240. this.assertEqual(actual, expected);
  241. }
  242. test_abbreviations() {
  243. let markdown = 'Lorem ipsum HTML dolor HTML sit\n' +
  244. '\n' +
  245. '*[HTML]: Hypertext Markup Language';
  246. let expected = '<p>Lorem ipsum <abbr title="Hypertext Markup Language">HTML</abbr> dolor <abbr title="Hypertext Markup Language">HTML</abbr> sit</p>';
  247. let actual = this.md(markdown);
  248. this.assertEqual(actual, expected);
  249. }
  250. }