Fabian Büchler avatar Fabian Büchler committed fb4eaca

More tests for MarkupMirrorField.

Comments (0)

Files changed (2)

tests/tests/fields.py

+import textwrap
+
+from django.core import serializers
+from django.core.exceptions import ImproperlyConfigured
 from django.test import TestCase
 
 from markupmirror.fields import Markup
 from markupmirror.fields import MarkupMirrorField
-from markupmirror.fields import MarkupMirrorFieldDescriptor
-from markupmirror.widgets import MarkupMirrorTextarea
-from markupmirror.widgets import AdminMarkupMirrorTextareaWidget
+from markupmirror.markup.base import markup_pool
 
-from tests.models import Post, Article, Abstract, Concrete
+from tests.models import Post, Concrete
 
 
 class MarkupMirrorFieldTests(TestCase):
     """Tests the ``markupmirror.fields.MarkupMirrorField`` implementation."""
 
     def setUp(self):
-        self.mp = Post(title='example markdown post',
-                       body='**markdown**',
-                       body_markup_type='markdown')
+        """Creates three ``Post`` objects with different field settings."""
+
+        # Post with Markdown field
+        self.mp = Post(title="example Markdown post",
+                       body="**markdown**", body_markup_type='markdown')
+        self.mp.save()
+
+        # Post with reStructuredText field
+        self.rp = Post(title="example reStructuredText post",
+                       body="*reST*", body_markup_type='restructuredtext')
+        self.rp.save()
+
+        # Post being attacked
+        self.xss_str = "<script>alert('xss');</script>"
+        self.xss_post = Post(title="example XSS post",
+                             body=self.xss_str, body_markup_type='markdown',
+                             comment=self.xss_str)
+        self.xss_post.save()
 
     def test_verbose_name(self):
         """Tests that the standard field property ``verbose_name`` works."""
         self.assertEqual(self.mp._meta.get_field('body').verbose_name,
-                         'post body')
+                         "post body")
+
+    def test_markup_body(self):
+        """Tests the three accessors ``raw``, ``rendered`` and ``markup_type``
+        of the ``Markup`` content wrapper class.
+
+        """
+        self.assertEquals(self.mp.body.raw, "**markdown**")
+        self.assertEquals(self.mp.body.rendered,
+                          "<p><strong>markdown</strong></p>")
+        self.assertEquals(self.mp.body.markup_type, "markdown")
+
+    def test_markup_unicode(self):
+        """Converting ``Markup`` to unicode uses the ``Markup.rendered``
+        accessor internally.
+
+        """
+        self.assertEqual(
+            unicode(self.rp.body.rendered), textwrap.dedent(u"""\
+            <div class="document">
+            <p><em>reST</em></p>
+            </div>
+            """))
+
+    def test_from_database(self):
+        """Test that data loads back from the database correctly and 'post'
+        has the right type.
+
+        """
+        post1 = Post.objects.get(pk=self.mp.pk)
+        self.assert_(isinstance(post1.body, Markup))
+        self.assertEqual(unicode(post1.body),
+                         u"<p><strong>markdown</strong></p>")
+
+    def test_body_assignment(self):
+        """Setting the field's value works through the descriptor's setter
+        (``MarkupMirrorFieldDescriptor.__set__``) and accepts both strings
+        and ``Markup`` instances.
+
+        """
+        self.rp.body = "**reST**"
+        self.rp.save()
+        self.assertEquals(unicode(self.rp.body),
+            unicode(self.rp.body.rendered), textwrap.dedent(u"""\
+            <div class="document">
+            <p><strong>reST</strong></p>
+            </div>
+            """))
+
+        rest_markup = Markup(self.rp, 'body',
+                             'body_rendered', 'body_markup_type')
+        rest_markup.raw = "*reST*"
+        self.rp.body = rest_markup
+        self.assertEquals(unicode(self.rp.body),
+            unicode(self.rp.body.rendered), textwrap.dedent(u"""\
+            <div class="document">
+            <p><em>reST</em></p>
+            </div>
+            """))
+
+    def test_raw_assignment(self):
+        """Setting the ``Markup.raw`` property modifies the field's value."""
+
+        self.rp.body.raw = '*more reST*'
+        self.rp.save()
+        self.assertEquals(unicode(self.rp.body),
+            unicode(self.rp.body.rendered), textwrap.dedent(u"""\
+            <div class="document">
+            <p><em>more reST</em></p>
+            </div>
+            """))
+
+    def test_rendered_assignment(self):
+        """The ``Markup.rendered`` property dos not have a setter."""
+
+        def set_rendered(text):
+            self.rp.body.rendered = text
+
+        self.assertRaises(AttributeError, set_rendered, "fail!")
+
+    def test_body_type_assignment(self):
+        """The markup type can be changed using the ``Markup.markup_type``
+        property.
+
+        """
+        self.rp.body.markup_type = 'markdown'
+        self.rp.save()
+        self.assertEquals(self.rp.body.markup_type, 'markdown')
+        self.assertEquals(unicode(self.rp.body),
+                          "<p><em>reST</em></p>")
+
+    def test_serialize_to_json(self):
+        """Serializing a ``Post`` with a ``MarkupMirrorField`` works."""
+        stream = serializers.serialize('json', Post.objects.all())
+        self.assertEqual(stream, '[{'
+            '"pk": 1, "model": "tests.post", "fields": {'
+                '"body": "**markdown**", '
+                '"comment": "", '
+                '"title": "example Markdown post", '
+                '"comment_rendered": "", '
+                '"comment_markup_type": "markdown", '
+                '"body_rendered": "<p><strong>markdown</strong></p>", '
+                '"body_markup_type": "markdown"'
+            '}}, {'
+            '"pk": 2, "model": "tests.post", "fields": {'
+                '"body": "*reST*", '
+                '"comment": "", '
+                '"title": "example reStructuredText post", '
+                '"comment_rendered": "", '
+                '"comment_markup_type": "markdown", '
+                '"body_rendered": '
+                    '"<div class=\\"document\\">\\n'
+                        '<p><em>reST</em></p>\\n</div>\\n", '
+                '"body_markup_type": "restructuredtext"'
+            '}}, {'
+                '"pk": 3, "model": "tests.post", "fields": {'
+                    '"body": "<script>alert(\'xss\');</script>", '
+                    '"comment": "<script>alert(\'xss\');</script>", '
+                    '"title": "example XSS post", '
+                    '"comment_rendered": '
+                        '"<p>&lt;script&gt;'
+                            'alert(&#39;xss&#39;);&lt;/script&gt;</p>", '
+                    '"comment_markup_type": "markdown", '
+                    '"body_rendered": "<script>alert(\'xss\');</script>", '
+                    '"body_markup_type": "markdown"'
+            '}}'
+        ']')
+
+    def test_deserialize_json(self):
+        """Tests that objects with ``MarkupMirrorFields`` can be deserialized
+        correctly.
+
+        """
+        stream = serializers.serialize('json', Post.objects.all())
+        obj = list(serializers.deserialize('json', stream))[0]
+        self.assertEquals(obj.object, self.mp)
+
+    def test_escape_html(self):
+        """Rendered content should be escaped to prevent XSS attacks."""
+        self.assertEquals(self.xss_post.comment.raw, self.xss_str)
+        self.assertEquals(
+            unicode(self.xss_post.comment.rendered),
+            u'<p>&lt;script&gt;alert(&#39;xss&#39;);&lt;/script&gt;</p>')
+
+    def test_escape_html_false(self):
+        """The ``MarkupMirrorField.escape_html`` prevents this escaping."""
+        self.assertEquals(self.xss_post.body.raw, self.xss_str)
+        self.assertEquals(unicode(self.xss_post.body.rendered), self.xss_str)
+
+    def test_inheritance(self):
+        """Abstract base models inherit the ``MarkupMirrorField`` to the
+        concrete subclasses.
+
+        """
+        concrete_fields = [f.name for f in Concrete._meta.fields]
+        self.assertEquals(
+            concrete_fields,
+            ['id', 'content', 'content_markup_type', 'content_rendered'])
+
+    def test_markup_type_validation(self):
+        """Invalid markup types are rejected."""
+        self.assertRaises(ImproperlyConfigured, MarkupMirrorField,
+            'verbose name', 'markup_field', 'bad_markup_type')
+
+    def test_default_markup_types(self):
+        """Per default the markup types plaintext, html are available.
+        Depending on available third-party products, markdown,
+        restructuredtext and textile are also in the markup pool.
+
+        """
+        markups = markup_pool.markups
+        for markup_type, markup in markups.items():
+            rendered = markup(u"test")
+            self.assertTrue(hasattr(rendered, '__str__'))
 
 
 __all__ = ('MarkupMirrorFieldTests',)

tests/tests/version.py

         markupmirror.VERSION_INFO['serial'] = '1'
         self.assertRaises(AssertionError, markupmirror.get_version)
 
-
     def test_invalid_major_minor_micro(self):
         """``VERSION_INFO['major|minor|micro']`` must be integers."""
         # invalid major
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.