diff options
Diffstat (limited to 'tests/test_syntax/blocks')
-rw-r--r-- | tests/test_syntax/blocks/__init__.py | 20 | ||||
-rw-r--r-- | tests/test_syntax/blocks/test_blockquotes.py | 51 | ||||
-rw-r--r-- | tests/test_syntax/blocks/test_code_blocks.py | 88 | ||||
-rw-r--r-- | tests/test_syntax/blocks/test_headers.py | 729 | ||||
-rw-r--r-- | tests/test_syntax/blocks/test_hr.py | 402 | ||||
-rw-r--r-- | tests/test_syntax/blocks/test_html_blocks.py | 1619 | ||||
-rw-r--r-- | tests/test_syntax/blocks/test_paragraphs.py | 229 |
7 files changed, 3138 insertions, 0 deletions
diff --git a/tests/test_syntax/blocks/__init__.py b/tests/test_syntax/blocks/__init__.py new file mode 100644 index 0000000..564ba3b --- /dev/null +++ b/tests/test_syntax/blocks/__init__.py @@ -0,0 +1,20 @@ +""" +Python Markdown + +A Python implementation of John Gruber's Markdown. + +Documentation: https://python-markdown.github.io/ +GitHub: https://github.com/Python-Markdown/markdown/ +PyPI: https://pypi.org/project/Markdown/ + +Started by Manfred Stienstra (http://www.dwerg.net/). +Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org). +Currently maintained by Waylan Limberg (https://github.com/waylan), +Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). + +Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later) +Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b) +Copyright 2004 Manfred Stienstra (the original version) + +License: BSD (see LICENSE.md for details). +""" diff --git a/tests/test_syntax/blocks/test_blockquotes.py b/tests/test_syntax/blocks/test_blockquotes.py new file mode 100644 index 0000000..3422f9f --- /dev/null +++ b/tests/test_syntax/blocks/test_blockquotes.py @@ -0,0 +1,51 @@ +""" +Python Markdown + +A Python implementation of John Gruber's Markdown. + +Documentation: https://python-markdown.github.io/ +GitHub: https://github.com/Python-Markdown/markdown/ +PyPI: https://pypi.org/project/Markdown/ + +Started by Manfred Stienstra (http://www.dwerg.net/). +Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org). +Currently maintained by Waylan Limberg (https://github.com/waylan), +Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). + +Copyright 2007-2020 The Python Markdown Project (v. 1.7 and later) +Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b) +Copyright 2004 Manfred Stienstra (the original version) + +License: BSD (see LICENSE.md for details). +""" + +from markdown.test_tools import TestCase, recursionlimit + + +class TestBlockquoteBlocks(TestCase): + + # TODO: Move legacy tests here + + def test_nesting_limit(self): + # Test that the nesting limit is within 100 levels of recursion limit. Future code changes could cause the + # recursion limit to need adjusted here. We need to account for all of Markdown's internal calls. Finally, we + # need to account for the 100 level cushion which we are testing. + with recursionlimit(120): + self.assertMarkdownRenders( + '>>>>>>>>>>', + self.dedent( + """ + <blockquote> + <blockquote> + <blockquote> + <blockquote> + <blockquote> + <p>>>>>></p> + </blockquote> + </blockquote> + </blockquote> + </blockquote> + </blockquote> + """ + ) + ) diff --git a/tests/test_syntax/blocks/test_code_blocks.py b/tests/test_syntax/blocks/test_code_blocks.py new file mode 100644 index 0000000..54b6860 --- /dev/null +++ b/tests/test_syntax/blocks/test_code_blocks.py @@ -0,0 +1,88 @@ +""" +Python Markdown + +A Python implementation of John Gruber's Markdown. + +Documentation: https://python-markdown.github.io/ +GitHub: https://github.com/Python-Markdown/markdown/ +PyPI: https://pypi.org/project/Markdown/ + +Started by Manfred Stienstra (http://www.dwerg.net/). +Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org). +Currently maintained by Waylan Limberg (https://github.com/waylan), +Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). + +Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later) +Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b) +Copyright 2004 Manfred Stienstra (the original version) + +License: BSD (see LICENSE.md for details). +""" + +from markdown.test_tools import TestCase + + +class TestCodeBlocks(TestCase): + + def test_spaced_codeblock(self): + self.assertMarkdownRenders( + ' # A code block.', + + self.dedent( + """ + <pre><code># A code block. + </code></pre> + """ + ) + ) + + def test_tabbed_codeblock(self): + self.assertMarkdownRenders( + '\t# A code block.', + + self.dedent( + """ + <pre><code># A code block. + </code></pre> + """ + ) + ) + + def test_multiline_codeblock(self): + self.assertMarkdownRenders( + ' # Line 1\n # Line 2\n', + + self.dedent( + """ + <pre><code># Line 1 + # Line 2 + </code></pre> + """ + ) + ) + + def test_codeblock_with_blankline(self): + self.assertMarkdownRenders( + ' # Line 1\n\n # Line 2\n', + + self.dedent( + """ + <pre><code># Line 1 + + # Line 2 + </code></pre> + """ + ) + ) + + def test_codeblock_escape(self): + self.assertMarkdownRenders( + ' <foo & bar>', + + self.dedent( + """ + <pre><code><foo & bar> + </code></pre> + """ + ) + ) diff --git a/tests/test_syntax/blocks/test_headers.py b/tests/test_syntax/blocks/test_headers.py new file mode 100644 index 0000000..ca065a5 --- /dev/null +++ b/tests/test_syntax/blocks/test_headers.py @@ -0,0 +1,729 @@ +""" +Python Markdown + +A Python implementation of John Gruber's Markdown. + +Documentation: https://python-markdown.github.io/ +GitHub: https://github.com/Python-Markdown/markdown/ +PyPI: https://pypi.org/project/Markdown/ + +Started by Manfred Stienstra (http://www.dwerg.net/). +Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org). +Currently maintained by Waylan Limberg (https://github.com/waylan), +Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). + +Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later) +Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b) +Copyright 2004 Manfred Stienstra (the original version) + +License: BSD (see LICENSE.md for details). +""" + +import unittest +from markdown.test_tools import TestCase + + +class TestSetextHeaders(TestCase): + + def test_setext_h1(self): + self.assertMarkdownRenders( + self.dedent( + """ + This is an H1 + ============= + """ + ), + + '<h1>This is an H1</h1>' + ) + + def test_setext_h2(self): + self.assertMarkdownRenders( + self.dedent( + """ + This is an H2 + ------------- + """ + ), + + '<h2>This is an H2</h2>' + ) + + def test_setext_h1_mismatched_length(self): + self.assertMarkdownRenders( + self.dedent( + """ + This is an H1 + === + """ + ), + + '<h1>This is an H1</h1>' + ) + + def test_setext_h2_mismatched_length(self): + self.assertMarkdownRenders( + self.dedent( + """ + This is an H2 + --- + """ + ), + + '<h2>This is an H2</h2>' + ) + + def test_setext_h1_followed_by_p(self): + self.assertMarkdownRenders( + self.dedent( + """ + This is an H1 + ============= + Followed by a Paragraph with no blank line. + """ + ), + self.dedent( + """ + <h1>This is an H1</h1> + <p>Followed by a Paragraph with no blank line.</p> + """ + ) + ) + + def test_setext_h2_followed_by_p(self): + self.assertMarkdownRenders( + self.dedent( + """ + This is an H2 + ------------- + Followed by a Paragraph with no blank line. + """ + ), + self.dedent( + """ + <h2>This is an H2</h2> + <p>Followed by a Paragraph with no blank line.</p> + """ + ) + ) + + # TODO: fix this + # see https://johnmacfarlane.net/babelmark2/?normalize=1&text=Paragraph%0AAn+H1%0A%3D%3D%3D%3D%3D + @unittest.skip('This is broken in Python-Markdown') + def test_p_followed_by_setext_h1(self): + self.assertMarkdownRenders( + self.dedent( + """ + This is a Paragraph. + Followed by an H1 with no blank line. + ===================================== + """ + ), + self.dedent( + """ + <p>This is a Paragraph.</p> + <h1>Followed by an H1 with no blank line.</h1> + """ + ) + ) + + # TODO: fix this + # see https://johnmacfarlane.net/babelmark2/?normalize=1&text=Paragraph%0AAn+H2%0A----- + @unittest.skip('This is broken in Python-Markdown') + def test_p_followed_by_setext_h2(self): + self.assertMarkdownRenders( + self.dedent( + """ + This is a Paragraph. + Followed by an H2 with no blank line. + ------------------------------------- + """ + ), + self.dedent( + """ + <p>This is a Paragraph.</p> + <h2>Followed by an H2 with no blank line.</h2> + """ + ) + ) + + +class TestHashHeaders(TestCase): + + def test_hash_h1_open(self): + self.assertMarkdownRenders( + '# This is an H1', + + '<h1>This is an H1</h1>' + ) + + def test_hash_h2_open(self): + self.assertMarkdownRenders( + '## This is an H2', + + '<h2>This is an H2</h2>' + ) + + def test_hash_h3_open(self): + self.assertMarkdownRenders( + '### This is an H3', + + '<h3>This is an H3</h3>' + ) + + def test_hash_h4_open(self): + self.assertMarkdownRenders( + '#### This is an H4', + + '<h4>This is an H4</h4>' + ) + + def test_hash_h5_open(self): + self.assertMarkdownRenders( + '##### This is an H5', + + '<h5>This is an H5</h5>' + ) + + def test_hash_h6_open(self): + self.assertMarkdownRenders( + '###### This is an H6', + + '<h6>This is an H6</h6>' + ) + + def test_hash_gt6_open(self): + self.assertMarkdownRenders( + '####### This is an H6', + + '<h6># This is an H6</h6>' + ) + + def test_hash_h1_open_missing_space(self): + self.assertMarkdownRenders( + '#This is an H1', + + '<h1>This is an H1</h1>' + ) + + def test_hash_h2_open_missing_space(self): + self.assertMarkdownRenders( + '##This is an H2', + + '<h2>This is an H2</h2>' + ) + + def test_hash_h3_open_missing_space(self): + self.assertMarkdownRenders( + '###This is an H3', + + '<h3>This is an H3</h3>' + ) + + def test_hash_h4_open_missing_space(self): + self.assertMarkdownRenders( + '####This is an H4', + + '<h4>This is an H4</h4>' + ) + + def test_hash_h5_open_missing_space(self): + self.assertMarkdownRenders( + '#####This is an H5', + + '<h5>This is an H5</h5>' + ) + + def test_hash_h6_open_missing_space(self): + self.assertMarkdownRenders( + '######This is an H6', + + '<h6>This is an H6</h6>' + ) + + def test_hash_gt6_open_missing_space(self): + self.assertMarkdownRenders( + '#######This is an H6', + + '<h6>#This is an H6</h6>' + ) + + def test_hash_h1_closed(self): + self.assertMarkdownRenders( + '# This is an H1 #', + + '<h1>This is an H1</h1>' + ) + + def test_hash_h2_closed(self): + self.assertMarkdownRenders( + '## This is an H2 ##', + + '<h2>This is an H2</h2>' + ) + + def test_hash_h3_closed(self): + self.assertMarkdownRenders( + '### This is an H3 ###', + + '<h3>This is an H3</h3>' + ) + + def test_hash_h4_closed(self): + self.assertMarkdownRenders( + '#### This is an H4 ####', + + '<h4>This is an H4</h4>' + ) + + def test_hash_h5_closed(self): + self.assertMarkdownRenders( + '##### This is an H5 #####', + + '<h5>This is an H5</h5>' + ) + + def test_hash_h6_closed(self): + self.assertMarkdownRenders( + '###### This is an H6 ######', + + '<h6>This is an H6</h6>' + ) + + def test_hash_gt6_closed(self): + self.assertMarkdownRenders( + '####### This is an H6 #######', + + '<h6># This is an H6</h6>' + ) + + def test_hash_h1_closed_missing_space(self): + self.assertMarkdownRenders( + '#This is an H1#', + + '<h1>This is an H1</h1>' + ) + + def test_hash_h2_closed_missing_space(self): + self.assertMarkdownRenders( + '##This is an H2##', + + '<h2>This is an H2</h2>' + ) + + def test_hash_h3_closed_missing_space(self): + self.assertMarkdownRenders( + '###This is an H3###', + + '<h3>This is an H3</h3>' + ) + + def test_hash_h4_closed_missing_space(self): + self.assertMarkdownRenders( + '####This is an H4####', + + '<h4>This is an H4</h4>' + ) + + def test_hash_h5_closed_missing_space(self): + self.assertMarkdownRenders( + '#####This is an H5#####', + + '<h5>This is an H5</h5>' + ) + + def test_hash_h6_closed_missing_space(self): + self.assertMarkdownRenders( + '######This is an H6######', + + '<h6>This is an H6</h6>' + ) + + def test_hash_gt6_closed_missing_space(self): + self.assertMarkdownRenders( + '#######This is an H6#######', + + '<h6>#This is an H6</h6>' + ) + + def test_hash_h1_closed_mismatch(self): + self.assertMarkdownRenders( + '# This is an H1 ##', + + '<h1>This is an H1</h1>' + ) + + def test_hash_h2_closed_mismatch(self): + self.assertMarkdownRenders( + '## This is an H2 #', + + '<h2>This is an H2</h2>' + ) + + def test_hash_h3_closed_mismatch(self): + self.assertMarkdownRenders( + '### This is an H3 #', + + '<h3>This is an H3</h3>' + ) + + def test_hash_h4_closed_mismatch(self): + self.assertMarkdownRenders( + '#### This is an H4 #', + + '<h4>This is an H4</h4>' + ) + + def test_hash_h5_closed_mismatch(self): + self.assertMarkdownRenders( + '##### This is an H5 #', + + '<h5>This is an H5</h5>' + ) + + def test_hash_h6_closed_mismatch(self): + self.assertMarkdownRenders( + '###### This is an H6 #', + + '<h6>This is an H6</h6>' + ) + + def test_hash_gt6_closed_mismatch(self): + self.assertMarkdownRenders( + '####### This is an H6 ##################', + + '<h6># This is an H6</h6>' + ) + + def test_hash_h1_followed_by_p(self): + self.assertMarkdownRenders( + self.dedent( + """ + # This is an H1 + Followed by a Paragraph with no blank line. + """ + ), + self.dedent( + """ + <h1>This is an H1</h1> + <p>Followed by a Paragraph with no blank line.</p> + """ + ) + ) + + def test_hash_h2_followed_by_p(self): + self.assertMarkdownRenders( + self.dedent( + """ + ## This is an H2 + Followed by a Paragraph with no blank line. + """ + ), + self.dedent( + """ + <h2>This is an H2</h2> + <p>Followed by a Paragraph with no blank line.</p> + """ + ) + ) + + def test_hash_h3_followed_by_p(self): + self.assertMarkdownRenders( + self.dedent( + """ + ### This is an H3 + Followed by a Paragraph with no blank line. + """ + ), + self.dedent( + """ + <h3>This is an H3</h3> + <p>Followed by a Paragraph with no blank line.</p> + """ + ) + ) + + def test_hash_h4_followed_by_p(self): + self.assertMarkdownRenders( + self.dedent( + """ + #### This is an H4 + Followed by a Paragraph with no blank line. + """ + ), + self.dedent( + """ + <h4>This is an H4</h4> + <p>Followed by a Paragraph with no blank line.</p> + """ + ) + ) + + def test_hash_h5_followed_by_p(self): + self.assertMarkdownRenders( + self.dedent( + """ + ##### This is an H5 + Followed by a Paragraph with no blank line. + """ + ), + self.dedent( + """ + <h5>This is an H5</h5> + <p>Followed by a Paragraph with no blank line.</p> + """ + ) + ) + + def test_hash_h6_followed_by_p(self): + self.assertMarkdownRenders( + self.dedent( + """ + ###### This is an H6 + Followed by a Paragraph with no blank line. + """ + ), + self.dedent( + """ + <h6>This is an H6</h6> + <p>Followed by a Paragraph with no blank line.</p> + """ + ) + ) + + def test_hash_h1_leading_space(self): + self.assertMarkdownRenders( + ' # This is an H1', + + '<p># This is an H1</p>' + ) + + def test_hash_h2_leading_space(self): + self.assertMarkdownRenders( + ' ## This is an H2', + + '<p>## This is an H2</p>' + ) + + def test_hash_h3_leading_space(self): + self.assertMarkdownRenders( + ' ### This is an H3', + + '<p>### This is an H3</p>' + ) + + def test_hash_h4_leading_space(self): + self.assertMarkdownRenders( + ' #### This is an H4', + + '<p>#### This is an H4</p>' + ) + + def test_hash_h5_leading_space(self): + self.assertMarkdownRenders( + ' ##### This is an H5', + + '<p>##### This is an H5</p>' + ) + + def test_hash_h6_leading_space(self): + self.assertMarkdownRenders( + ' ###### This is an H6', + + '<p>###### This is an H6</p>' + ) + + def test_hash_h1_open_trailing_space(self): + self.assertMarkdownRenders( + '# This is an H1 ', + + '<h1>This is an H1</h1>' + ) + + def test_hash_h2_open_trailing_space(self): + self.assertMarkdownRenders( + '## This is an H2 ', + + '<h2>This is an H2</h2>' + ) + + def test_hash_h3_open_trailing_space(self): + self.assertMarkdownRenders( + '### This is an H3 ', + + '<h3>This is an H3</h3>' + ) + + def test_hash_h4_open_trailing_space(self): + self.assertMarkdownRenders( + '#### This is an H4 ', + + '<h4>This is an H4</h4>' + ) + + def test_hash_h5_open_trailing_space(self): + self.assertMarkdownRenders( + '##### This is an H5 ', + + '<h5>This is an H5</h5>' + ) + + def test_hash_h6_open_trailing_space(self): + self.assertMarkdownRenders( + '###### This is an H6 ', + + '<h6>This is an H6</h6>' + ) + + def test_hash_gt6_open_trailing_space(self): + self.assertMarkdownRenders( + '####### This is an H6 ', + + '<h6># This is an H6</h6>' + ) + + # TODO: Possibly change the following behavior. While this follows the behavior + # of markdown.pl, it is rather uncommon and not necessarily intuitive. + # See: https://johnmacfarlane.net/babelmark2/?normalize=1&text=%23+This+is+an+H1+%23+ + def test_hash_h1_closed_trailing_space(self): + self.assertMarkdownRenders( + '# This is an H1 # ', + + '<h1>This is an H1 #</h1>' + ) + + def test_hash_h2_closed_trailing_space(self): + self.assertMarkdownRenders( + '## This is an H2 ## ', + + '<h2>This is an H2 ##</h2>' + ) + + def test_hash_h3_closed_trailing_space(self): + self.assertMarkdownRenders( + '### This is an H3 ### ', + + '<h3>This is an H3 ###</h3>' + ) + + def test_hash_h4_closed_trailing_space(self): + self.assertMarkdownRenders( + '#### This is an H4 #### ', + + '<h4>This is an H4 ####</h4>' + ) + + def test_hash_h5_closed_trailing_space(self): + self.assertMarkdownRenders( + '##### This is an H5 ##### ', + + '<h5>This is an H5 #####</h5>' + ) + + def test_hash_h6_closed_trailing_space(self): + self.assertMarkdownRenders( + '###### This is an H6 ###### ', + + '<h6>This is an H6 ######</h6>' + ) + + def test_hash_gt6_closed_trailing_space(self): + self.assertMarkdownRenders( + '####### This is an H6 ####### ', + + '<h6># This is an H6 #######</h6>' + ) + + def test_no_blank_lines_between_hashs(self): + self.assertMarkdownRenders( + self.dedent( + """ + # This is an H1 + ## This is an H2 + """ + ), + self.dedent( + """ + <h1>This is an H1</h1> + <h2>This is an H2</h2> + """ + ) + ) + + def test_random_hash_levels(self): + self.assertMarkdownRenders( + self.dedent( + """ + ### H3 + ###### H6 + # H1 + ##### H5 + #### H4 + ## H2 + ### H3 + """ + ), + self.dedent( + """ + <h3>H3</h3> + <h6>H6</h6> + <h1>H1</h1> + <h5>H5</h5> + <h4>H4</h4> + <h2>H2</h2> + <h3>H3</h3> + """ + ) + ) + + def test_hash_followed_by_p(self): + self.assertMarkdownRenders( + self.dedent( + """ + # This is an H1 + Followed by a Paragraph with no blank line. + """ + ), + self.dedent( + """ + <h1>This is an H1</h1> + <p>Followed by a Paragraph with no blank line.</p> + """ + ) + ) + + def test_p_followed_by_hash(self): + self.assertMarkdownRenders( + self.dedent( + """ + This is a Paragraph. + # Followed by an H1 with no blank line. + """ + ), + self.dedent( + """ + <p>This is a Paragraph.</p> + <h1>Followed by an H1 with no blank line.</h1> + """ + ) + ) + + def test_escaped_hash(self): + self.assertMarkdownRenders( + "### H3 \\###", + self.dedent( + """ + <h3>H3 #</h3> + """ + ) + ) + + def test_unescaped_hash(self): + self.assertMarkdownRenders( + "### H3 \\\\###", + self.dedent( + """ + <h3>H3 \\</h3> + """ + ) + ) diff --git a/tests/test_syntax/blocks/test_hr.py b/tests/test_syntax/blocks/test_hr.py new file mode 100644 index 0000000..85a51b3 --- /dev/null +++ b/tests/test_syntax/blocks/test_hr.py @@ -0,0 +1,402 @@ +""" +Python Markdown + +A Python implementation of John Gruber's Markdown. + +Documentation: https://python-markdown.github.io/ +GitHub: https://github.com/Python-Markdown/markdown/ +PyPI: https://pypi.org/project/Markdown/ + +Started by Manfred Stienstra (http://www.dwerg.net/). +Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org). +Currently maintained by Waylan Limberg (https://github.com/waylan), +Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). + +Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later) +Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b) +Copyright 2004 Manfred Stienstra (the original version) + +License: BSD (see LICENSE.md for details). +""" + +from markdown.test_tools import TestCase + + +class TestHorizontalRules(TestCase): + + def test_hr_asterisks(self): + self.assertMarkdownRenders( + '***', + + '<hr />' + ) + + def test_hr_asterisks_spaces(self): + self.assertMarkdownRenders( + '* * *', + + '<hr />' + ) + + def test_hr_asterisks_long(self): + self.assertMarkdownRenders( + '*******', + + '<hr />' + ) + + def test_hr_asterisks_spaces_long(self): + self.assertMarkdownRenders( + '* * * * * * *', + + '<hr />' + ) + + def test_hr_asterisks_1_indent(self): + self.assertMarkdownRenders( + ' ***', + + '<hr />' + ) + + def test_hr_asterisks_spaces_1_indent(self): + self.assertMarkdownRenders( + ' * * *', + + '<hr />' + ) + + def test_hr_asterisks_2_indent(self): + self.assertMarkdownRenders( + ' ***', + + '<hr />' + ) + + def test_hr_asterisks_spaces_2_indent(self): + self.assertMarkdownRenders( + ' * * *', + + '<hr />' + ) + + def test_hr_asterisks_3_indent(self): + self.assertMarkdownRenders( + ' ***', + + '<hr />' + ) + + def test_hr_asterisks_spaces_3_indent(self): + self.assertMarkdownRenders( + ' * * *', + + '<hr />' + ) + + def test_hr_asterisks_trailing_space(self): + self.assertMarkdownRenders( + '*** ', + + '<hr />' + ) + + def test_hr_asterisks_spaces_trailing_space(self): + self.assertMarkdownRenders( + '* * * ', + + '<hr />' + ) + + def test_hr_hyphens(self): + self.assertMarkdownRenders( + '---', + + '<hr />' + ) + + def test_hr_hyphens_spaces(self): + self.assertMarkdownRenders( + '- - -', + + '<hr />' + ) + + def test_hr_hyphens_long(self): + self.assertMarkdownRenders( + '-------', + + '<hr />' + ) + + def test_hr_hyphens_spaces_long(self): + self.assertMarkdownRenders( + '- - - - - - -', + + '<hr />' + ) + + def test_hr_hyphens_1_indent(self): + self.assertMarkdownRenders( + ' ---', + + '<hr />' + ) + + def test_hr_hyphens_spaces_1_indent(self): + self.assertMarkdownRenders( + ' - - -', + + '<hr />' + ) + + def test_hr_hyphens_2_indent(self): + self.assertMarkdownRenders( + ' ---', + + '<hr />' + ) + + def test_hr_hyphens_spaces_2_indent(self): + self.assertMarkdownRenders( + ' - - -', + + '<hr />' + ) + + def test_hr_hyphens_3_indent(self): + self.assertMarkdownRenders( + ' ---', + + '<hr />' + ) + + def test_hr_hyphens_spaces_3_indent(self): + self.assertMarkdownRenders( + ' - - -', + + '<hr />' + ) + + def test_hr_hyphens_trailing_space(self): + self.assertMarkdownRenders( + '--- ', + + '<hr />' + ) + + def test_hr_hyphens_spaces_trailing_space(self): + self.assertMarkdownRenders( + '- - - ', + + '<hr />' + ) + + def test_hr_underscores(self): + self.assertMarkdownRenders( + '___', + + '<hr />' + ) + + def test_hr_underscores_spaces(self): + self.assertMarkdownRenders( + '_ _ _', + + '<hr />' + ) + + def test_hr_underscores_long(self): + self.assertMarkdownRenders( + '_______', + + '<hr />' + ) + + def test_hr_underscores_spaces_long(self): + self.assertMarkdownRenders( + '_ _ _ _ _ _ _', + + '<hr />' + ) + + def test_hr_underscores_1_indent(self): + self.assertMarkdownRenders( + ' ___', + + '<hr />' + ) + + def test_hr_underscores_spaces_1_indent(self): + self.assertMarkdownRenders( + ' _ _ _', + + '<hr />' + ) + + def test_hr_underscores_2_indent(self): + self.assertMarkdownRenders( + ' ___', + + '<hr />' + ) + + def test_hr_underscores_spaces_2_indent(self): + self.assertMarkdownRenders( + ' _ _ _', + + '<hr />' + ) + + def test_hr_underscores_3_indent(self): + self.assertMarkdownRenders( + ' ___', + + '<hr />' + ) + + def test_hr_underscores_spaces_3_indent(self): + self.assertMarkdownRenders( + ' _ _ _', + + '<hr />' + ) + + def test_hr_underscores_trailing_space(self): + self.assertMarkdownRenders( + '___ ', + + '<hr />' + ) + + def test_hr_underscores_spaces_trailing_space(self): + self.assertMarkdownRenders( + '_ _ _ ', + + '<hr />' + ) + + def test_hr_before_paragraph(self): + self.assertMarkdownRenders( + self.dedent( + """ + *** + An HR followed by a paragraph with no blank line. + """ + ), + self.dedent( + """ + <hr /> + <p>An HR followed by a paragraph with no blank line.</p> + """ + ) + ) + + def test_hr_after_paragraph(self): + self.assertMarkdownRenders( + self.dedent( + """ + A paragraph followed by an HR with no blank line. + *** + """ + ), + self.dedent( + """ + <p>A paragraph followed by an HR with no blank line.</p> + <hr /> + """ + ) + ) + + def test_hr_after_emstrong(self): + self.assertMarkdownRenders( + self.dedent( + """ + ***text*** + *** + """ + ), + self.dedent( + """ + <p><strong><em>text</em></strong></p> + <hr /> + """ + ) + ) + + def test_not_hr_2_asterisks(self): + self.assertMarkdownRenders( + '**', + + '<p>**</p>' + ) + + def test_not_hr_2_asterisks_spaces(self): + self.assertMarkdownRenders( + '* *', + + self.dedent( + """ + <ul> + <li>*</li> + </ul> + """ + ) + ) + + def test_not_hr_2_hyphens(self): + self.assertMarkdownRenders( + '--', + + '<p>--</p>' + ) + + def test_not_hr_2_hyphens_spaces(self): + self.assertMarkdownRenders( + '- -', + + self.dedent( + """ + <ul> + <li>-</li> + </ul> + """ + ) + ) + + def test_not_hr_2_underscores(self): + self.assertMarkdownRenders( + '__', + + '<p>__</p>' + ) + + def test_not_hr_2_underscores_spaces(self): + self.assertMarkdownRenders( + '_ _', + + '<p>_ _</p>' + ) + + def test_2_consecutive_hr(self): + self.assertMarkdownRenders( + self.dedent( + """ + - - - + - - - + """ + ), + self.dedent( + """ + <hr /> + <hr /> + """ + ) + ) + + def test_not_hr_end_in_char(self): + self.assertMarkdownRenders( + '--------------------------------------c', + + '<p>--------------------------------------c</p>' + ) diff --git a/tests/test_syntax/blocks/test_html_blocks.py b/tests/test_syntax/blocks/test_html_blocks.py new file mode 100644 index 0000000..9ec0668 --- /dev/null +++ b/tests/test_syntax/blocks/test_html_blocks.py @@ -0,0 +1,1619 @@ +# -*- coding: utf-8 -*- +""" +Python Markdown + +A Python implementation of John Gruber's Markdown. + +Documentation: https://python-markdown.github.io/ +GitHub: https://github.com/Python-Markdown/markdown/ +PyPI: https://pypi.org/project/Markdown/ + +Started by Manfred Stienstra (http://www.dwerg.net/). +Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org). +Currently maintained by Waylan Limberg (https://github.com/waylan), +Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). + +Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later) +Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b) +Copyright 2004 Manfred Stienstra (the original version) + +License: BSD (see LICENSE.md for details). +""" + +from markdown.test_tools import TestCase +import markdown + + +class TestHTMLBlocks(TestCase): + + def test_raw_paragraph(self): + self.assertMarkdownRenders( + '<p>A raw paragraph.</p>', + '<p>A raw paragraph.</p>' + ) + + def test_raw_skip_inline_markdown(self): + self.assertMarkdownRenders( + '<p>A *raw* paragraph.</p>', + '<p>A *raw* paragraph.</p>' + ) + + def test_raw_indent_one_space(self): + self.assertMarkdownRenders( + ' <p>A *raw* paragraph.</p>', + '<p>A *raw* paragraph.</p>' + ) + + def test_raw_indent_two_spaces(self): + self.assertMarkdownRenders( + ' <p>A *raw* paragraph.</p>', + '<p>A *raw* paragraph.</p>' + ) + + def test_raw_indent_three_spaces(self): + self.assertMarkdownRenders( + ' <p>A *raw* paragraph.</p>', + '<p>A *raw* paragraph.</p>' + ) + + def test_raw_indent_four_spaces(self): + self.assertMarkdownRenders( + ' <p>code block</p>', + self.dedent( + """ + <pre><code><p>code block</p> + </code></pre> + """ + ) + ) + + def test_raw_span(self): + self.assertMarkdownRenders( + '<span>*inline*</span>', + '<p><span><em>inline</em></span></p>' + ) + + def test_code_span(self): + self.assertMarkdownRenders( + '`<p>code span</p>`', + '<p><code><p>code span</p></code></p>' + ) + + def test_code_span_open_gt(self): + self.assertMarkdownRenders( + '*bar* `<` *foo*', + '<p><em>bar</em> <code><</code> <em>foo</em></p>' + ) + + def test_raw_empty(self): + self.assertMarkdownRenders( + '<p></p>', + '<p></p>' + ) + + def test_raw_empty_space(self): + self.assertMarkdownRenders( + '<p> </p>', + '<p> </p>' + ) + + def test_raw_empty_newline(self): + self.assertMarkdownRenders( + '<p>\n</p>', + '<p>\n</p>' + ) + + def test_raw_empty_blank_line(self): + self.assertMarkdownRenders( + '<p>\n\n</p>', + '<p>\n\n</p>' + ) + + def test_raw_uppercase(self): + self.assertMarkdownRenders( + '<DIV>*foo*</DIV>', + '<DIV>*foo*</DIV>' + ) + + def test_raw_uppercase_multiline(self): + self.assertMarkdownRenders( + self.dedent( + """ + <DIV> + *foo* + </DIV> + """ + ), + self.dedent( + """ + <DIV> + *foo* + </DIV> + """ + ) + ) + + def test_multiple_raw_single_line(self): + self.assertMarkdownRenders( + '<p>*foo*</p><div>*bar*</div>', + self.dedent( + """ + <p>*foo*</p> + <div>*bar*</div> + """ + ) + ) + + def test_multiple_raw_single_line_with_pi(self): + self.assertMarkdownRenders( + "<p>*foo*</p><?php echo '>'; ?>", + self.dedent( + """ + <p>*foo*</p> + <?php echo '>'; ?> + """ + ) + ) + + def test_multiline_raw(self): + self.assertMarkdownRenders( + self.dedent( + """ + <p> + A raw paragraph + with multiple lines. + </p> + """ + ), + self.dedent( + """ + <p> + A raw paragraph + with multiple lines. + </p> + """ + ) + ) + + def test_blank_lines_in_raw(self): + self.assertMarkdownRenders( + self.dedent( + """ + <p> + + A raw paragraph... + + with many blank lines. + + </p> + """ + ), + self.dedent( + """ + <p> + + A raw paragraph... + + with many blank lines. + + </p> + """ + ) + ) + + def test_raw_surrounded_by_Markdown(self): + self.assertMarkdownRenders( + self.dedent( + """ + Some *Markdown* text. + + <p>*Raw* HTML.</p> + + More *Markdown* text. + """ + ), + self.dedent( + """ + <p>Some <em>Markdown</em> text.</p> + <p>*Raw* HTML.</p> + + <p>More <em>Markdown</em> text.</p> + """ + ) + ) + + def test_raw_surrounded_by_text_without_blank_lines(self): + self.assertMarkdownRenders( + self.dedent( + """ + Some *Markdown* text. + <p>*Raw* HTML.</p> + More *Markdown* text. + """ + ), + self.dedent( + """ + <p>Some <em>Markdown</em> text.</p> + <p>*Raw* HTML.</p> + <p>More <em>Markdown</em> text.</p> + """ + ) + ) + + def test_multiline_markdown_with_code_span(self): + self.assertMarkdownRenders( + self.dedent( + """ + A paragraph with a block-level + `<p>code span</p>`, which is + at the start of a line. + """ + ), + self.dedent( + """ + <p>A paragraph with a block-level + <code><p>code span</p></code>, which is + at the start of a line.</p> + """ + ) + ) + + def test_raw_block_preceded_by_markdown_code_span_with_unclosed_block_tag(self): + self.assertMarkdownRenders( + self.dedent( + """ + A paragraph with a block-level code span: `<div>`. + + <p>*not markdown*</p> + + This is *markdown* + """ + ), + self.dedent( + """ + <p>A paragraph with a block-level code span: <code><div></code>.</p> + <p>*not markdown*</p> + + <p>This is <em>markdown</em></p> + """ + ) + ) + + def test_raw_one_line_followed_by_text(self): + self.assertMarkdownRenders( + '<p>*foo*</p>*bar*', + self.dedent( + """ + <p>*foo*</p> + <p><em>bar</em></p> + """ + ) + ) + + def test_raw_one_line_followed_by_span(self): + self.assertMarkdownRenders( + "<p>*foo*</p><span>*bar*</span>", + self.dedent( + """ + <p>*foo*</p> + <p><span><em>bar</em></span></p> + """ + ) + ) + + def test_raw_with_markdown_blocks(self): + self.assertMarkdownRenders( + self.dedent( + """ + <div> + Not a Markdown paragraph. + + * Not a list item. + * Another non-list item. + + Another non-Markdown paragraph. + </div> + """ + ), + self.dedent( + """ + <div> + Not a Markdown paragraph. + + * Not a list item. + * Another non-list item. + + Another non-Markdown paragraph. + </div> + """ + ) + ) + + def test_adjacent_raw_blocks(self): + self.assertMarkdownRenders( + self.dedent( + """ + <p>A raw paragraph.</p> + <p>A second raw paragraph.</p> + """ + ), + self.dedent( + """ + <p>A raw paragraph.</p> + <p>A second raw paragraph.</p> + """ + ) + ) + + def test_adjacent_raw_blocks_with_blank_lines(self): + self.assertMarkdownRenders( + self.dedent( + """ + <p>A raw paragraph.</p> + + <p>A second raw paragraph.</p> + """ + ), + self.dedent( + """ + <p>A raw paragraph.</p> + + <p>A second raw paragraph.</p> + """ + ) + ) + + def test_nested_raw_one_line(self): + self.assertMarkdownRenders( + '<div><p>*foo*</p></div>', + '<div><p>*foo*</p></div>' + ) + + def test_nested_raw_block(self): + self.assertMarkdownRenders( + self.dedent( + """ + <div> + <p>A raw paragraph.</p> + </div> + """ + ), + self.dedent( + """ + <div> + <p>A raw paragraph.</p> + </div> + """ + ) + ) + + def test_nested_indented_raw_block(self): + self.assertMarkdownRenders( + self.dedent( + """ + <div> + <p>A raw paragraph.</p> + </div> + """ + ), + self.dedent( + """ + <div> + <p>A raw paragraph.</p> + </div> + """ + ) + ) + + def test_nested_raw_blocks(self): + self.assertMarkdownRenders( + self.dedent( + """ + <div> + <p>A raw paragraph.</p> + <p>A second raw paragraph.</p> + </div> + """ + ), + self.dedent( + """ + <div> + <p>A raw paragraph.</p> + <p>A second raw paragraph.</p> + </div> + """ + ) + ) + + def test_nested_raw_blocks_with_blank_lines(self): + self.assertMarkdownRenders( + self.dedent( + """ + <div> + + <p>A raw paragraph.</p> + + <p>A second raw paragraph.</p> + + </div> + """ + ), + self.dedent( + """ + <div> + + <p>A raw paragraph.</p> + + <p>A second raw paragraph.</p> + + </div> + """ + ) + ) + + def test_nested_inline_one_line(self): + self.assertMarkdownRenders( + '<p><em>foo</em><br></p>', + '<p><em>foo</em><br></p>' + ) + + def test_raw_nested_inline(self): + self.assertMarkdownRenders( + self.dedent( + """ + <div> + <p> + <span>*text*</span> + </p> + </div> + """ + ), + self.dedent( + """ + <div> + <p> + <span>*text*</span> + </p> + </div> + """ + ) + ) + + def test_raw_nested_inline_with_blank_lines(self): + self.assertMarkdownRenders( + self.dedent( + """ + <div> + + <p> + + <span>*text*</span> + + </p> + + </div> + """ + ), + self.dedent( + """ + <div> + + <p> + + <span>*text*</span> + + </p> + + </div> + """ + ) + ) + + def test_raw_html5(self): + self.assertMarkdownRenders( + self.dedent( + """ + <section> + <header> + <hgroup> + <h1>Hello :-)</h1> + </hgroup> + </header> + <figure> + <img src="image.png" alt="" /> + <figcaption>Caption</figcaption> + </figure> + <footer> + <p>Some footer</p> + </footer> + </section> + """ + ), + self.dedent( + """ + <section> + <header> + <hgroup> + <h1>Hello :-)</h1> + </hgroup> + </header> + <figure> + <img src="image.png" alt="" /> + <figcaption>Caption</figcaption> + </figure> + <footer> + <p>Some footer</p> + </footer> + </section> + """ + ) + ) + + def test_raw_pre_tag(self): + self.assertMarkdownRenders( + self.dedent( + """ + Preserve whitespace in raw html + + <pre> + class Foo(): + bar = 'bar' + + @property + def baz(self): + return self.bar + </pre> + """ + ), + self.dedent( + """ + <p>Preserve whitespace in raw html</p> + <pre> + class Foo(): + bar = 'bar' + + @property + def baz(self): + return self.bar + </pre> + """ + ) + ) + + def test_raw_pre_tag_nested_escaped_html(self): + self.assertMarkdownRenders( + self.dedent( + """ + <pre> + <p>foo</p> + </pre> + """ + ), + self.dedent( + """ + <pre> + <p>foo</p> + </pre> + """ + ) + ) + + def test_raw_p_no_end_tag(self): + self.assertMarkdownRenders( + '<p>*text*', + '<p>*text*' + ) + + def test_raw_multiple_p_no_end_tag(self): + self.assertMarkdownRenders( + self.dedent( + """ + <p>*text*' + + <p>more *text* + """ + ), + self.dedent( + """ + <p>*text*' + + <p>more *text* + """ + ) + ) + + def test_raw_p_no_end_tag_followed_by_blank_line(self): + self.assertMarkdownRenders( + self.dedent( + """ + <p>*raw text*' + + Still part of *raw* text. + """ + ), + self.dedent( + """ + <p>*raw text*' + + Still part of *raw* text. + """ + ) + ) + + def test_raw_nested_p_no_end_tag(self): + self.assertMarkdownRenders( + '<div><p>*text*</div>', + '<div><p>*text*</div>' + ) + + def test_raw_open_bracket_only(self): + self.assertMarkdownRenders( + '<', + '<p><</p>' + ) + + def test_raw_open_bracket_followed_by_space(self): + self.assertMarkdownRenders( + '< foo', + '<p>< foo</p>' + ) + + def test_raw_missing_close_bracket(self): + self.assertMarkdownRenders( + '<foo', + '<p><foo</p>' + ) + + def test_raw_unclosed_tag_in_code_span(self): + self.assertMarkdownRenders( + self.dedent( + """ + `<div`. + + <div> + hello + </div> + """ + ), + self.dedent( + """ + <p><code><div</code>.</p> + <div> + hello + </div> + """ + ) + ) + + def test_raw_unclosed_tag_in_code_span_space(self): + self.assertMarkdownRenders( + self.dedent( + """ + ` <div `. + + <div> + hello + </div> + """ + ), + self.dedent( + """ + <p><code><div</code>.</p> + <div> + hello + </div> + """ + ) + ) + + def test_raw_attributes(self): + self.assertMarkdownRenders( + '<p id="foo", class="bar baz", style="margin: 15px; line-height: 1.5; text-align: center;">text</p>', + '<p id="foo", class="bar baz", style="margin: 15px; line-height: 1.5; text-align: center;">text</p>' + ) + + def test_raw_attributes_nested(self): + self.assertMarkdownRenders( + self.dedent( + """ + <div id="foo, class="bar", style="background: #ffe7e8; border: 2px solid #e66465;"> + <p id="baz", style="margin: 15px; line-height: 1.5; text-align: center;"> + <img scr="../foo.jpg" title="with 'quoted' text." valueless_attr weirdness="<i>foo</i>" /> + </p> + </div> + """ + ), + self.dedent( + """ + <div id="foo, class="bar", style="background: #ffe7e8; border: 2px solid #e66465;"> + <p id="baz", style="margin: 15px; line-height: 1.5; text-align: center;"> + <img scr="../foo.jpg" title="with 'quoted' text." valueless_attr weirdness="<i>foo</i>" /> + </p> + </div> + """ + ) + ) + + def test_raw_comment_one_line(self): + self.assertMarkdownRenders( + '<!-- *foo* -->', + '<!-- *foo* -->' + ) + + def test_raw_comment_one_line_with_tag(self): + self.assertMarkdownRenders( + '<!-- <tag> -->', + '<!-- <tag> -->' + ) + + def test_comment_in_code_span(self): + self.assertMarkdownRenders( + '`<!-- *foo* -->`', + '<p><code><!-- *foo* --></code></p>' + ) + + def test_raw_comment_one_line_followed_by_text(self): + self.assertMarkdownRenders( + '<!-- *foo* -->*bar*', + self.dedent( + """ + <!-- *foo* --> + <p><em>bar</em></p> + """ + ) + ) + + def test_raw_comment_one_line_followed_by_html(self): + self.assertMarkdownRenders( + '<!-- *foo* --><p>*bar*</p>', + self.dedent( + """ + <!-- *foo* --> + <p>*bar*</p> + """ + ) + ) + + # Note: Trailing (insignificant) whitespace is not preserved, which does not match the + # reference implementation. However, it is not a change in behavior for Python-Markdown. + def test_raw_comment_trailing_whitespace(self): + self.assertMarkdownRenders( + '<!-- *foo* --> ', + '<!-- *foo* -->' + ) + + # Note: this is a change in behavior for Python-Markdown, which does *not* match the reference + # implementation. However, it does match the HTML5 spec. Declarations must start with either + # `<!DOCTYPE` or `<![`. Anything else that starts with `<!` is a comment. According to the + # HTML5 spec, a comment without the hyphens is a "bogus comment", but a comment nonetheless. + # See https://www.w3.org/TR/html52/syntax.html#markup-declaration-open-state. + # If we wanted to change this behavior, we could override `HTMLParser.parse_bogus_comment()`. + def test_bogus_comment(self): + self.assertMarkdownRenders( + '<!*foo*>', + '<!--*foo*-->' + ) + + def test_raw_multiline_comment(self): + self.assertMarkdownRenders( + self.dedent( + """ + <!-- + *foo* + --> + """ + ), + self.dedent( + """ + <!-- + *foo* + --> + """ + ) + ) + + def test_raw_multiline_comment_with_tag(self): + self.assertMarkdownRenders( + self.dedent( + """ + <!-- + <tag> + --> + """ + ), + self.dedent( + """ + <!-- + <tag> + --> + """ + ) + ) + + def test_raw_multiline_comment_first_line(self): + self.assertMarkdownRenders( + self.dedent( + """ + <!-- *foo* + --> + """ + ), + self.dedent( + """ + <!-- *foo* + --> + """ + ) + ) + + def test_raw_multiline_comment_last_line(self): + self.assertMarkdownRenders( + self.dedent( + """ + <!-- + *foo* --> + """ + ), + self.dedent( + """ + <!-- + *foo* --> + """ + ) + ) + + def test_raw_comment_with_blank_lines(self): + self.assertMarkdownRenders( + self.dedent( + """ + <!-- + + *foo* + + --> + """ + ), + self.dedent( + """ + <!-- + + *foo* + + --> + """ + ) + ) + + def test_raw_comment_with_blank_lines_with_tag(self): + self.assertMarkdownRenders( + self.dedent( + """ + <!-- + + <tag> + + --> + """ + ), + self.dedent( + """ + <!-- + + <tag> + + --> + """ + ) + ) + + def test_raw_comment_with_blank_lines_first_line(self): + self.assertMarkdownRenders( + self.dedent( + """ + <!-- *foo* + + --> + """ + ), + self.dedent( + """ + <!-- *foo* + + --> + """ + ) + ) + + def test_raw_comment_with_blank_lines_last_line(self): + self.assertMarkdownRenders( + self.dedent( + """ + <!-- + + *foo* --> + """ + ), + self.dedent( + """ + <!-- + + *foo* --> + """ + ) + ) + + def test_raw_comment_indented(self): + self.assertMarkdownRenders( + self.dedent( + """ + <!-- + + *foo* + + --> + """ + ), + self.dedent( + """ + <!-- + + *foo* + + --> + """ + ) + ) + + def test_raw_comment_indented_with_tag(self): + self.assertMarkdownRenders( + self.dedent( + """ + <!-- + + <tag> + + --> + """ + ), + self.dedent( + """ + <!-- + + <tag> + + --> + """ + ) + ) + + def test_raw_comment_nested(self): + self.assertMarkdownRenders( + self.dedent( + """ + <div> + <!-- *foo* --> + </div> + """ + ), + self.dedent( + """ + <div> + <!-- *foo* --> + </div> + """ + ) + ) + + def test_comment_in_code_block(self): + self.assertMarkdownRenders( + ' <!-- *foo* -->', + self.dedent( + """ + <pre><code><!-- *foo* --> + </code></pre> + """ + ) + ) + + # Note: This is a change in behavior. Previously, Python-Markdown interpreted this in the same manner + # as browsers and all text after the opening comment tag was considered to be in a comment. However, + # that did not match the reference implementation. The new behavior does. + def test_unclosed_comment_(self): + self.assertMarkdownRenders( + self.dedent( + """ + <!-- unclosed comment + + *not* a comment + """ + ), + self.dedent( + """ + <p><!-- unclosed comment</p> + <p><em>not</em> a comment</p> + """ + ) + ) + + def test_raw_processing_instruction_one_line(self): + self.assertMarkdownRenders( + "<?php echo '>'; ?>", + "<?php echo '>'; ?>" + ) + + # This is a change in behavior and does not match the reference implementation. + # We have no way to determine if text is on the same line, so we get this. TODO: reevaluate! + def test_raw_processing_instruction_one_line_followed_by_text(self): + self.assertMarkdownRenders( + "<?php echo '>'; ?>*bar*", + self.dedent( + """ + <?php echo '>'; ?> + <p><em>bar</em></p> + """ + ) + ) + + def test_raw_multiline_processing_instruction(self): + self.assertMarkdownRenders( + self.dedent( + """ + <?php + echo '>'; + ?> + """ + ), + self.dedent( + """ + <?php + echo '>'; + ?> + """ + ) + ) + + def test_raw_processing_instruction_with_blank_lines(self): + self.assertMarkdownRenders( + self.dedent( + """ + <?php + + echo '>'; + + ?> + """ + ), + self.dedent( + """ + <?php + + echo '>'; + + ?> + """ + ) + ) + + def test_raw_processing_instruction_indented(self): + self.assertMarkdownRenders( + self.dedent( + """ + <?php + + echo '>'; + + ?> + """ + ), + self.dedent( + """ + <?php + + echo '>'; + + ?> + """ + ) + ) + + def test_raw_processing_instruction_code_span(self): + self.assertMarkdownRenders( + self.dedent( + """ + `<?php` + + <div> + foo + </div> + """ + ), + self.dedent( + """ + <p><code><?php</code></p> + <div> + foo + </div> + """ + ) + ) + + def test_raw_declaration_one_line(self): + self.assertMarkdownRenders( + '<!DOCTYPE html>', + '<!DOCTYPE html>' + ) + + # This is a change in behavior and does not match the reference implementation. + # We have no way to determine if text is on the same line, so we get this. TODO: reevaluate! + def test_raw_declaration_one_line_followed_by_text(self): + self.assertMarkdownRenders( + '<!DOCTYPE html>*bar*', + self.dedent( + """ + <!DOCTYPE html> + <p><em>bar</em></p> + """ + ) + ) + + def test_raw_multiline_declaration(self): + self.assertMarkdownRenders( + self.dedent( + """ + <!DOCTYPE html PUBLIC + "-//W3C//DTD XHTML 1.1//EN" + "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> + """ + ), + self.dedent( + """ + <!DOCTYPE html PUBLIC + "-//W3C//DTD XHTML 1.1//EN" + "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> + """ + ) + ) + + def test_raw_declaration_code_span(self): + self.assertMarkdownRenders( + self.dedent( + """ + `<!` + + <div> + foo + </div> + """ + ), + self.dedent( + """ + <p><code><!</code></p> + <div> + foo + </div> + """ + ) + ) + + def test_raw_cdata_one_line(self): + self.assertMarkdownRenders( + '<![CDATA[ document.write(">"); ]]>', + '<![CDATA[ document.write(">"); ]]>' + ) + + # Note: this is a change. Neither previous output nor this match reference implementation. + def test_raw_cdata_one_line_followed_by_text(self): + self.assertMarkdownRenders( + '<![CDATA[ document.write(">"); ]]>*bar*', + self.dedent( + """ + <![CDATA[ document.write(">"); ]]> + <p><em>bar</em></p> + """ + ) + ) + + def test_raw_multiline_cdata(self): + self.assertMarkdownRenders( + self.dedent( + """ + <![CDATA[ + document.write(">"); + ]]> + """ + ), + self.dedent( + """ + <![CDATA[ + document.write(">"); + ]]> + """ + ) + ) + + def test_raw_cdata_with_blank_lines(self): + self.assertMarkdownRenders( + self.dedent( + """ + <![CDATA[ + + document.write(">"); + + ]]> + """ + ), + self.dedent( + """ + <![CDATA[ + + document.write(">"); + + ]]> + """ + ) + ) + + def test_raw_cdata_indented(self): + self.assertMarkdownRenders( + self.dedent( + """ + <![CDATA[ + + document.write(">"); + + ]]> + """ + ), + self.dedent( + """ + <![CDATA[ + + document.write(">"); + + ]]> + """ + ) + ) + + def test_raw_cdata_code_span(self): + self.assertMarkdownRenders( + self.dedent( + """ + `<![` + + <div> + foo + </div> + """ + ), + self.dedent( + """ + <p><code><![</code></p> + <div> + foo + </div> + """ + ) + ) + + def test_charref(self): + self.assertMarkdownRenders( + '§', + '<p>§</p>' + ) + + def test_nested_charref(self): + self.assertMarkdownRenders( + '<p>§</p>', + '<p>§</p>' + ) + + def test_entityref(self): + self.assertMarkdownRenders( + '§', + '<p>§</p>' + ) + + def test_nested_entityref(self): + self.assertMarkdownRenders( + '<p>§</p>', + '<p>§</p>' + ) + + def test_amperstand(self): + self.assertMarkdownRenders( + 'AT&T & AT&T', + '<p>AT&T & AT&T</p>' + ) + + def test_startendtag(self): + self.assertMarkdownRenders( + '<hr>', + '<hr>' + ) + + def test_startendtag_with_attrs(self): + self.assertMarkdownRenders( + '<hr id="foo" class="bar">', + '<hr id="foo" class="bar">' + ) + + def test_startendtag_with_space(self): + self.assertMarkdownRenders( + '<hr >', + '<hr >' + ) + + def test_closed_startendtag(self): + self.assertMarkdownRenders( + '<hr />', + '<hr />' + ) + + def test_closed_startendtag_without_space(self): + self.assertMarkdownRenders( + '<hr/>', + '<hr/>' + ) + + def test_closed_startendtag_with_attrs(self): + self.assertMarkdownRenders( + '<hr id="foo" class="bar" />', + '<hr id="foo" class="bar" />' + ) + + def test_nested_startendtag(self): + self.assertMarkdownRenders( + '<div><hr></div>', + '<div><hr></div>' + ) + + def test_nested_closed_startendtag(self): + self.assertMarkdownRenders( + '<div><hr /></div>', + '<div><hr /></div>' + ) + + def test_auto_links_dont_break_parser(self): + self.assertMarkdownRenders( + self.dedent( + """ + <https://example.com> + + <email@example.com> + """ + ), + '<p><a href="https://example.com">https://example.com</a></p>\n' + '<p><a href="mailto:em' + 'ail@example' + '.com">email@e' + 'xample.com</a></p>' + ) + + def test_text_links_ignored(self): + self.assertMarkdownRenders( + self.dedent( + """ + https://example.com + + email@example.com + """ + ), + self.dedent( + """ + <p>https://example.com</p> + <p>email@example.com</p> + """ + ), + ) + + def text_invalid_tags(self): + self.assertMarkdownRenders( + self.dedent( + """ + <some [weird](http://example.com) stuff> + + <some>> <<unbalanced>> <<brackets> + """ + ), + self.dedent( + """ + <p><some <a href="http://example.com">weird</a> stuff></p> + <p><some>> <<unbalanced>> <<brackets></p> + """ + ) + ) + + def test_script_tags(self): + self.assertMarkdownRenders( + self.dedent( + """ + <script> + *random stuff* <div> & + </script> + + <style> + **more stuff** + </style> + """ + ), + self.dedent( + """ + <script> + *random stuff* <div> & + </script> + + <style> + **more stuff** + </style> + """ + ) + ) + + def test_unclosed_script_tag(self): + # Ensure we have a working fix for https://bugs.python.org/issue41989 + self.assertMarkdownRenders( + self.dedent( + """ + <script> + *random stuff* <div> & + + Still part of the *script* tag + """ + ), + self.dedent( + """ + <script> + *random stuff* <div> & + + Still part of the *script* tag + """ + ) + ) + + def test_inline_script_tags(self): + # Ensure inline script tags doesn't cause the parser to eat content (see #1036). + self.assertMarkdownRenders( + self.dedent( + """ + Text `<script>` more *text*. + + <div> + *foo* + </div> + + <div> + + bar + + </div> + + A new paragraph with a closing `</script>` tag. + """ + ), + self.dedent( + """ + <p>Text <code><script></code> more <em>text</em>.</p> + <div> + *foo* + </div> + + <div> + + bar + + </div> + + <p>A new paragraph with a closing <code></script></code> tag.</p> + """ + ) + ) + + def test_hr_only_start(self): + self.assertMarkdownRenders( + self.dedent( + """ + *emphasis1* + <hr> + *emphasis2* + """ + ), + self.dedent( + """ + <p><em>emphasis1</em></p> + <hr> + <p><em>emphasis2</em></p> + """ + ) + ) + + def test_hr_self_close(self): + self.assertMarkdownRenders( + self.dedent( + """ + *emphasis1* + <hr/> + *emphasis2* + """ + ), + self.dedent( + """ + <p><em>emphasis1</em></p> + <hr/> + <p><em>emphasis2</em></p> + """ + ) + ) + + def test_hr_start_and_end(self): + # Browsers ignore ending hr tags, so we don't try to do anything to handle them special. + self.assertMarkdownRenders( + self.dedent( + """ + *emphasis1* + <hr></hr> + *emphasis2* + """ + ), + self.dedent( + """ + <p><em>emphasis1</em></p> + <hr> + <p></hr> + <em>emphasis2</em></p> + """ + ) + ) + + def test_hr_only_end(self): + # Browsers ignore ending hr tags, so we don't try to do anything to handle them special. + self.assertMarkdownRenders( + self.dedent( + """ + *emphasis1* + </hr> + *emphasis2* + """ + ), + self.dedent( + """ + <p><em>emphasis1</em> + </hr> + <em>emphasis2</em></p> + """ + ) + ) + + def test_hr_with_content(self): + # Browsers ignore ending hr tags, so we don't try to do anything to handle them special. + # Content is not allowed and will be treated as normal content between two hr tags. + self.assertMarkdownRenders( + self.dedent( + """ + *emphasis1* + <hr> + **content** + </hr> + *emphasis2* + """ + ), + self.dedent( + """ + <p><em>emphasis1</em></p> + <hr> + <p><strong>content</strong> + </hr> + <em>emphasis2</em></p> + """ + ) + ) + + def test_placeholder_in_source(self): + # This should never occur, but third party extensions could create weird edge cases. + md = markdown.Markdown() + # Ensure there is an htmlstash so relevant code (nested in `if replacements`) is run. + md.htmlStash.store('foo') + # Run with a placeholder which is not in the stash + placeholder = md.htmlStash.get_placeholder(md.htmlStash.html_counter + 1) + result = md.postprocessors['raw_html'].run(placeholder) + self.assertEqual(placeholder, result) diff --git a/tests/test_syntax/blocks/test_paragraphs.py b/tests/test_syntax/blocks/test_paragraphs.py new file mode 100644 index 0000000..9b7ba03 --- /dev/null +++ b/tests/test_syntax/blocks/test_paragraphs.py @@ -0,0 +1,229 @@ +""" +Python Markdown + +A Python implementation of John Gruber's Markdown. + +Documentation: https://python-markdown.github.io/ +GitHub: https://github.com/Python-Markdown/markdown/ +PyPI: https://pypi.org/project/Markdown/ + +Started by Manfred Stienstra (http://www.dwerg.net/). +Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org). +Currently maintained by Waylan Limberg (https://github.com/waylan), +Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). + +Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later) +Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b) +Copyright 2004 Manfred Stienstra (the original version) + +License: BSD (see LICENSE.md for details). +""" + +from markdown.test_tools import TestCase + + +class TestParagraphBlocks(TestCase): + + def test_simple_paragraph(self): + self.assertMarkdownRenders( + 'A simple paragraph.', + + '<p>A simple paragraph.</p>' + ) + + def test_blank_line_before_paragraph(self): + self.assertMarkdownRenders( + '\nA paragraph preceded by a blank line.', + + '<p>A paragraph preceded by a blank line.</p>' + ) + + def test_multiline_paragraph(self): + self.assertMarkdownRenders( + self.dedent( + """ + This is a paragraph + on multiple lines + with hard returns. + """ + ), + self.dedent( + """ + <p>This is a paragraph + on multiple lines + with hard returns.</p> + """ + ) + ) + + def test_paragraph_long_line(self): + self.assertMarkdownRenders( + 'A very long long long long long long long long long long long long long long long long long long long ' + 'long long long long long long long long long long long long long paragraph on 1 line.', + + '<p>A very long long long long long long long long long long long long long long long long long long ' + 'long long long long long long long long long long long long long long paragraph on 1 line.</p>' + ) + + def test_2_paragraphs_long_line(self): + self.assertMarkdownRenders( + 'A very long long long long long long long long long long long long long long long long long long long ' + 'long long long long long long long long long long long long long paragraph on 1 line.\n\n' + + 'A new long long long long long long long long long long long long long long long ' + 'long paragraph on 1 line.', + + '<p>A very long long long long long long long long long long long long long long long long long long ' + 'long long long long long long long long long long long long long long paragraph on 1 line.</p>\n' + '<p>A new long long long long long long long long long long long long long long long ' + 'long paragraph on 1 line.</p>' + ) + + def test_consecutive_paragraphs(self): + self.assertMarkdownRenders( + self.dedent( + """ + Paragraph 1. + + Paragraph 2. + """ + ), + self.dedent( + """ + <p>Paragraph 1.</p> + <p>Paragraph 2.</p> + """ + ) + ) + + def test_consecutive_paragraphs_tab(self): + self.assertMarkdownRenders( + self.dedent( + """ + Paragraph followed by a line with a tab only. + \t + Paragraph after a line with a tab only. + """ + ), + self.dedent( + """ + <p>Paragraph followed by a line with a tab only.</p> + <p>Paragraph after a line with a tab only.</p> + """ + ) + ) + + def test_consecutive_paragraphs_space(self): + self.assertMarkdownRenders( + self.dedent( + """ + Paragraph followed by a line with a space only. + + Paragraph after a line with a space only. + """ + ), + self.dedent( + """ + <p>Paragraph followed by a line with a space only.</p> + <p>Paragraph after a line with a space only.</p> + """ + ) + ) + + def test_consecutive_multiline_paragraphs(self): + self.assertMarkdownRenders( + self.dedent( + """ + Paragraph 1, line 1. + Paragraph 1, line 2. + + Paragraph 2, line 1. + Paragraph 2, line 2. + """ + ), + self.dedent( + """ + <p>Paragraph 1, line 1. + Paragraph 1, line 2.</p> + <p>Paragraph 2, line 1. + Paragraph 2, line 2.</p> + """ + ) + ) + + def test_paragraph_leading_space(self): + self.assertMarkdownRenders( + ' A paragraph with 1 leading space.', + + '<p>A paragraph with 1 leading space.</p>' + ) + + def test_paragraph_2_leading_spaces(self): + self.assertMarkdownRenders( + ' A paragraph with 2 leading spaces.', + + '<p>A paragraph with 2 leading spaces.</p>' + ) + + def test_paragraph_3_leading_spaces(self): + self.assertMarkdownRenders( + ' A paragraph with 3 leading spaces.', + + '<p>A paragraph with 3 leading spaces.</p>' + ) + + def test_paragraph_trailing_leading_space(self): + self.assertMarkdownRenders( + ' A paragraph with 1 trailing and 1 leading space. ', + + '<p>A paragraph with 1 trailing and 1 leading space. </p>' + ) + + def test_paragraph_trailing_tab(self): + self.assertMarkdownRenders( + 'A paragraph with 1 trailing tab.\t', + + '<p>A paragraph with 1 trailing tab. </p>' + ) + + def test_paragraphs_CR(self): + self.assertMarkdownRenders( + 'Paragraph 1, line 1.\rParagraph 1, line 2.\r\rParagraph 2, line 1.\rParagraph 2, line 2.\r', + + self.dedent( + """ + <p>Paragraph 1, line 1. + Paragraph 1, line 2.</p> + <p>Paragraph 2, line 1. + Paragraph 2, line 2.</p> + """ + ) + ) + + def test_paragraphs_LF(self): + self.assertMarkdownRenders( + 'Paragraph 1, line 1.\nParagraph 1, line 2.\n\nParagraph 2, line 1.\nParagraph 2, line 2.\n', + + self.dedent( + """ + <p>Paragraph 1, line 1. + Paragraph 1, line 2.</p> + <p>Paragraph 2, line 1. + Paragraph 2, line 2.</p> + """ + ) + ) + + def test_paragraphs_CR_LF(self): + self.assertMarkdownRenders( + 'Paragraph 1, line 1.\r\nParagraph 1, line 2.\r\n\r\nParagraph 2, line 1.\r\nParagraph 2, line 2.\r\n', + + self.dedent( + """ + <p>Paragraph 1, line 1. + Paragraph 1, line 2.</p> + <p>Paragraph 2, line 1. + Paragraph 2, line 2.</p> + """ + ) + ) |