""" 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-2019 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 from markdown.extensions.codehilite import CodeHiliteExtension, CodeHilite import os try: import pygments # noqa has_pygments = True except ImportError: has_pygments = False # The version required by the tests is the version specified and installed in the 'pygments' tox env. # In any environment where the PYGMENTS_VERSION environment variable is either not defined or doesn't # match the version of Pygments installed, all tests which rely in pygments will be skipped. required_pygments_version = os.environ.get('PYGMENTS_VERSION', '') class TestCodeHiliteClass(TestCase): """ Test the markdown.extensions.codehilite.CodeHilite class. """ def setUp(self): if has_pygments and pygments.__version__ != required_pygments_version: self.skipTest(f'Pygments=={required_pygments_version} is required') maxDiff = None def assertOutputEquals(self, source, expected, **options): """ Test that source code block results in the expected output with given options. """ output = CodeHilite(source, **options).hilite() self.assertMultiLineEqual(output.strip(), expected) def test_codehilite_defaults(self): if has_pygments: # Odd result as no lang given and a single comment is not enough for guessing. expected = ( '
# A Code Comment\n'
                '
' ) else: expected = ( '
# A Code Comment\n'
                '
' ) self.assertOutputEquals('# A Code Comment', expected) def test_codehilite_guess_lang(self): if has_pygments: expected = ( '
<?php '
                'print("Hello World"'
                '); ?>\n'
                '
' ) else: expected = ( '
<?php print("Hello World"); ?>\n'
                '
' ) # Use PHP as the the starting `', expected, guess_lang=True) def test_codehilite_guess_lang_plain_text(self): if has_pygments: expected = ( '
plain text\n'
                '
' ) else: expected = ( '
plain text\n'
                '
' ) # This will be difficult to guess. self.assertOutputEquals('plain text', expected, guess_lang=True) def test_codehilite_set_lang(self): if has_pygments: # Note an extra `` is added to end of code block when lang explicitly set. # Compare with expected output for `test_guess_lang`. Not sure why this happens. expected = ( '
<?php '
                'print("Hello World"'
                '); ?>\n'
                '
' ) else: expected = ( '
<?php print("Hello World"); ?>\n'
                '
' ) self.assertOutputEquals('', expected, lang='php') def test_codehilite_bad_lang(self): if has_pygments: expected = ( '
<?php '
                'print('
                '"Hello World"); ?>\n'
                '
' ) else: # Note that without pygments there is no way to check that the language name is bad. expected = ( '
'
                '<?php print("Hello World"); ?>\n'
                '
' ) # The starting `', expected, lang='unkown') def test_codehilite_use_pygments_false(self): expected = ( '
<?php print("Hello World"); ?>\n'
            '
' ) self.assertOutputEquals('', expected, lang='php', use_pygments=False) def test_codehilite_lang_prefix_empty(self): expected = ( '
<?php print("Hello World"); ?>\n'
            '
' ) self.assertOutputEquals( '', expected, lang='php', use_pygments=False, lang_prefix='' ) def test_codehilite_lang_prefix(self): expected = ( '
<?php print("Hello World"); ?>\n'
            '
' ) self.assertOutputEquals( '', expected, lang='php', use_pygments=False, lang_prefix='lang-' ) def test_codehilite_linenos_true(self): if has_pygments: expected = ( '
1
' '
plain text\n'
                '
\n' '
' ) else: expected = ( '
plain text\n'
                '
' ) self.assertOutputEquals('plain text', expected, lang='text', linenos=True) def test_codehilite_linenos_false(self): if has_pygments: expected = ( '
plain text\n'
                '
' ) else: expected = ( '
plain text\n'
                '
' ) self.assertOutputEquals('plain text', expected, lang='text', linenos=False) def test_codehilite_linenos_none(self): if has_pygments: expected = ( '
plain text\n'
                '
' ) else: expected = ( '
plain text\n'
                '
' ) self.assertOutputEquals('plain text', expected, lang='text', linenos=None) def test_codehilite_linenos_table(self): if has_pygments: expected = ( '
1
' '
plain text\n'
                '
\n' '
' ) else: expected = ( '
plain text\n'
                '
' ) self.assertOutputEquals('plain text', expected, lang='text', linenos='table') def test_codehilite_linenos_inline(self): if has_pygments: expected = ( '
1plain text\n'
                '
' ) else: expected = ( '
plain text\n'
                '
' ) self.assertOutputEquals('plain text', expected, lang='text', linenos='inline') def test_codehilite_linenums_true(self): if has_pygments: expected = ( '
1
' '
plain text\n'
                '
\n' '
' ) else: expected = ( '
plain text\n'
                '
' ) self.assertOutputEquals('plain text', expected, lang='text', linenums=True) def test_codehilite_set_cssclass(self): if has_pygments: expected = ( '
plain text\n'
                '
' ) else: expected = ( '
plain text\n'
                '
' ) self.assertOutputEquals('plain text', expected, lang='text', cssclass='override') def test_codehilite_set_css_class(self): if has_pygments: expected = ( '
plain text\n'
                '
' ) else: expected = ( '
plain text\n'
                '
' ) self.assertOutputEquals('plain text', expected, lang='text', css_class='override') def test_codehilite_linenostart(self): if has_pygments: expected = ( '
42plain text\n'
                '
' ) else: # TODO: Implement linenostart for no-pygments. Will need to check what JS libs look for. expected = ( '
plain text\n'
                '
' ) self.assertOutputEquals('plain text', expected, lang='text', linenos='inline', linenostart=42) def test_codehilite_linenos_hl_lines(self): if has_pygments: expected = ( '
'
                '1line 1\n'
                '2line 2\n'
                '3line 3\n'
                '
' ) else: expected = ( '
line 1\n'
                'line 2\n'
                'line 3\n'
                '
' ) self.assertOutputEquals('line 1\nline 2\nline 3', expected, lang='text', linenos='inline', hl_lines=[1, 3]) def test_codehilite_linenos_linenostep(self): if has_pygments: expected = ( '
 line 1\n'
                '2line 2\n'
                ' line 3\n'
                '
' ) else: expected = ( '
line 1\n'
                'line 2\n'
                'line 3\n'
                '
' ) self.assertOutputEquals('line 1\nline 2\nline 3', expected, lang='text', linenos='inline', linenostep=2) def test_codehilite_linenos_linenospecial(self): if has_pygments: expected = ( '
1line 1\n'
                '2line 2\n'
                '3line 3\n'
                '
' ) else: expected = ( '
line 1\n'
                'line 2\n'
                'line 3\n'
                '
' ) self.assertOutputEquals('line 1\nline 2\nline 3', expected, lang='text', linenos='inline', linenospecial=2) def test_codehilite_startinline(self): if has_pygments: expected = ( '
print('
                '"Hello World");\n'
                '
' ) else: expected = ( '
print("Hello World");\n'
                '
' ) self.assertOutputEquals('print("Hello World");', expected, lang='php', startinline=True) class TestCodeHiliteExtension(TestCase): """ Test codehilite extension. """ def setUp(self): if has_pygments and pygments.__version__ != required_pygments_version: self.skipTest(f'Pygments=={required_pygments_version} is required') # Define a custom Pygments formatter (same example in the documentation) if has_pygments: class CustomAddLangHtmlFormatter(pygments.formatters.HtmlFormatter): def __init__(self, lang_str='', **options): super().__init__(**options) self.lang_str = lang_str def _wrap_code(self, source): yield 0, f'' yield from source yield 0, '' else: CustomAddLangHtmlFormatter = None self.custom_pygments_formatter = CustomAddLangHtmlFormatter maxDiff = None def testBasicCodeHilite(self): if has_pygments: # Odd result as no lang given and a single comment is not enough for guessing. expected = ( '
# A Code Comment\n'
                '
' ) else: expected = ( '
# A Code Comment\n'
                '
' ) self.assertMarkdownRenders( '\t# A Code Comment', expected, extensions=['codehilite'] ) def testLinenumsTrue(self): if has_pygments: expected = ( '' '' '
1
'
                '# A Code Comment\n'
                '
\n' '
' ) else: expected = ( '
# A Code Comment\n'
                '
' ) self.assertMarkdownRenders( '\t# A Code Comment', expected, extensions=[CodeHiliteExtension(linenums=True)] ) def testLinenumsFalse(self): if has_pygments: expected = ( '
# A Code Comment\n'
                '
' ) else: expected = ( '
# A Code Comment\n'
                '
' ) self.assertMarkdownRenders( ( '\t#!Python\n' '\t# A Code Comment' ), expected, extensions=[CodeHiliteExtension(linenums=False)] ) def testLinenumsNone(self): if has_pygments: expected = ( '
# A Code Comment\n'
                '
' ) else: expected = ( '
# A Code Comment\n'
                '
' ) self.assertMarkdownRenders( '\t# A Code Comment', expected, extensions=[CodeHiliteExtension(linenums=None)] ) def testLinenumsNoneWithShebang(self): if has_pygments: expected = ( '' '' '
1
'
                '# A Code Comment\n'
                '
\n' '
' ) else: expected = ( '
# A Code Comment\n'
                '
' ) self.assertMarkdownRenders( ( '\t#!Python\n' '\t# A Code Comment' ), expected, extensions=[CodeHiliteExtension(linenums=None)] ) def testLinenumsNoneWithColon(self): if has_pygments: expected = ( '
# A Code Comment\n'
                '
' ) else: expected = ( '
# A Code Comment\n'
                '
' ) self.assertMarkdownRenders( ( '\t:::Python\n' '\t# A Code Comment' ), expected, extensions=[CodeHiliteExtension(linenums=None)] ) def testHighlightLinesWithColon(self): if has_pygments: expected = ( '
#line 1\n'
                '#line 2\n'
                '#line 3\n'
                '
' ) else: expected = ( '
#line 1\n'
                '#line 2\n'
                '#line 3\n'
                '
' ) # Double quotes self.assertMarkdownRenders( ( '\t:::Python hl_lines="1"\n' '\t#line 1\n' '\t#line 2\n' '\t#line 3' ), expected, extensions=['codehilite'] ) # Single quotes self.assertMarkdownRenders( ( "\t:::Python hl_lines='1'\n" '\t#line 1\n' '\t#line 2\n' '\t#line 3' ), expected, extensions=['codehilite'] ) def testUsePygmentsFalse(self): self.assertMarkdownRenders( ( '\t:::Python\n' '\t# A Code Comment' ), ( '
# A Code Comment\n'
                '
' ), extensions=[CodeHiliteExtension(use_pygments=False)] ) def testLangPrefixEmpty(self): self.assertMarkdownRenders( ( '\t:::Python\n' '\t# A Code Comment' ), ( '
# A Code Comment\n'
                '
' ), extensions=[CodeHiliteExtension(use_pygments=False, lang_prefix='')] ) def testLangPrefix(self): self.assertMarkdownRenders( ( '\t:::Python\n' '\t# A Code Comment' ), ( '
# A Code Comment\n'
                '
' ), extensions=[CodeHiliteExtension(use_pygments=False, lang_prefix='lang-')] ) def testDoubleEscape(self): if has_pygments: expected = ( '
'
                ''
                '<span>'
                'This&amp;That'
                '</span>'
                '\n
' ) else: expected = ( '
'
                '<span>This&amp;That</span>\n'
                '
' ) self.assertMarkdownRenders( ( '\t:::html\n' '\tThis&That' ), expected, extensions=['codehilite'] ) def testEntitiesIntact(self): if has_pygments: expected = ( '
'
                ''
                '< &lt; and > &gt;'
                '\n
' ) else: expected = ( '
'
                '< &lt; and > &gt;\n'
                '
' ) self.assertMarkdownRenders( ( '\t:::text\n' '\t< < and > >' ), expected, extensions=['codehilite'] ) def testHighlightAmps(self): if has_pygments: expected = ( '
&\n'
                '&amp;\n'
                '&amp;amp;\n'
                '
' ) else: expected = ( '
&\n'
                '&amp;\n'
                '&amp;amp;\n'
                '
' ) self.assertMarkdownRenders( ( '\t:::text\n' '\t&\n' '\t&\n' '\t&amp;' ), expected, extensions=['codehilite'] ) def testUnknownOption(self): if has_pygments: # Odd result as no lang given and a single comment is not enough for guessing. expected = ( '
# A Code Comment\n'
                '
' ) else: expected = ( '
# A Code Comment\n'
                '
' ) self.assertMarkdownRenders( '\t# A Code Comment', expected, extensions=[CodeHiliteExtension(unknown='some value')], ) def testMultipleBlocksSameStyle(self): if has_pygments: # See also: https://github.com/Python-Markdown/markdown/issues/1240 expected = ( '
'
                '# First Code Block\n'
                '
\n\n' '

Normal paragraph

\n' '
'
                '# Second Code Block\n'
                '
' ) else: expected = ( '
# First Code Block\n'
                '
\n\n' '

Normal paragraph

\n' '
# Second Code Block\n'
                '
' ) self.assertMarkdownRenders( ( '\t:::Python\n' '\t# First Code Block\n\n' 'Normal paragraph\n\n' '\t:::Python\n' '\t# Second Code Block' ), expected, extensions=[CodeHiliteExtension(pygments_style="native", noclasses=True)] ) def testFormatterLangStr(self): if has_pygments: expected = ( '
'
                '# A Code Comment\n'
                '
' ) else: expected = ( '
# A Code Comment\n'
                '
' ) self.assertMarkdownRenders( '\t:::Python\n' '\t# A Code Comment', expected, extensions=[ CodeHiliteExtension( guess_lang=False, pygments_formatter=self.custom_pygments_formatter ) ] ) def testFormatterLangStrGuessLang(self): if has_pygments: expected = ( '
'
                '<?php '
                'print('
                '"Hello World"'
                '); ?>\n'
                '
' ) else: expected = ( '
<?php print("Hello World"); ?>\n'
                '
' ) # Use PHP as the the starting `', expected, extensions=[CodeHiliteExtension(pygments_formatter=self.custom_pygments_formatter)] ) def testFormatterLangStrEmptyLang(self): if has_pygments: expected = ( '
'
                '# A Code Comment\n'
                '
' ) else: expected = ( '
# A Code Comment\n'
                '
' ) self.assertMarkdownRenders( '\t# A Code Comment', expected, extensions=[ CodeHiliteExtension( guess_lang=False, pygments_formatter=self.custom_pygments_formatter, ) ] )