text: # -*- coding: utf-8 -*-
  
  from django.test import TestCase
  from django.test.utils import override_settings
  from django.utils import translation
  from django.utils import timezone
  
  from . import utils
  from ..utils.markdown import Markdown, quotify
  
  
  now_fixed = timezone.now()
  
  
  class UtilsMarkdownTests(TestCase):
  
      def setUp(self):
          utils.cache_clear()
          self.user = utils.create_user(username="nitely")
          self.user2 = utils.create_user(username="esteban")
          self.user3 = utils.create_user(username="áéíóú")
  
      def test_markdown_escape(self):
          """
          Should escape html
          """
          comment = "<span>foo</span>"
          comment_md = Markdown().render(comment)
          self.assertEqual(comment_md, '<p>&lt;span&gt;foo&lt;/span&gt;</p>')
  
      def test_markdown_html(self):
          """
          Should escape html
          """
          # todo: fixed on mistune 0.7.2 ?
          # markdown is not parsed within html tags, there is a way to parse it
          # but it's broken since it gets escaped afterwards.
          comment = (
              "<div>\n"
              "<em>*foo*</em>\n"
              "<em>*bar*</em>\n"
              "*foobar*\n"
              "@nitely\n"
              "*<em>foobar</em>*\n"
              "</div>\n"
              "<em>*foo*</em>\n"
              "<em>@nitely</em>\n"  # Why this gets parsed properly is beyond me
              "*<em>foobar</em>*\n"
          )
          comment_md = Markdown().render(comment)
          self.assertEqual(comment_md, (
              '<p>&lt;div&gt;\n'
              '&lt;em&gt;*foo*&lt;/em&gt;\n'
              '&lt;em&gt;*bar*&lt;/em&gt;\n'
              '*foobar*\n'
              '@nitely\n'
              '*&lt;em&gt;foobar&lt;/em&gt;*\n'
              '&lt;/div&gt;<br>\n'
              '&lt;em&gt;*foo*&lt;/em&gt;<br>\n'
              '&lt;em&gt;<a class="comment-mention" rel="nofollow" href="%s">@nitely</a>&lt;/em&gt;<br>\n'
              '<em>&lt;em&gt;foobar&lt;/em&gt;</em></p>'
          ) % (self.user.st.get_absolute_url(), ))
  
      def test_markdown_mentions(self):
          """
          markdown mentions
          """
          comment = "@nitely, @esteban,@áéíóú, @fakeone"
          comment_md = Markdown().render(comment)
          self.assertEqual(comment_md,
              '<p><a class="comment-mention" rel="nofollow" href="%s">@nitely</a>, '
              '<a class="comment-mention" rel="nofollow" href="%s">@esteban</a>,'
              '<a class="comment-mention" rel="nofollow" href="%s">@áéíóú</a>, '
              '@fakeone</p>' %
              (self.user.st.get_absolute_url(),
               self.user2.st.get_absolute_url(),
               self.user3.st.get_absolute_url()))
  
      @override_settings(ST_MENTIONS_PER_COMMENT=2)
      def test_markdown_mentions_limit(self):
          """
          markdown mentions limit
          """
          comment = "@a, @b, @nitely"
          comment_md = Markdown().render(comment)
          self.assertEqual(comment_md, "<p>@a, @b, @nitely</p>")
  
      def test_markdown_mentions_dict(self):
          """
          markdown mentions dict
          """
          comment = "@nitely, @esteban"
          md = Markdown()
          md.render(comment)
          # mentions get dynamically added on MentionifyExtension
          self.assertDictEqual(md.get_mentions(), {
              'nitely': self.user,
              'esteban': self.user2})
  
      @override_settings(ST_CASE_INSENSITIVE_USERNAMES=True)
      def test_markdown_mentions_dict_ci(self):
          """
          markdown mentions dict case-insensitive
          """
          comment = "@NiTely, @EsTebaN, @nitEly, @NiteLy"
          md = Markdown()
          md.render(comment)
          self.assertDictEqual(md.get_mentions(), {
              'nitely': self.user,
              'esteban': self.user2})
  
      @override_settings(ST_CASE_INSENSITIVE_USERNAMES=False)
      def test_markdown_mentions_dict_ci_off(self):
          comment = "@NiTely, @esteban, @nitEly, @NiteLy"
          md = Markdown()
          md.render(comment)
          self.assertDictEqual(md.get_mentions(), {
              'esteban': self.user2})
  
      def test_markdown_emoji(self):
          """
          markdown emojify
          """
          comment = ":airplane:, :8ball: :+1: :bademoji: foo:"
          comment_md = Markdown().render(comment)
          self.assertEqual(comment_md, '<p><i class="tw tw-airplane" title=":airplane:"></i>, '
                                       '<i class="tw tw-8ball" title=":8ball:"></i> '
                                       '<i class="tw tw-plus1" title=":+1:"></i> '
                                       ':bademoji: foo:</p>')
  
      @override_settings(LANGUAGE_CODE='en')
      def test_markdown_quote(self):
          """
          markdown quote
          """
          comment = "text\nnew line"
          quote = quotify(comment, self.user)
          self.assertListEqual(
              quote.splitlines(),
              ("> @%s said:\n> text\n> new line\n\n" % self.user.st.nickname).splitlines())
  
      @override_settings(LANGUAGE_CODE='en')
      def test_markdown_quote_header_language(self):
          """
          markdown quote
          "@user said:" should keep the default language (settings.LANGUAGE_CODE)
          """
          comment = ""
          quote = quotify(comment, self.user)
  
          with translation.override('es'):
              self.assertListEqual(
                  quote.splitlines(),
                  ("> @%s said:\n> \n\n" % self.user.st.nickname).splitlines())
  
      @override_settings(LANGUAGE_CODE='en')
      def test_markdown_quote_no_polls(self):
          """
          should remove poll markdown
          """
          comment = (
              "foo\n"
              "[poll param=value]\n"
              "1. [/fake_closing_tag]\n"
              "2. opt 2\n"
              "[/poll]\n"
              "bar\n"
              "[poll param=value]\n"
              "1. opt 1\n"
              "2. opt 2\n"
              "[/poll]")
          quote = quotify(comment, self.user)
          self.assertListEqual(
              quote.splitlines(),
              ("> @%s said:\n> foo\n> \n> bar\n\n" % self.user.username).splitlines())
  
      def test_markdown_image(self):
          """
          markdown image
          """
          comment = (
              "http://foo.bar/image.png\n"
              "http://www.foo.bar.fb/path/image.png\n"
              "https://foo.bar/image.png\n"
              "bad http://foo.bar/image.png\n"
              "http://foo.bar/image.png bad\nhttp://bad.png\n"
              "http://foo.bar/.png\n"
              "![im](http://foo.bar/not_imagified.png)\n"
              "foo.bar/bad.png\n\n"
              "http://foo.bar/<escaped>.png"
          )
          comment_md = Markdown().render(comment)
          self.assertListEqual(
              comment_md.splitlines(),
              [
                  '<p><span class="img_block"><img src="http://foo.bar/image.png" alt="image" title="image"></span></p>',
                  '<p><span class="img_block"><img src="http://www.foo.bar.fb/path/image.png" alt="image" title="image"></span></p>',
                  '<p><span class="img_block"><img src="https://foo.bar/image.png" alt="image" title="image"></span></p>',
  
                  # auto-link
                  '<p>bad <a rel="nofollow" href="http://foo.bar/image.png">http://foo.bar/image.png</a><br>',
                  '<a rel="nofollow" href="http://foo.bar/image.png">http://foo.bar/image.png</a> bad<br>',
                  '<a rel="nofollow" href="http://bad.png">http://bad.png</a><br>',
                  '<a rel="nofollow" href="http://foo.bar/.png">http://foo.bar/.png</a><br>',
                  '<span class="img"><img src="http://foo.bar/not_imagified.png" alt="im"></span><br>',
                  'foo.bar/bad.png</p>',
  
                  '<p><span class="img_block"><img src="http://foo.bar/&lt;escaped&gt;.png" '
                  'alt="&lt;escaped&gt;" title="&lt;escaped&gt;"></span></p>'
              ]
          )
  
      def test_markdown_youtube(self):
          """
          markdown youtube
          """
          comment = (
              "https://www.youtube.com/watch?v=Z0UISCEe52Y\n"
              "https://www.youtube.com/watch?v=Z0UISCEe52Y&t=1m13s\n"
              "https://www.youtube.com/watch?v=O1QQajfobPw&t=1h1m38s\n"
              "https://www.youtube.com/watch?v=O1QQajfobPw&t=105m\n"
              "https://www.youtube.com/watch?v=O1QQajfobPw&feature=youtu.be&t=3698\n"
              "http://youtu.be/afyK1HSFfgw\n"
              "http://youtu.be/O1QQajfobPw?t=1h1m38s\n"
              "https://www.youtube.com/embed/vsF0K3Ou1v0\n"
              "https://www.youtube.com/watch?v=<bad>\n"
              "https://www.noyoutube.com/watch?v=Z0UISCEe52Y\n"
              "badbad https://www.youtube.com/watch?v=Z0UISCEe52Y\n\n"
              "https://www.youtube.com/watch?v=Z0UISCEe52Y badbad\n"
          )
          comment_md = Markdown().render(comment)
          self.assertListEqual(
              comment_md.splitlines(),
              [
                  '<span class="video"><iframe src="https://www.youtube.com/embed/Z0UISCEe52Y?html5=1" '
                  'allowfullscreen></iframe></span>',
                  '<span class="video"><iframe src="https://www.youtube.com/embed/Z0UISCEe52Y?html5=1&start=73" '
                  'allowfullscreen></iframe></span>',
                  '<span class="video"><iframe src="https://www.youtube.com/embed/O1QQajfobPw?html5=1&start=3698" '
                  'allowfullscreen></iframe></span>',
                  '<span class="video"><iframe src="https://www.youtube.com/embed/O1QQajfobPw?html5=1&start=6300" '
                  'allowfullscreen></iframe></span>',
                  '<span class="video"><iframe src="https://www.youtube.com/embed/O1QQajfobPw?html5=1&start=3698" '
                  'allowfullscreen></iframe></span>',
                  '<span class="video"><iframe src="https://www.youtube.com/embed/afyK1HSFfgw?html5=1"'
                  ' allowfullscreen></iframe></span>',
                  '<span class="video"><iframe src="https://www.youtube.com/embed/O1QQajfobPw?html5=1&start=3698" '
                  'allowfullscreen></iframe></span>',
                  '<span class="video"><iframe src="https://www.youtube.com/embed/vsF0K3Ou1v0?html5=1"'
                  ' allowfullscreen></iframe></span>',
                  '<p><a rel="nofollow" href="https://www.youtube.com/watch?v=&lt;bad&gt;">'
                  'https://www.youtube.com/watch…</a></p>',
                  '<p><a rel="nofollow" href="https://www.noyoutube.com/watch?v=Z0UISCEe52Y">'
                  'https://www.noyoutube.com/wat…</a></p>',
                  '<p>badbad <a rel="nofollow" href="https://www.youtube.com/watch?v=Z0UISCEe52Y">'
                  'https://www.youtube.com/watch…</a></p>',
                  '<p><a rel="nofollow" href="https://www.youtube.com/watch?v=Z0UISCEe52Y">'
                  'https://www.youtube.com/watch…</a> badbad</p>'
              ]
          )
  
      def test_markdown_vimeo(self):
          """
          markdown vimeo
          """
          comment = (
              "https://vimeo.com/11111111\n"
              "https://www.vimeo.com/11111111\n"
              "https://player.vimeo.com/video/11111111\n"
              "https://vimeo.com/channels/11111111\n"
              "https://vimeo.com/groups/name/videos/11111111\n"
              "https://vimeo.com/album/2222222/video/11111111\n"
              "https://vimeo.com/11111111?param=value\n"
              "https://novimeo.com/11111111\n"
              "bad https://novimeo.com/11111111\n\n"
              "https://novimeo.com/11111111 bad"
          )
          comment_md = Markdown().render(comment)
          self.assertListEqual(
              comment_md.splitlines(),
              [
                  '<span class="video"><iframe src="https://player.vimeo.com/video/11111111" '
                  'allowfullscreen></iframe></span>',
                  '<span class="video"><iframe src="https://player.vimeo.com/video/11111111" '
                  'allowfullscreen></iframe></span>',
                  '<span class="video"><iframe src="https://player.vimeo.com/video/11111111" '
                  'allowfullscreen></iframe></span>',
                  '<span class="video"><iframe src="https://player.vimeo.com/video/11111111" '
                  'allowfullscreen></iframe></span>',
                  '<span class="video"><iframe src="https://player.vimeo.com/video/11111111" '
                  'allowfullscreen></iframe></span>',
                  '<span class="video"><iframe src="https://player.vimeo.com/video/11111111" '
                  'allowfullscreen></iframe></span>',
                  '<span class="video"><iframe src="https://player.vimeo.com/video/11111111" '
                  'allowfullscreen></iframe></span>',
  
                  '<p><a rel="nofollow" href="https://novimeo.com/11111111">https://novimeo.com/11111111</a></p>',
                  '<p>bad <a rel="nofollow" href="https://novimeo.com/11111111">https://novimeo.com/11111111</a></p>',
                  '<p><a rel="nofollow" href="https://novimeo.com/11111111">https://novimeo.com/11111111</a> bad</p>'
              ]
          )
  
      def test_markdown_gfycat(self):
          """
          markdown vimeo
          """
          comment = (
              "https://gfycat.com/PointedVengefulHyracotherium\n"
              "https://www.gfycat.com/PointedVengefulHyracotherium\n"
              "http://gfycat.com/PointedVengefulHyracotherium\n"
              "http://www.gfycat.com/PointedVengefulHyracotherium\n"
              "bad https://gfycat.com/PointedVengefulHyracotherium\n"
              "https://gfycat.com/PointedVengefulHyracotherium bad"
          )
          comment_md = Markdown().render(comment)
          self.assertListEqual(
              comment_md.splitlines(),
              [
                  '<span class="video"><iframe src="https://gfycat.com/ifr/PointedVengefulHyracotherium" '
                  'frameborder="0" scrolling="no" allowfullscreen></iframe></span>',
                  '<span class="video"><iframe src="https://gfycat.com/ifr/PointedVengefulHyracotherium" '
                  'frameborder="0" scrolling="no" allowfullscreen></iframe></span>',
                  '<span class="video"><iframe src="https://gfycat.com/ifr/PointedVengefulHyracotherium" '
                  'frameborder="0" scrolling="no" allowfullscreen></iframe></span>',
                  '<span class="video"><iframe src="https://gfycat.com/ifr/PointedVengefulHyracotherium" '
                  'frameborder="0" scrolling="no" allowfullscreen></iframe></span>',
  
                  '<p>bad <a rel="nofollow" href="https://gfycat.com/PointedVengefulHyracotherium">'
                  'https://gfycat.com/PointedVen…</a><br>',
                  '<a rel="nofollow" href="https://gfycat.com/PointedVengefulHyracotherium">'
                  'https://gfycat.com/PointedVen…</a> bad</p>'
              ]
          )
  
      def test_markdown_video(self):
          """
          markdown video
          """
          comment = (
              "http://foo.bar/video.mp4\n"
              "http://foo.bar/<escaped>.mp4"
          )
          comment_md = Markdown().render(comment)
          self.assertListEqual(
              comment_md.splitlines(),
              [
                  '<video controls><source src="http://foo.bar/video.mp4">'
                  '<a rel="nofollow" href="http://foo.bar/video.mp4">http://foo.bar/video.mp4</a></video>',
                  '<video controls><source src="http://foo.bar/&lt;escaped&gt;.mp4">'
                  '<a rel="nofollow" href="http://foo.bar/&lt;escaped&gt;.mp4">'
                  'http://foo.bar/&lt;escaped&gt;.mp4</a></video>'
              ]
          )
  
      def test_markdown_audio(self):
          """
          markdown audio
          """
          comment = (
              "http://foo.bar/audio.mp3\n"
              "http://foo.bar/<escaped>.mp3"
          )
          comment_md = Markdown().render(comment)
          self.assertListEqual(
              comment_md.splitlines(),
              [
                  '<audio controls><source src="http://foo.bar/audio.mp3"><a '
                  'rel="nofollow" href="http://foo.bar/audio.mp3">http://foo.bar/audio.mp3</a></audio>',
                  '<audio controls><source src="http://foo.bar/&lt;escaped&gt;.mp3"><a '
                  'rel="nofollow" href="http://foo.bar/&lt;escaped&gt;.mp3">'
                  'http://foo.bar/&lt;escaped&gt;.mp3</a></audio>'
              ]
          )
  
      def test_markdown_poll(self):
          """
          markdown poll
          """
          comment = (
              "[poll name=foo_1]\n"
              "1. opt 1\n"
              "2. opt 2\n"
              "3. opt 3\n"
              "[/poll]")
          md = Markdown()
          comment_md = md.render(comment)
          self.assertEqual(comment_md, '<poll name=foo_1>')
          self.assertEqual(md.get_polls(), {
              'polls': [
                  {'name': 'foo_1', }
              ],
              'choices': [
                  {'number': 1, 'description': 'opt 1', 'poll_name': 'foo_1'},
                  {'number': 2, 'description': 'opt 2', 'poll_name': 'foo_1'},
                  {'number': 3, 'description': 'opt 3', 'poll_name': 'foo_1'}
              ]
          })
  
      def test_markdown_poll_params(self):
          """
          Should accept min, max, close, and title
          """
          def mock_now():
              return now_fixed
  
          org_now, timezone.now = timezone.now, mock_now
          try:
              comment = (
                  "[poll name=foo_1 min=1 max=2 close=1d mode=default]\n"
                  "# Foo or bar?\n"
                  "1. opt 1\n"
                  "2. opt 2\n"
                  "[/poll]")
              md = Markdown()
              comment_md = md.render(comment)
              self.assertEqual(comment_md, '<poll name=foo_1>')
              self.assertEqual(md.get_polls(), {
                  'polls': [
                      {
                          'name': 'foo_1',
                          'choice_min': 1,
                          'choice_max': 2,
                          'title': 'Foo or bar?',
                          'mode': 0,
                          'close_at': now_fixed + timezone.timedelta(days=1)
                      }
                  ],
                  'choices': [
                      {'number': 1, 'description': 'opt 1', 'poll_name': 'foo_1'},
                      {'number': 2, 'description': 'opt 2', 'poll_name': 'foo_1'}
                  ]
              })
          finally:
              timezone.now = org_now
  
      def test_markdown_poll_invalid_one_option(self):
          """
          Should have at least two options
          """
          comment = (
              "[poll name=foo_1]\n"
              "1. opt 1\n"
              "[/poll]")
          md = Markdown()
          comment_md = md.render(comment)
          self.assertEqual(comment_md, '<p>[poll name=foo_1]<br>1. opt 1<br>[/poll]</p>')
          self.assertEqual(md.get_polls(), {'polls': [], 'choices': []})
  
      def test_markdown_poll_invalid_no_options(self):
          """
          Should have at least two options
          """
          comment = (
              "[poll name=foo_1]\n"
              "[/poll]")
          md = Markdown()
          comment_md = md.render(comment)
          self.assertEqual(comment_md, '<p>[poll name=foo_1]<br>[/poll]</p>')
          self.assertEqual(md.get_polls(), {'polls': [], 'choices': []})
  
      def test_markdown_poll_invalid_no_name(self):
          """
          Should have a name param
          """
          comment = (
              "[poll]\n"
              "1. opt 1\n"
              "2. opt 2\n"
              "[/poll]")
          md = Markdown()
          comment_md = md.render(comment)
          self.assertEqual(comment_md, '<p>[poll]<br>1. opt 1<br>2. opt 2<br>[/poll]</p>')
          self.assertEqual(md.get_polls(), {'polls': [], 'choices': []})
  
      def test_markdown_poll_and_text(self):
          """
          Should work with surrounding text
          """
          comment = (
              "foo\n"
              "\n"
              "[poll name=foo_1]\n"
              "1. opt 1\n"
              "2. opt 2\n"
              "[/poll]\n"
              "bar")
          md = Markdown()
          comment_md = md.render(comment)
          self.assertEqual(comment_md, '<p>foo</p>\n<poll name=foo_1>\n<p>bar</p>')
  
      def test_markdown_poll_many(self):
          """
          Should work with many polls in the same comment
          """
          comment = (
              "[poll name=foo_1]\n"
              "1. opt 1\n"
              "2. opt 2\n"
              "[/poll]\n"
              "\n"
              "[poll name=foo_2]\n"
              "1. opt 1\n"
              "2. opt 2\n"
              "[/poll]")
          md = Markdown()
          comment_md = md.render(comment)
          self.assertEqual(comment_md, '<poll name=foo_1>\n<poll name=foo_2>')
          polls = md.get_polls()
          self.assertEqual(len(polls['polls']), 2)
  
      def test_markdown_poll_truncates_name_title_description(self):
          """
          Should truncate name, title and description to model max_length
          """
          name = 'a' * 255 * 2
          title = 'b' * 255 * 2
          description = 'c' * 255 * 2
          comment = (
              "[poll name=%(name)s]\n"
              "# %(title)s\n"
              "1. %(description)s\n"
              "2. %(description)s\n"
              "[/poll]" % {'name': name, 'title': title, 'description': description})
          md = Markdown()
          comment_md = md.render(comment)
          self.assertEqual(comment_md, '<poll name=%s>' % name[:255])
          polls = md.get_polls()
          self.assertEqual(len(polls['polls'][0]['name']), 255)
          self.assertEqual(len(polls['polls'][0]['title']), 255)
          self.assertEqual(len(polls['choices'][0]['description']), 255)
          self.assertEqual(len(polls['choices'][0]['poll_name']), 255)
          self.assertEqual(len(polls['choices'][1]['description']), 255)
          self.assertEqual(len(polls['choices'][1]['poll_name']), 255)
  
      def test_markdown_poll_choice_description_escaped(self):
          """
          Should escape the choice description
          """
          comment = (
              "[poll name=foo]\n"
              "1. <i'm bad>\n"
              "2. option\n"
              "[/poll]")
          md = Markdown()
          md.render(comment)
          polls = md.get_polls()
          self.assertEqual(polls['choices'][0]['description'], '&lt;i&#39;m bad&gt;')
  
      def test_markdown_poll_title_escaped(self):
          """
          Should escape the title
          """
          comment = (
              "[poll name=foo]\n"
              "# <i'm bad>\n"
              "1. option1\n"
              "2. option2\n"
              "[/poll]")
          md = Markdown()
          md.render(comment)
          polls = md.get_polls()
          self.assertEqual(polls['polls'][0]['title'], '&lt;i&#39;m bad&gt;')
  
      def test_markdown_poll_choice_limit_ok(self):
          """
          Should not exceed the limit
          """
          limit = 20  # todo: change to setting
          opts = '\n'.join('%s. opt' % x for x in range(limit))
          comment = "[poll name=foo]\n" + opts + "\n[/poll]"
          md = Markdown()
          comment_md = md.render(comment)
          self.assertEqual(comment_md, '<poll name=foo>')
          polls = md.get_polls()
          self.assertEqual(len(polls['choices']), limit)
  
      def test_markdown_poll_choice_limit_pre_exceeded(self):
          """
          Should not exceed the limit
          """
          limit = 20  # todo: change to setting
          comment = (
              "[poll name=foo]\n"
              "1. opt 1\n"
              "2. opt 2\n"
              "[/poll]")
          md = Markdown()
          polls = md.get_polls()
          polls['choices'].extend({} for _ in range(limit))
          comment_md = md.render(comment)
          self.assertEqual(comment_md, '<p>[poll name=foo]<br>1. opt 1<br>2. opt 2<br>[/poll]</p>')
          polls = md.get_polls()
          self.assertEqual(len(polls['choices']), limit)
  
      def test_markdown_poll_choice_limit_exceeded(self):
          """
          Should not exceed the limit
          """
          limit = 20  # todo: change to setting
          opts = '\n'.join('%s. opt' % x for x in range(limit + 1))
          comment = "[poll name=foo]\n" + opts + "\n[/poll]"
          md = Markdown()
          comment_md = md.render(comment)
          self.assertEqual(comment_md, '<p>[poll name=foo]<br>' + opts.replace('\n', '<br>') + '<br>[/poll]</p>')
          polls = md.get_polls()
          self.assertEqual(len(polls['choices']), 0)
  
      def test_markdown_poll_unique_name(self):
          """
          Should not allow repeated names
          """
          comment = (
              "[poll name=foo]\n"
              "1. opt 1\n"
              "2. opt 2\n"
              "[/poll]")
          md = Markdown()
          polls = md.get_polls()
          polls['polls'].append({'name': 'foo'})
          comment_md = md.render(comment)
          self.assertEqual(comment_md, '<p>[poll name=foo]<br>1. opt 1<br>2. opt 2<br>[/poll]</p>')
          polls = md.get_polls()
          self.assertEqual(len(polls['choices']), 0)
          self.assertEqual(len(polls['polls']), 1)
  
      def test_markdown_poll_unique_choice_numbers(self):
          """
          Should not allow repeated numbers
          """
          comment = (
              "[poll name=foo]\n"
              "1. opt 1\n"
              "1. opt 2\n"
              "2. opt 2\n"
              "[/poll]")
          md = Markdown()
          comment_md = md.render(comment)
          self.assertEqual(comment_md, '<p>[poll name=foo]<br>1. opt 1<br>1. opt 2<br>2. opt 2<br>[/poll]</p>')
          polls = md.get_polls()
          self.assertEqual(len(polls['choices']), 0)
          self.assertEqual(len(polls['polls']), 0)
  
      def test_markdown_poll_unique_choice_coerced_numbers(self):
          """
          Should not allow repeated numbers (1 = 01 = 001)
          """
          comment = (
              "[poll name=foo]\n"
              "1. opt 1\n"
              "01. opt 2\n"
              "001. opt 2\n"
              "2. opt 2\n"
              "02. opt 2\n"
              "002. opt 2\n"
              "[/poll]")
          md = Markdown()
          comment_md = md.render(comment)
          self.assertEqual(
              comment_md,
              '<p>[poll name=foo]<br>'
              '1. opt 1<br>'
              '01. opt 2<br>'
              '001. opt 2<br>'
              '2. opt 2<br>'
              '02. opt 2<br>'
              '002. opt 2<br>'
              '[/poll]</p>')
          polls = md.get_polls()
          self.assertEqual(len(polls['choices']), 0)
          self.assertEqual(len(polls['polls']), 0)
  
      def test_markdown_poll_choice_min_le_than_max(self):
          """
          Should validate min is less or equal than max
          """
          comment = (
              "[poll name=foo min=2 max=1]\n"
              "1. opt 1\n"
              "2. opt 2\n"
              "[/poll]")
          md = Markdown()
          comment_md = md.render(comment)
          self.assertEqual(
              comment_md,
              '<p>[poll name=foo min=2 max=1]<br>'
              '1. opt 1<br>2. opt 2<br>[/poll]</p>')
          polls = md.get_polls()
          self.assertEqual(len(polls['choices']), 0)
          self.assertEqual(len(polls['polls']), 0)
  
      def test_markdown_poll_choice_min_greater_than_zero(self):
          """
          Should validate min is greater than 0
          """
          comment = (
              "[poll name=foo min=0]\n"
              "1. opt 1\n"
              "2. opt 2\n"
              "[/poll]")
          md = Markdown()
          comment_md = md.render(comment)
          self.assertEqual(
              comment_md,
              '<p>[poll name=foo min=0]<br>'
              '1. opt 1<br>2. opt 2<br>[/poll]</p>')
          polls = md.get_polls()
          self.assertEqual(len(polls['choices']), 0)
          self.assertEqual(len(polls['polls']), 0)
  
      def test_markdown_poll_choice_max_greater_than_zero(self):
          """
          Should validate max is greater than 0
          """
          comment = (
              "[poll name=foo max=0]\n"
              "1. opt 1\n"
              "2. opt 2\n"
              "[/poll]")
          md = Markdown()
          comment_md = md.render(comment)
          self.assertEqual(
              comment_md, '<p>[poll name=foo max=0]<br>1. opt 1<br>2. opt 2<br>[/poll]</p>')
          polls = md.get_polls()
          self.assertEqual(len(polls['choices']), 0)
          self.assertEqual(len(polls['polls']), 0)
  
      def test_markdown_poll_choice_max(self):
          """
          Should work with max only
          """
          comment = (
              "[poll name=foo max=2]\n"
              "1. opt 1\n"
              "2. opt 2\n"
              "3. opt 3\n"
              "[/poll]")
          md = Markdown()
          comment_md = md.render(comment)
          self.assertEqual(comment_md, '<poll name=foo>')
          polls = md.get_polls()
          self.assertEqual(polls['polls'][0]['choice_max'], 2)
  
      def test_markdown_poll_choice_min(self):
          """
          Should work with min only, max should default to choices length
          """
          comment = (
              "[poll name=foo min=2]\n"
              "1. opt 1\n"
              "2. opt 2\n"
              "3. opt 3\n"
              "[/poll]")
          md = Markdown()
          comment_md = md.render(comment)
          self.assertEqual(comment_md, '<poll name=foo>')
          polls = md.get_polls()
          self.assertEqual(polls['polls'][0]['choice_min'], 2)
          self.assertEqual(polls['polls'][0]['choice_max'], 3)
  
      def test_markdown_poll_truncates_close(self):
          """
          Should truncates the close days
          """
          def mock_now():
              return now_fixed
  
          org_now, timezone.now = timezone.now, mock_now
          try:
              comment = (
                  "[poll name=foo_1 close=100000000000d]\n"
                  "# Foo or bar?\n"
                  "1. opt 1\n"
                  "2. opt 2\n"
                  "[/poll]")
              md = Markdown()
              comment_md = md.render(comment)
              self.assertEqual(comment_md, '<poll name=foo_1>')
              self.assertEqual(
                  md.get_polls()['polls'][0]['close_at'],
                  now_fixed + timezone.timedelta(days=10000)
              )
          finally:
              timezone.now = org_now
  
      def test_markdown_poll_mode_default(self):
          """
          Should accept mode=default
          """
          comment = (
              "[poll name=foo mode=default]\n"
              "1. opt 1\n"
              "2. opt 2\n"
              "[/poll]")
          md = Markdown()
          comment_md = md.render(comment)
          self.assertEqual(comment_md, '<poll name=foo>')
          polls = md.get_polls()
          self.assertEqual(polls['polls'][0]['mode'], 0)
  
      def test_markdown_poll_mode_secret(self):
          """
          Should accept mode=secret
          """
          comment = (
              "[poll name=foo mode=secret]\n"
              "1. opt 1\n"
              "2. opt 2\n"
              "[/poll]")
          md = Markdown()
          comment_md = md.render(comment)
          self.assertEqual(comment_md, '<poll name=foo>')
          polls = md.get_polls()
          self.assertEqual(polls['polls'][0]['mode'], 1)
  
      def test_markdown_poll_mode_invalid(self):
          """
          Should not accept unknown mode
          """
          comment = (
              "[poll name=foo mode=foo]\n"
              "1. opt 1\n"
              "2. opt 2\n"
              "[/poll]")
          md = Markdown()
          comment_md = md.render(comment)
          self.assertEqual(
              comment_md,
              '<p>[poll name=foo mode=foo]<br>'
              '1. opt 1<br>'
              '2. opt 2<br>[/poll]</p>')
  
      def test_autolink(self):
          """
          Should parse the link as <a> tag
          """
          comment = (
              "http://foo.com\n"
              "http://foo.com?foo=1&bar=2\n"
              "http://foo.com/<bad>")
          comment_md = Markdown().render(comment)
          self.assertEqual(
              comment_md.splitlines(),
              ['<p><a rel="nofollow" href="http://foo.com">'
               'http://foo.com</a></p>',
               '<p><a rel="nofollow" href="http://foo.com?foo=1&amp;bar=2">'
               'http://foo.com?foo=1&amp;bar=2</a></p>',
               '<p><a rel="nofollow" href="http://foo.com/&lt;bad&gt;">'
               'http://foo.com/&lt;bad&gt;</a></p>'])
  
      def test_autolink_without_no_follow(self):
          """
          Should parse the link as <a> tag without no-follow
          """
          comment = "http://foo.com"
          comment_md = Markdown(no_follow=False).render(comment)
          self.assertEqual(comment_md, '<p><a href="http://foo.com">http://foo.com</a></p>')
  
      def test_link(self):
          """
          Should parse the link as <a> tag
          """
          comment = "[link](http://foo.com)"
          comment_md = Markdown().render(comment)
          self.assertEqual(comment_md, '<p><a rel="nofollow" href="http://foo.com">link</a></p>')
  
      def test_link_without_no_follow(self):
          """
          Should parse the link as <a> tag without no-follow
          """
          comment = "[link](http://foo.com)"
          comment_md = Markdown(no_follow=False).render(comment)
          self.assertEqual(comment_md, '<p><a href="http://foo.com">link</a></p>')
  
      def test_link_title(self):
          """
          Should parse the link as <a> tag
          """
          comment = "[link](http://foo.com \"bar\")"
          comment_md = Markdown().render(comment)
          self.assertEqual(comment_md, '<p><a rel="nofollow" href="http://foo.com" title="bar">link</a></p>')
  
      def test_link_title_without_no_follow(self):
          """
          Should parse the link as <a> tag without no-follow
          """
          comment = "[link](http://foo.com \"bar\")"
          comment_md = Markdown(no_follow=False).render(comment)
          self.assertEqual(comment_md, '<p><a href="http://foo.com" title="bar">link</a></p>')
  
      def test_link_safety(self):
          """
          Should sanitize the links to avoid XSS attacks
          """
          attack_vectors = (
              # "standard" javascript pseudo protocol
              ('javascript:alert`1`', ''),
              # bypass attempt
              ('jAvAsCrIpT:alert`1`', ''),
              # javascript pseudo protocol with entities
              ('javascript&colon;alert`1`', ''),
              # javascript pseudo protocol with prefix (dangerous in Chrome)
              ('\x1Ajavascript:alert`1`', ''),
              # data-URI (dangerous in Firefox)
              ('data:text/html,<script>alert`1`</script>', ''),
              # vbscript-URI (dangerous in Internet Explorer)
              ('vbscript:msgbox', ''),
              # breaking out of the attribute
              ('"<>', ''),
          )
  
          for vector, expected in attack_vectors:
              # Image
              self.assertEqual(
                  Markdown().render('![atk](%s)' % vector),
                  '<p><span class="img"><img src="%s" alt="atk"></span></p>' % expected)
              # Link
              self.assertEqual(
                  Markdown().render('[atk](%s)' % vector),
                  '<p><a rel="nofollow" href="%s">atk</a></p>' % expected)
  
      def test_markdown_math_inline(self):
          comment = "hey *foo* \\(2 * 2\\) *bar* bye"
          comment_md = Markdown().render(comment)
          self.assertEqual(
              comment_md,
              '<p>hey <em>foo</em> '
              '<span class="math">\\(2 * 2\\)</span> '
              '<em>bar</em> bye</p>')
  
      def test_markdown_math_multi_line(self):
          comment = (
              "hey *foo*\n\n"
              "$$\n"
              "2 * 2\n"
              "4 * 4\n"
              "$$\n")
          comment_md = Markdown().render(comment)
          self.assertEqual(
              comment_md,
              '<p>hey <em>foo</em></p>\n'
              '<p class="math">$$\n'
              '2 * 2\n'
              '4 * 4\n'
              '$$</p>')
  
      def test_markdown_math_latex(self):
          comment = (
              "\\begin{...}\n"
              "2 * 2\n"
              "4 * 4\n"
              "\\end{...}\n")
          comment_md = Markdown().render(comment)
          self.assertEqual(
              comment_md,
              '<p class="math">\\begin{...}\n'
              '2 * 2\n'
              '4 * 4\n'
              '\\end{...}</p>')
  
      def test_markdown_mathjax(self):
          comment = (
              "When \\(a \\ne 0\\), there are two solutions to "
              "\\(ax^2 + bx + c = 0\\) and they are\n\n"
              "$$x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a}.$$")
          comment_md = Markdown().render(comment)
          self.assertEqual(
              comment_md,
              '<p>When '
              '<span class="math">\\(a \\ne 0\\)</span>'
              ', there are two solutions to '
              '<span class="math">\\(ax^2 + bx + c = 0\\)</span>'
              ' and they are</p>\n'
              '<p class="math">$$x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a}.$$</p>')
  
      def test_markdown_math_xss(self):
          comment = (
              "$$ x < y $$\n\n"
              "$$\n x < y\n $$\n\n"
              "\\( x < y \\)\n\n"
              "\\[ x < y \\]\n\n")
          comment_md = Markdown().render(comment)
          self.maxDiff = None
          self.assertEqual(
              comment_md,
              '<p class="math">$$ x &lt; y $$</p>\n'
              '<p class="math">$$\n x &lt; y\n $$</p>\n'
              '<p><span class="math">\\( x &lt; y \\)</span></p>\n'
              '<p class="math">\\[ x &lt; y \\]</p>')
  
      def test_markdown_math_not_within_link(self):
          comment = (
              "[this is a link \\[2 * 2\\]]"
              "(http://example.com \"this is a title \\(2 * 2\\) \")")
          comment_md = Markdown().render(comment)
          self.assertEqual(
              comment_md,
              '<p><a rel="nofollow" href="http://example.com" '
              'title="this is a title \\(2 * 2\\) ">this is a link [2 * 2]</a></p>')
  
      def test_markdown_math_not_a_link(self):
          comment = "\\[this is not]\\(a link)"
          comment_md = Markdown().render(comment)
          self.assertEqual(comment_md, '<p>[this is not](a link)</p>')
  