# -*- coding: utf-8 -*- from __future__ import unicode_literals from django.contrib.auth import get_user_model from django.test import TestCase from misago.markup.parser import parse UserModel = get_user_model() class MockRequest(object): scheme = 'http' def __init__(self, user=None): self.user = user def get_host(self): return 'test.com' class MockPoster(object): username = 'LoremIpsum' slug = 'loremipsum' class HTMLTests(TestCase): def test_html_escaped(self): """parser escapes all html""" test_text = """ Lorem <strong>ipsum!</strong> """.strip() expected_result = """ <p>Lorem <strong>ipsum!</strong></p> """.strip() result = parse(test_text, MockRequest(), MockPoster(), minify=True) self.assertEqual(expected_result, result['parsed_text']) self.assertEqual(result['internal_links'], []) self.assertEqual(result['images'], []) self.assertEqual(result['outgoing_links'], []) class BBCodeTests(TestCase): def test_inline_text(self): """inline elements are correctly parsed""" test_text = """ Lorem **ipsum**, dolor met. Lorem [b]ipsum[/b], [i]dolor[/i] [u]met[/u]. Lorem [b]**ipsum**[/b] [i]dolor[/i] [u]met[/u]. Lorem [b]**ipsum[/b]** [i]dolor[/i] [u]met[/u]. Lorem [b]__ipsum[/b]__ [i]dolor[/i] [u]met[/u]. Lorem [b][i]ipsum[/i][/b]. Lorem [b][i]ipsum[/b][/i]. Lorem [b]ipsum[/B]. """.strip() expected_result = """ <p>Lorem <strong>ipsum</strong>, dolor met.</p> <p>Lorem <b>ipsum</b>, <i>dolor</i> <u>met</u>.</p> <p>Lorem <b><strong>ipsum</strong></b> <i>dolor</i> <u>met</u>.</p> <p>Lorem <b>**ipsum</b>** <i>dolor</i> <u>met</u>.</p> <p>Lorem <b>__ipsum</b>__ <i>dolor</i> <u>met</u>.</p> <p>Lorem <b><i>ipsum</i></b>.</p> <p>Lorem <b>[i]ipsum</b>[/i].</p> <p>Lorem <b>ipsum</b>.</p> """.strip() result = parse(test_text, MockRequest(), MockPoster(), minify=False) self.assertEqual(expected_result, result['parsed_text']) def test_hr(self): """hr bbcode is correctly parsed""" test_text = """ Lorem ipsum. [hr] Dolor met. """.strip() expected_result = """ <p>Lorem ipsum.</p> <hr/> <p>Dolor met.</p> """.strip() result = parse(test_text, MockRequest(), MockPoster(), minify=False) self.assertEqual(expected_result, result['parsed_text']) def test_img(self): """img bbcode is correctly parsed""" test_text = """ Lorem ipsum [img]https://placekitten.com/g/1200/500[/img] Lorem ipsum [iMg]https://placekitten.com/g/1200/500[/ImG] Lorem ipsum !(https://placekitten.com/g/1200/500) """.strip() expected_result = """ <p>Lorem ipsum <img alt="placekitten.com/g/1200/500" src="https://placekitten.com/g/1200/500"/></p> <p>Lorem ipsum <img alt="placekitten.com/g/1200/500" src="https://placekitten.com/g/1200/500"/></p> <p>Lorem ipsum <img alt="placekitten.com/g/1200/500" src="https://placekitten.com/g/1200/500"/></p> """.strip() result = parse(test_text, MockRequest(), MockPoster(), minify=False) self.assertEqual(expected_result, result['parsed_text']) def test_url(self): """url bbcode is correctly parsed""" test_text = """ Lorem ipsum [url]placekitten.com/g/300/300[/url] Lorem ipsum [url]https://placekitten.com/g/600/600[/url] Lorem ipsum [uRL=https://placekitten.com/g/400/400"]Label text![/UrL] Lorem ipsum [Lorem ipsum](https://placekitten.com/g/1200/500) """.strip() expected_result = """ <p>Lorem ipsum <a href="http://placekitten.com/g/300/300" rel="nofollow">placekitten.com/g/300/300</a></p> <p>Lorem ipsum <a href="https://placekitten.com/g/600/600" rel="nofollow">placekitten.com/g/600/600</a></p> <p>Lorem ipsum <a href="https://placekitten.com/g/400/400" rel="nofollow">Label text!</a></p> <p>Lorem ipsum <a href="https://placekitten.com/g/1200/500" rel="nofollow">Lorem ipsum</a></p> """.strip() result = parse(test_text, MockRequest(), MockPoster(), minify=False) self.assertEqual(expected_result, result['parsed_text']) class MinifyTests(TestCase): def test_minified_text(self): """parser minifies text successfully""" test_text = """ Lorem ipsum. Lorem ipsum. """.strip() expected_result = """ <p>Lorem ipsum.</p><p>Lorem ipsum.</p> """.strip() result = parse(test_text, MockRequest(), MockPoster(), minify=True) self.assertEqual(expected_result, result['parsed_text']) def test_minified_unicode_text(self): """parser minifies unicode text successfully""" test_text = """ Bżęczyszczykiewłicz ipsum. Lorem ipsum. """.strip() expected_result = """ <p>Bżęczyszczykiewłicz ipsum.</p><p>Lorem ipsum.</p> """.strip() result = parse(test_text, MockRequest(), MockPoster(), minify=True) self.assertEqual(expected_result, result['parsed_text']) def test_complex_paragraph(self): """parser minifies complex paragraph""" user = UserModel.objects.create_user('Bob', 'bob@test.com', 'Pass123') test_text = """ Hey there @{}, how's going? """.strip().format(user) expected_result = """ <p>Hey there <a href="{}">@{}</a>, how's going?</p> """.strip().format(user.get_absolute_url(), user) result = parse(test_text, MockRequest(user), user, minify=True) self.assertEqual(expected_result, result['parsed_text']) class CleanLinksTests(TestCase): def test_clean_current_link(self): """clean_links step cleans http://test.com""" test_text = """ Lorem ipsum: http://test.com """.strip() expected_result = """ <p>Lorem ipsum: <a href="/">test.com</a></p> """.strip() result = parse(test_text, MockRequest(), MockPoster(), minify=True) self.assertEqual(expected_result, result['parsed_text']) self.assertEqual(result['internal_links'], ['/']) self.assertEqual(result['images'], []) self.assertEqual(result['outgoing_links'], []) def test_clean_schemaless_link(self): """clean_links step cleans test.com""" test_text = """ Lorem ipsum: test.com """.strip() expected_result = """ <p>Lorem ipsum: <a href="/">test.com</a></p> """.strip() result = parse(test_text, MockRequest(), MockPoster(), minify=True) self.assertEqual(expected_result, result['parsed_text']) self.assertEqual(result['internal_links'], ['/']) self.assertEqual(result['images'], []) self.assertEqual(result['outgoing_links'], []) def test_trim_current_path(self): """clean_links step leaves http://test.com path""" test_text = """ Lorem ipsum: http://test.com/somewhere-something/ """.strip() expected_result = """ <p>Lorem ipsum: <a href="/somewhere-something/">test.com/somewhere-something/</a></p> """.strip() result = parse(test_text, MockRequest(), MockPoster(), minify=True) self.assertEqual(expected_result, result['parsed_text']) self.assertEqual(result['internal_links'], ['/somewhere-something/']) self.assertEqual(result['images'], []) self.assertEqual(result['outgoing_links'], []) def test_clean_outgoing_link_domain(self): """clean_links step leaves outgoing domain link""" test_text = """ Lorem ipsum: http://somewhere.com """.strip() expected_result = """ <p>Lorem ipsum: <a href="http://somewhere.com" rel="nofollow">somewhere.com</a></p> """.strip() result = parse(test_text, MockRequest(), MockPoster(), minify=True) self.assertEqual(expected_result, result['parsed_text']) self.assertEqual(result['outgoing_links'], ['somewhere.com']) self.assertEqual(result['images'], []) self.assertEqual(result['internal_links'], []) def test_trim_outgoing_path(self): """clean_links step leaves outgoing link domain and path""" test_text = """ Lorem ipsum: http://somewhere.com/somewhere-something/ """.strip() expected_result = """ <p>Lorem ipsum: <a href="http://somewhere.com/somewhere-something/" rel="nofollow">somewhere.com/somewhere-something/</a></p> """.strip() result = parse(test_text, MockRequest(), MockPoster(), minify=True) self.assertEqual(expected_result, result['parsed_text']) self.assertEqual(result['outgoing_links'], ['somewhere.com/somewhere-something/']) self.assertEqual(result['images'], []) self.assertEqual(result['internal_links'], []) def test_clean_local_image_src(self): """clean_links step cleans local image src""" test_text = """ !(http://test.com/image.jpg) """.strip() expected_result = """ <p><img alt="test.com/image.jpg" src="/image.jpg"/></p> """.strip() result = parse(test_text, MockRequest(), MockPoster(), minify=True) self.assertEqual(expected_result, result['parsed_text']) self.assertEqual(result['images'], ['/image.jpg']) self.assertEqual(result['internal_links'], []) self.assertEqual(result['outgoing_links'], []) def test_clean_remote_image_src(self): """clean_links step cleans remote image src""" test_text = """ !(http://somewhere.com/image.jpg) """.strip() expected_result = """ <p><img alt="somewhere.com/image.jpg" src="http://somewhere.com/image.jpg"/></p> """.strip() result = parse(test_text, MockRequest(), MockPoster(), minify=True) self.assertEqual(expected_result, result['parsed_text']) self.assertEqual(result['images'], ['somewhere.com/image.jpg']) self.assertEqual(result['internal_links'], []) self.assertEqual(result['outgoing_links'], []) def test_clean_linked_image(self): """parser handles image element nested in link""" test_text = """ [](http://test.com/a/test/43/) """.strip() expected_result = """ <p><a href="/a/test/43/"><img alt="3.png" src="/a/thumb/test/43/"/></a></p> """.strip() result = parse(test_text, MockRequest(), MockPoster(), minify=True) self.assertEqual(expected_result, result['parsed_text']) self.assertEqual(result['images'], ['/a/thumb/test/43/']) self.assertEqual(result['internal_links'], ['/a/test/43/']) self.assertEqual(result['outgoing_links'], []) def test_force_shva(self): """parser appends ?shva=1 bit to attachment links if flag is present""" test_text = """  """.strip() expected_result = """ <p><img alt="3.png" src="/a/thumb/test/43/?shva=1"/></p> """.strip() result = parse(test_text, MockRequest(), MockPoster(), minify=True, force_shva=True) self.assertEqual(expected_result, result['parsed_text']) self.assertEqual(result['images'], ['/a/thumb/test/43/']) self.assertEqual(result['internal_links'], []) self.assertEqual(result['outgoing_links'], []) def test_remove_shva(self): """parser removes ?shva=1 bit from attachment links if flag is absent""" test_text = """  """.strip() expected_result = """ <p><img alt="3.png" src="/a/thumb/test/43/"/></p> """.strip() result = parse(test_text, MockRequest(), MockPoster(), minify=True) self.assertEqual(expected_result, result['parsed_text']) self.assertEqual(result['images'], ['/a/thumb/test/43/?shva=1']) self.assertEqual(result['internal_links'], []) self.assertEqual(result['outgoing_links'], []) class LinkifyTests(TestCase): def test_clean_current_link(self): """clean_links step cleans http://test.com""" test_text = """ Lorem ipsum: `<http://test.com>` """.strip() expected_result = """ <p>Lorem ipsum: <code><http://test.com></code></p> """.strip() result = parse(test_text, MockRequest(), MockPoster(), minify=True) self.assertEqual(expected_result, result['parsed_text']) self.assertEqual(result['internal_links'], []) self.assertEqual(result['images'], []) self.assertEqual(result['outgoing_links'], []) class StriketroughTests(TestCase): def test_striketrough(self): """striketrough markdown deletes test""" test_text = """ Lorem ~~ipsum, dolor~~ met. """.strip() expected_result = """ <p>Lorem <del>ipsum, dolor</del> met.</p> """.strip() result = parse(test_text, MockRequest(), MockPoster(), minify=False) self.assertEqual(expected_result, result['parsed_text']) class QuoteTests(TestCase): def test_quotes(self): """bbcode for quote is supported""" test_text = """ Lorem ipsum. [quote]Dolor met[/quote] [quote]Dolor <b>met</b>[/quote] [quote]Dolor **met**[quote]Dolor met[/quote][/quote] """.strip() expected_result = """ <p>Lorem ipsum.</p> <aside class="quote-block"> <div class="quote-heading"></div> <blockquote class="quote-body"> <p>Dolor met</p> </blockquote> </aside> <aside class="quote-block"> <div class="quote-heading"></div> <blockquote class="quote-body"> <p>Dolor <b>met</b></p> </blockquote> </aside> <aside class="quote-block"> <div class="quote-heading"></div> <blockquote class="quote-body"> <p>Dolor <strong>met</strong></p> <aside class="quote-block"> <div class="quote-heading"></div> <blockquote class="quote-body"> <p>Dolor met</p> </blockquote> </aside> </blockquote> </aside> """.strip() result = parse(test_text, MockRequest(), MockPoster(), minify=False) self.assertEqual(expected_result, result['parsed_text']) def test_authored_quotes(self): """bbcode for authored quote is supported and handles mentions as well""" test_text = """ Lorem ipsum. [quote]Dolor met[/quote] [quote=\"@Bob\"]Dolor <b>met</b>[/quote] [quote]Dolor **met**[quote=@Bob]Dolor met[/quote][/quote] """.strip() expected_result = """ <p>Lorem ipsum.</p> <aside class="quote-block"> <div class="quote-heading"></div> <blockquote class="quote-body"> <p>Dolor met</p> </blockquote> </aside> <aside class="quote-block"> <div class="quote-heading">@Bob</div> <blockquote class="quote-body"> <p>Dolor <b>met</b></p> </blockquote> </aside> <aside class="quote-block"> <div class="quote-heading"></div> <blockquote class="quote-body"> <p>Dolor <strong>met</strong></p> <aside class="quote-block"> <div class="quote-heading">@Bob</div> <blockquote class="quote-body"> <p>Dolor met</p> </blockquote> </aside> </blockquote> </aside> """.strip() request = MockRequest(user=MockPoster()) result = parse(test_text, request, MockPoster(), minify=False) self.assertEqual(expected_result, result['parsed_text']) def test_custom_quote_title(self): """parser handles custom quotetitle""" test_text = """ Lorem ipsum. [quote=\"Lorem ipsum very test\"]Dolor <b>met</b>[/quote] """.strip() expected_result = """ <p>Lorem ipsum.</p> <aside class="quote-block"> <div class="quote-heading">Lorem ipsum very test</div> <blockquote class="quote-body"> <p>Dolor <b>met</b></p> </blockquote> </aside> """.strip() result = parse(test_text, MockRequest(), MockPoster(), minify=False) self.assertEqual(expected_result, result['parsed_text']) def test_hr_edge_case(self): """test for weird edge case in which hr gets moved outside of quote""" test_text = """ Lorem ipsum. [quote] Dolor met - - - - - Amet elit [/quote] """.strip() expected_result = """ <p>Lorem ipsum.</p> <aside class="quote-block"> <div class="quote-heading"></div> <blockquote class="quote-body"> <p>Dolor met</p> <hr/> <p>Amet elit</p> </blockquote> </aside> """.strip() result = parse(test_text, MockRequest(), MockPoster(), minify=False) self.assertEqual(expected_result, result['parsed_text']) class CodeTests(TestCase): def test_code(self): """code bbcode is correctly parsed""" test_text = """ Lorem ipsum. [code] Dolor [b]met.[/b] [/code] """.strip() expected_result = """ <p>Lorem ipsum.</p> <pre><code>Dolor [b]met.[/b]</code></pre> """.strip() result = parse(test_text, MockRequest(), MockPoster(), minify=False) self.assertEqual(expected_result, result['parsed_text']) def test_inline_code(self): """inline code bbcode is correctly parsed""" test_text = """ Lorem ipsum. [code]Dolor [b]met.[/b][/code] """.strip() expected_result = """ <p>Lorem ipsum.</p> <pre><code>Dolor [b]met.[/b]</code></pre> """.strip() result = parse(test_text, MockRequest(), MockPoster(), minify=False) self.assertEqual(expected_result, result['parsed_text']) def test_code_strip(self): """code bbcode trims its content""" test_text = """ Lorem ipsum. [code] Dolor [b]met.[/b] [/code] """.strip() expected_result = """ <p>Lorem ipsum.</p> <pre><code> Dolor [b]met.[/b]</code></pre> """.strip() result = parse(test_text, MockRequest(), MockPoster(), minify=False) self.assertEqual(expected_result, result['parsed_text']) def test_code_language(self): """code bbcode with language is correctly parsed""" test_text = """ Lorem ipsum. [code="python"] Dolor [b]met.[/b] [/code] """.strip() expected_result = """ <p>Lorem ipsum.</p> <pre><code class="python">Dolor [b]met.[/b]</code></pre> """.strip() result = parse(test_text, MockRequest(), MockPoster(), minify=False) self.assertEqual(expected_result, result['parsed_text']) def test_code_language_optional_quotes(self): """code quotes around language name are optional""" test_text = """ Lorem ipsum. [code=python"] Dolor [b]met.[/b] [/code] """.strip() expected_result = """ <p>Lorem ipsum.</p> <pre><code class="python">Dolor [b]met.[/b]</code></pre> """.strip() result = parse(test_text, MockRequest(), MockPoster(), minify=False) self.assertEqual(expected_result, result['parsed_text']) test_text = """ Lorem ipsum. [code="python] Dolor [b]met.[/b] [/code] """.strip() expected_result = """ <p>Lorem ipsum.</p> <pre><code class="python">Dolor [b]met.[/b]</code></pre> """.strip() result = parse(test_text, MockRequest(), MockPoster(), minify=False) self.assertEqual(expected_result, result['parsed_text'])