aboutsummaryrefslogtreecommitdiff
path: root/tests/test_syntax/blocks/test_html_blocks.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test_syntax/blocks/test_html_blocks.py')
-rw-r--r--tests/test_syntax/blocks/test_html_blocks.py1619
1 files changed, 1619 insertions, 0 deletions
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>&lt;p&gt;code block&lt;/p&gt;
+ </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>&lt;p&gt;code span&lt;/p&gt;</code></p>'
+ )
+
+ def test_code_span_open_gt(self):
+ self.assertMarkdownRenders(
+ '*bar* `<` *foo*',
+ '<p><em>bar</em> <code>&lt;</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>&lt;p&gt;code span&lt;/p&gt;</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>&lt;div&gt;</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>
+ &lt;p&gt;foo&lt;/p&gt;
+ </pre>
+ """
+ ),
+ self.dedent(
+ """
+ <pre>
+ &lt;p&gt;foo&lt;/p&gt;
+ </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>&lt;</p>'
+ )
+
+ def test_raw_open_bracket_followed_by_space(self):
+ self.assertMarkdownRenders(
+ '< foo',
+ '<p>&lt; foo</p>'
+ )
+
+ def test_raw_missing_close_bracket(self):
+ self.assertMarkdownRenders(
+ '<foo',
+ '<p>&lt;foo</p>'
+ )
+
+ def test_raw_unclosed_tag_in_code_span(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ `<div`.
+
+ <div>
+ hello
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <p><code>&lt;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>&lt;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>&lt;!-- *foo* --&gt;</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>&lt;!-- *foo* --&gt;
+ </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>&lt;!-- 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>&lt;?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>&lt;!</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>&lt;![</code></p>
+ <div>
+ foo
+ </div>
+ """
+ )
+ )
+
+ def test_charref(self):
+ self.assertMarkdownRenders(
+ '&sect;',
+ '<p>&sect;</p>'
+ )
+
+ def test_nested_charref(self):
+ self.assertMarkdownRenders(
+ '<p>&sect;</p>',
+ '<p>&sect;</p>'
+ )
+
+ def test_entityref(self):
+ self.assertMarkdownRenders(
+ '&#167;',
+ '<p>&#167;</p>'
+ )
+
+ def test_nested_entityref(self):
+ self.assertMarkdownRenders(
+ '<p>&#167;</p>',
+ '<p>&#167;</p>'
+ )
+
+ def test_amperstand(self):
+ self.assertMarkdownRenders(
+ 'AT&T & AT&amp;T',
+ '<p>AT&amp;T &amp; AT&amp;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="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#101;&#109;'
+ '&#97;&#105;&#108;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;'
+ '&#46;&#99;&#111;&#109;">&#101;&#109;&#97;&#105;&#108;&#64;&#101;'
+ '&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;</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>&gt; &lt;<unbalanced>&gt; &lt;<brackets></p>
+ """
+ )
+ )
+
+ def test_script_tags(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <script>
+ *random stuff* <div> &amp;
+ </script>
+
+ <style>
+ **more stuff**
+ </style>
+ """
+ ),
+ self.dedent(
+ """
+ <script>
+ *random stuff* <div> &amp;
+ </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> &amp;
+
+ Still part of the *script* tag
+ """
+ ),
+ self.dedent(
+ """
+ <script>
+ *random stuff* <div> &amp;
+
+ 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>&lt;script&gt;</code> more <em>text</em>.</p>
+ <div>
+ *foo*
+ </div>
+
+ <div>
+
+ bar
+
+ </div>
+
+ <p>A new paragraph with a closing <code>&lt;/script&gt;</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)