PHP and Javascript implementations of a simple markdown parser
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

BlockTests.php 10.0KB

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