Commits

Fabian Büchler committed a199259

Improved test setup with nose (and django-nose) and added some more coverage.

Comments (0)

Files changed (39)

 *.EGG
 *.EGG-INFO
 .tox
+.coverage
+.noseids
 
 syntax: regexp
 

markupmirror/__init__.py

     """Concatenates ``VERSION_INFO`` to dotted version string."""
     assert len(VERSION_INFO) == 5
     assert VERSION_INFO['sub'] in ('alpha', 'beta', 'candidate', 'final')
+    assert VERSION_INFO['serial'] >= 1
+    assert isinstance(VERSION_INFO['major'], int)
+    assert isinstance(VERSION_INFO['minor'], int)
+    assert isinstance(VERSION_INFO['micro'], int)
+    assert isinstance(VERSION_INFO['serial'], int)
 
     version = "%(major)s.%(minor)s" % VERSION_INFO
-    # append micro version only if not short and micro != 0
-    if not short and VERSION_INFO['micro']:
-        version += ".%(micro)s" % VERSION_INFO
-    # append sub (pre-release) version and number
-    if VERSION_INFO['sub'] != 'final':
-        version += "%(sub)s%(serial)s" % VERSION_INFO
+    if not short:
+        # append micro version only if micro != 0
+        if VERSION_INFO['micro']:
+            version += ".%(micro)s" % VERSION_INFO
+        # append sub (pre-release) version and number
+        if VERSION_INFO['sub'] != 'final':
+            version += "%(sub)s%(serial)s" % {
+                'sub': VERSION_INFO['sub'][0],
+                'serial': VERSION_INFO['serial'],
+            }
     return version
 
 

markupmirror/tests/__init__.py

Empty file removed.

markupmirror/tests/media/.keep

Empty file removed.

markupmirror/tests/models.py

-from django.db import models
-
-from markupmirror.fields import MarkupMirrorField
-
-
-class Post(models.Model):
-    title = models.CharField(max_length=50)
-    body = MarkupMirrorField('post body')
-    comment = MarkupMirrorField(
-        escape_html=True, default_markup_type='markdown')
-
-    def __unicode__(self):
-        return self.title
-
-
-class Article(models.Model):
-    normal_field = MarkupMirrorField()
-    default_field = MarkupMirrorField(default_markup_type='markdown')
-    markdown_field = MarkupMirrorField(markup_type='markdown')
-
-
-class Abstract(models.Model):
-    content = MarkupMirrorField()
-
-    class Meta:
-        abstract = True
-
-
-class Concrete(Abstract):
-    pass

markupmirror/tests/requirements.txt

-coverage == 3.5.1
-django-coverage == 1.2.2
-docutils == 0.8.1
-ipython == 0.12
-ipdb == 0.6.1
-FeinCMS == 1.5.3
-Markdown == 2.1.1
-nose == 1.1.2
-pep8 == 1.0
-Sphinx == 1.1.3
-textile == 2.1.5

markupmirror/tests/settings.py

-"""Test settigs for django-markupmirror."""
-
-import os
-
-
-TESTS_PATH = os.path.abspath(os.path.dirname(__file__))
-
-
-def tests_path_to(*parts):
-    """Returns absolute path for ``parts`` relative to ``TESTS_PATH``."""
-    return os.path.abspath(os.path.join(TESTS_PATH, *parts))
-
-
-DEBUG = True
-TEMPLATE_DEBUG = DEBUG
-
-INSTALLED_APPS = (
-    'markupmirror',
-    'markupmirror.feincms',
-    'markupmirror.tests',
-)
-
-ROOT_URLCONF = 'tests.urls'
-
-DATABASES = {
-    'default': {
-        'ENGINE': 'django.db.backends.sqlite3',
-        'NAME': 'markupmirror.db',
-    }
-}
-
-CACHES = {
-    'default': {
-        'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
-        'LOCATION': 'markupmirror-tests',
-        'KEY_PREFIX': 'markupmirror-tests',
-        'TIMEOUT': 300,
-    }
-}
-
-MEDIA_ROOT = tests_path_to('media')
-MEDIA_URL = '/media/'
-STATIC_ROOT = tests_path_to('static')
-STATIC_URL = '/media/'
-
-USE_TZ = True
-
-LOGGING = {
-    'version': 1,
-    'disable_existing_loggers': True,
-    'handlers': {
-        'simple': {
-            'level': 'ERROR',
-            'class': 'logging.StreamHandler',
-        }
-    },
-    'loggers': {
-        'django.request': {
-            'handlers': ['simple'],
-            'level': 'ERROR',
-            'propagate': False,
-        },
-    }
-}
-
-
-# ### coverage / django-coverage
-
-INSTALLED_APPS += (
-    'django_coverage',
-)
-
-COVERAGE_ADDITIONAL_MODULES = [
-    'markupmirror',
-]
-
-COVERAGE_PATH_EXCLUDES = [
-    r'.hg',
-    r'bin',
-    r'etc',
-    r'fixtures',
-    r'media',
-    r'static',
-    r'templates',
-]
-
-COVERAGE_CODE_EXCLUDES = [
-    'def __unicode__\(self\):',
-    'def get_absolute_url\(self\):',
-    'from .* import .*', 'import .*',
-    'except ImportError:',
-]
-
-COVERAGE_REPORT_HTML_OUTPUT_DIR = tests_path_to(
-    os.path.pardir, os.path.pardir, 'docs', '_coverage')

markupmirror/tests/static/.keep

Empty file removed.

markupmirror/tests/tests/__init__.py

-from markupmirror.tests.tests.fields import *
-from markupmirror.tests.tests.markup_base import *
-from markupmirror.tests.tests.markup_html import *
-from markupmirror.tests.tests.markup_markdown import *
-from markupmirror.tests.tests.markup_plaintext import *
-from markupmirror.tests.tests.markup_restructuredtext import *
-from markupmirror.tests.tests.markup_textile import *
-from markupmirror.tests.tests.widgets import *

markupmirror/tests/tests/fields.py

-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.tests.models import Post, Article, Abstract, 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')
-
-    def test_verbose_name(self):
-        self.assertEqual(self.mp._meta.get_field('body').verbose_name,
-                         'post body')
-
-
-__all__ = ('MarkupMirrorFieldTests',)

markupmirror/tests/tests/markup_base.py

-from django.test import TestCase
-
-from markupmirror.exceptions import InvalidMarkup
-from markupmirror.markup.base import BaseMarkup
-from markupmirror.markup.base import markup_pool
-from markupmirror.markup.base import register_markup
-
-
-class DummyMarkup(BaseMarkup):
-    pass
-
-
-class BaseMarkupTests(TestCase):
-    """Tests the ``markupmirror.markup.base.BaseMarkup`` class that acts as
-    a base class for markup converters.
-
-    """
-    def test_name(self):
-        """Tests ``BaseMarkup.get_name``."""
-
-        self.assertEqual(BaseMarkup.get_name(), 'base')
-        self.assertEqual(DummyMarkup.get_name(), 'dummy')
-
-    def test_convert_markup(self):
-        """Tests that the order of the three convert methods
-        ``before_convert``, ``convert`` and ``after_convert`` is kept
-        correctly.
-
-        """
-        class DummyMarkup(BaseMarkup):
-
-            def before_convert(self, markup):
-                return markup.replace("1", "2", 1)
-
-            def convert(self, markup):
-                return markup.replace("2", "3", 1)
-
-            def after_convert(self, markup):
-                return markup.replace("3", "4", 1)
-
-        dummy_markup = DummyMarkup()
-
-        self.assertEqual(dummy_markup.before_convert("1"), "2")
-        self.assertEqual(dummy_markup.convert("2"), "3")
-        self.assertEqual(dummy_markup.after_convert("3"), "4")
-        # test order
-        self.assertEqual(dummy_markup("1"), "4")
-
-    def test_base_convert(self):
-        """The ``BaseMarkup`` converter does not do anything."""
-        bm = BaseMarkup()
-        self.assertEqual(bm.before_convert("markup"), "markup")
-        self.assertEqual(bm.convert("markup"), "markup")
-        self.assertEqual(bm.after_convert("markup"), "markup")
-
-
-class MarkupPoolTests(TestCase):
-    """Tests the ``markupmirror.markup.base.MarkupPool``."""
-
-    def tearDown(self):
-        markup_pool.unregister_markup('dummy')
-
-    def test_register_invalid(self):
-        """Registering a markup class which does not subclass ``BaseMarkup``
-        raises an ``InvalidMarkup`` exception.
-
-        """
-        class InvalidMarkupClass(object):
-            pass
-
-        self.assertRaises(InvalidMarkup, register_markup, InvalidMarkupClass)
-
-    def test_re_register(self):
-        """Registering a markup converter would overwrite it.
-
-        """
-        register_markup(DummyMarkup)
-        dummy_markup = markup_pool['dummy']
-        register_markup(DummyMarkup)
-        self.assertTrue(isinstance(markup_pool['dummy'], DummyMarkup))
-        self.assertFalse(dummy_markup is markup_pool['dummy'])
-
-    def test_register(self):
-        """Registering a markup converter makes it available through its name.
-
-        """
-        # before the markup is registered, we'll get ``KeyError`` if
-        # we try to retrieve it.
-        self.assertRaises(KeyError, markup_pool.get_markup, 'dummy')
-
-        # it is available after registering it
-        register_markup(DummyMarkup)
-        self.assertTrue(isinstance(markup_pool['dummy'], DummyMarkup))
-
-    def test_unregister(self):
-        """Unregistering a markup converter removes it from the pool."""
-        register_markup(DummyMarkup)
-        self.assertTrue(isinstance(markup_pool['dummy'], DummyMarkup))
-        del markup_pool['dummy']
-        self.assertRaises(KeyError, markup_pool.get_markup, 'dummy')
-
-    def test_get_all(self):
-        """``markup_pool.get_all_markups`` returns all markup converters."""
-        all_markups = markup_pool.markups
-        self.assertEqual(
-            ['html', 'markdown', 'plaintext', 'restructuredtext', 'textile'],
-            sorted(all_markups.keys()))
-
-
-__all__ = ('BaseMarkupTests', 'MarkupPoolTests')

markupmirror/tests/tests/markup_html.py

-from django.test import TestCase
-
-from markupmirror.markup.html import HtmlMarkup
-
-MARKUP = u"""\
-<h1>A First Level Header</h1>
-
-<h2>A Second Level Header</h2>
-
-<p>Now is the time for all good men to come to the aid of their country.<br />
-This is just a regular paragraph.</p>
-
-<p>The quick brown fox jumped over the lazy dog's back.</p>
-
-<h3>Header 3</h3>
-
-<blockquote>
-    <p>This is a blockquote.</p>
-    <p>This is the second paragraph in the blockquote.</p>
-</blockquote>
-"""
-
-
-class HTMLMarkupTests(TestCase):
-    """Tests the ``markupmirror.markup.html.HtmlMarkup`` class that
-    passes through plain HTML content.
-
-    """
-    def test_convert(self):
-        html_markup = HtmlMarkup()
-        self.assertHTMLEqual(html_markup(MARKUP), MARKUP)
-
-
-__all__ = ('HTMLMarkupTests',)

markupmirror/tests/tests/markup_markdown.py

-import textwrap
-
-from django.test import TestCase
-
-from markupmirror.markup.markdown_ import MarkdownMarkup
-
-
-MARKUP = u"""\
-A First Level Header
-====================
-
-A Second Level Header
----------------------
-
-Now is the time for all good men to come to
-the aid of their country. This is just a
-regular paragraph.
-
-The quick brown fox jumped over the lazy
-dog's back.
-
-### Header 3
-
-> This is a blockquote.
->
-> This is the second paragraph in the blockquote.
->
-> ## This is an H2 in a blockquote
-"""
-
-
-class MarkdownMarkupTests(TestCase):
-    """Tests the ``markupmirror.markup.markdown_.MarkdownMarkup`` class that
-    converts Markdown content to HTML.
-
-    """
-    def test_convert(self):
-        markdown_markup = MarkdownMarkup()
-        # === becomes h2 because of headerid(level=2) extension
-        self.assertHTMLEqual(
-            markdown_markup(MARKUP),
-            textwrap.dedent(u"""\
-                <h2 id="a-first-level-header">A First Level Header</h2>
-                <h3 id="a-second-level-header">A Second Level Header</h3>
-                <p>Now is the time for all good men to come to
-                    the aid of their country. This is just a
-                    regular paragraph.</p>
-                <p>The quick brown fox jumped over the lazy dog's back.</p>
-                <h4 id="header-3">Header 3</h4>
-                <blockquote>
-                    <p>This is a blockquote.</p>
-                    <p>This is the second paragraph in the blockquote.</p>
-                    <h3 id="this-is-an-h2-in-a-blockquote">
-                        This is an H2 in a blockquote</h3>
-                </blockquote>
-                """))
-
-    # TODO: don't know how to fake an ImportError.
-    #       Excluded in tests.settings.COVERAGE_CODE_EXCLUDES.
-    #
-    # def test_no_markdown(self):
-    #     """If markdown is not installed, the converter will just not be
-    #     available.
-
-    #     """
-    #     # first, remove already registered markdown converter
-    #     markup_pool.unregister_markup('markdown')
-    #     self.assertRaises(KeyError, markup_pool.get_markup, 'markdown')
-
-    #     # trying to import markdown fails
-    #     with self.assertRaises(ImportError):
-    #         from markdown import Markdown
-
-    #     # now try to re-register by importing markdown_ module
-    #     # this tries to import markdown and fails silently
-    #     from markupmirror.markup import markdown_
-
-    #     # markdown should not be found
-    #     self.assertRaises(KeyError, markup_pool.get_markup, 'markdown')
-
-    #     # re-register markdown to restore default state
-    #     register_markup(MarkdownMarkup)
-
-
-__all__ = ('MarkdownMarkupTests',)

markupmirror/tests/tests/markup_plaintext.py

-import textwrap
-
-from django.test import TestCase
-
-from markupmirror.markup.plaintext import PlainTextMarkup
-
-
-MARKUP = u"""\
-This is some plaintext markup.
-It includes http://www.domain.com/ links and
-
-also some linebreaks.
-"""
-
-
-class PlainTextMarkupTests(TestCase):
-    """Tests the ``markupmirror.markup.plaintext.PlainTextMarkup`` class that
-    does simple conversion of linebreaks and URLs.
-
-    """
-
-    def test_convert(self):
-        plaintext_markup = PlainTextMarkup()
-        self.assertHTMLEqual(
-            plaintext_markup(MARKUP),
-            textwrap.dedent(u"""\
-                <p>This is some plaintext markup.<br />
-                It includes <a href="http://www.domain.com/">
-                    http://www.domain.com/</a> links and</p>
-                <p>also some linebreaks.<br /></p>
-                """))
-
-
-__all__ = ('PlainTextMarkupTests',)

markupmirror/tests/tests/markup_restructuredtext.py

-import textwrap
-
-from django.test import TestCase
-
-from markupmirror.markup.restructuredtext import ReStructuredTextMarkup
-
-MARKUP = u"""\
-A First Level Header
-====================
-
-A Second Level Header
----------------------
-
-Now is the time for all good men to come to
-the aid of their country. This is just a
-regular paragraph.
-
-The quick brown fox jumped over the lazy
-dog's back.
-
-Header 3
-^^^^^^^^
-
-    This is a blockquote.
-
-    This is the second paragraph in the blockquote.
-"""
-
-
-class ReStructuredTextMarkupTests(TestCase):
-    """Tests the
-    ``markupmirror.markup.restructuredtext.ReStructuredTextMarkup`` class that
-    converts reStructuredText content to HTML.
-
-    """
-    def test_convert(self):
-        restructuredtext_markup = ReStructuredTextMarkup()
-        self.assertHTMLEqual(
-            restructuredtext_markup(MARKUP),
-            textwrap.dedent(u"""\
-                <div class="document" id="a-first-level-header">
-                    <h1 class="title">A First Level Header</h1>
-                    <h2 class="subtitle" id="a-second-level-header">
-                        A Second Level Header</h2>
-                    <p>Now is the time for all good men to come to
-                        the aid of their country. This is just a
-                        regular paragraph.</p>
-                    <p>The quick brown fox jumped over the lazy dog's back.</p>
-                    <div class="section" id="header-3">
-                        <h1>Header 3</h1>
-                        <blockquote>
-                            <p>This is a blockquote.</p>
-                            <p>This is the second paragraph in the blockquote.
-                                </p>
-                        </blockquote>
-                    </div>
-                </div>
-                """))
-
-
-__all__ = ('ReStructuredTextMarkupTests',)

markupmirror/tests/tests/markup_textile.py

-import textwrap
-
-from django.test import TestCase
-
-from markupmirror.markup.textile_ import TextileMarkup
-
-MARKUP = u"""\
-h1. A First Level Header
-
-h2. A Second Level Header
-
-Now is the time for all good men to come to the aid of their country.
-This is just a regular paragraph.
-
-The quick brown fox jumped over the lazy dog's back.
-
-h3. Header 3
-
-bq. This is a blockquote.
-This is the second paragraph in the blockquote.
-"""
-
-
-class TextileMarkupTests(TestCase):
-    """Tests the ``markupmirror.markup.textile_.TextileMarkup`` class that
-    converts Textile content to HTML.
-
-    """
-    def test_convert(self):
-        textile_markup = TextileMarkup()
-        self.assertHTMLEqual(
-            textile_markup(MARKUP),
-            textwrap.dedent(u"""\
-                <h1>A First Level Header</h1>
-
-                <h2>A Second Level Header</h2>
-
-                <p>Now is the time for all good men to come to the aid of
-                    their country.<br />
-                    This is just a regular paragraph.</p>
-
-                <p>The quick brown fox jumped over the lazy dog&#8217;s back.
-                    </p>
-
-                <h3>Header 3</h3>
-
-                <blockquote>
-                    <p>This is a blockquote.<br />
-                    This is the second paragraph in the blockquote.</p>
-                </blockquote>
-                """))
-
-
-__all__ = ('TextileMarkupTests',)

markupmirror/tests/tests/widgets.py

Empty file removed.

markupmirror/tests/urls.py

-from django.conf.urls.defaults import include
-from django.conf.urls.defaults import patterns
-
-urlpatterns = patterns('',
-    (r'^markupmirror/', include('markupmirror.urls')),
-)

markupmirror/views.py

-from django.contrib.auth.decorators import login_required
-from django.contrib.auth.decorators import user_passes_test
 from django.http import HttpResponse
-from django.utils.decorators import method_decorator
 from django.views.generic.base import View
 
 from markupmirror.markup.base import markup_pool
 
     http_method_names = ['post']
 
-    @method_decorator(login_required)
-    @method_decorator(user_passes_test(lambda user: user.is_staff))
     def post(self, request, markup_type, *args, **kwargs):
         markup = markup_pool.get_markup(markup_type)
         text = self.request.POST.get('text', u"")
 Django == 1.4
 coverage == 3.5.1
-django-coverage == 1.2.2
+django-nose == 1.0
 docutils == 0.8.1
 ipython == 0.12
 ipdb == 0.6.1
 FeinCMS == 1.5.3
 Markdown == 2.1.1
+nose == 1.1.2
 pep8 == 1.0
 Sphinx == 1.1.3
 textile == 2.1.5

tests/__init__.py

Empty file added.

tests/media/.keep

Empty file added.
+from django.db import models
+
+from markupmirror.fields import MarkupMirrorField
+
+
+class Post(models.Model):
+    title = models.CharField(max_length=50)
+    body = MarkupMirrorField('post body')
+    comment = MarkupMirrorField(
+        escape_html=True, default_markup_type='markdown')
+
+    def __unicode__(self):
+        return self.title
+
+
+class Article(models.Model):
+    normal_field = MarkupMirrorField()
+    default_field = MarkupMirrorField(default_markup_type='markdown')
+    markdown_field = MarkupMirrorField(markup_type='markdown')
+
+
+class Abstract(models.Model):
+    content = MarkupMirrorField()
+
+    class Meta:
+        abstract = True
+
+
+class Concrete(Abstract):
+    pass

tests/requirements.txt

+coverage == 3.5.1
+django-nose == 1.0
+docutils == 0.8.1
+ipython == 0.12
+ipdb == 0.6.1
+FeinCMS == 1.5.3
+Markdown == 2.1.1
+nose == 1.1.2
+pep8 == 1.0
+Sphinx == 1.1.3
+textile == 2.1.5

tests/settings.py

+"""Test settigs for django-markupmirror."""
+
+import os
+
+
+TESTS_PATH = os.path.abspath(os.path.dirname(__file__))
+
+
+def tests_path_to(*parts):
+    """Returns absolute path for ``parts`` relative to ``TESTS_PATH``."""
+    return os.path.abspath(os.path.join(TESTS_PATH, *parts))
+
+
+DEBUG = True
+TEMPLATE_DEBUG = DEBUG
+
+INSTALLED_APPS = (
+    'django_nose',
+    'markupmirror',
+    'markupmirror.feincms',
+    'tests',
+)
+
+ROOT_URLCONF = 'tests.urls'
+
+DATABASES = {
+    'default': {
+        'ENGINE': 'django.db.backends.sqlite3',
+        'NAME': 'markupmirror.db',
+    }
+}
+
+CACHES = {
+    'default': {
+        'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
+        'LOCATION': 'markupmirror-tests',
+        'KEY_PREFIX': 'markupmirror-tests',
+        'TIMEOUT': 300,
+    }
+}
+
+MEDIA_ROOT = tests_path_to('media')
+MEDIA_URL = '/media/'
+STATIC_ROOT = tests_path_to('static')
+STATIC_URL = '/media/'
+
+USE_TZ = True
+
+LOGGING = {
+    'version': 1,
+    'disable_existing_loggers': True,
+    'handlers': {
+        'simple': {
+            'level': 'ERROR',
+            'class': 'logging.StreamHandler',
+        }
+    },
+    'loggers': {
+        'django.request': {
+            'handlers': ['simple'],
+            'level': 'ERROR',
+            'propagate': False,
+        },
+    }
+}
+
+
+# ### django-nose
+
+TEST_RUNNER = 'django_nose.NoseTestSuiteRunner'
+
+NOSE_ARGS = [
+    '--detailed-errors',
+    '--verbose',
+    '--with-coverage',
+    '--cover-html',
+    '--cover-html-dir=' + tests_path_to(os.path.pardir, 'docs', '_coverage'),
+    '--cover-package=markupmirror',
+]

tests/static/.keep

Empty file added.

tests/tests/__init__.py

+from tests.tests.fields import *
+from tests.tests.markup_base import *
+from tests.tests.markup_html import *
+from tests.tests.markup_markdown import *
+from tests.tests.markup_plaintext import *
+from tests.tests.markup_restructuredtext import *
+from tests.tests.markup_textile import *
+from tests.tests.version import *
+from tests.tests.views import *
+from tests.tests.widgets import *

tests/tests/fields.py

+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 tests.models import Post, Article, Abstract, 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')
+
+    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')
+
+
+__all__ = ('MarkupMirrorFieldTests',)

tests/tests/markup_base.py

+from django.test import TestCase
+
+from markupmirror.exceptions import InvalidMarkup
+from markupmirror.markup.base import BaseMarkup
+from markupmirror.markup.base import markup_pool
+from markupmirror.markup.base import register_markup
+
+
+class DummyMarkup(BaseMarkup):
+    pass
+
+
+class BaseMarkupTests(TestCase):
+    """Tests the ``markupmirror.markup.base.BaseMarkup`` class that acts as
+    a base class for markup converters.
+
+    """
+    def test_name(self):
+        """Tests ``BaseMarkup.get_name``."""
+
+        self.assertEqual(BaseMarkup.get_name(), 'base')
+        self.assertEqual(DummyMarkup.get_name(), 'dummy')
+
+    def test_convert_markup(self):
+        """Tests that the order of the three convert methods
+        ``before_convert``, ``convert`` and ``after_convert`` is kept
+        correctly.
+
+        """
+        class DummyMarkup(BaseMarkup):
+
+            def before_convert(self, markup):
+                return markup.replace("1", "2", 1)
+
+            def convert(self, markup):
+                return markup.replace("2", "3", 1)
+
+            def after_convert(self, markup):
+                return markup.replace("3", "4", 1)
+
+        dummy_markup = DummyMarkup()
+
+        self.assertEqual(dummy_markup.before_convert("1"), "2")
+        self.assertEqual(dummy_markup.convert("2"), "3")
+        self.assertEqual(dummy_markup.after_convert("3"), "4")
+        # test order
+        self.assertEqual(dummy_markup("1"), "4")
+
+    def test_base_convert(self):
+        """The ``BaseMarkup`` converter does not do anything."""
+        bm = BaseMarkup()
+        self.assertEqual(bm.before_convert("markup"), "markup")
+        self.assertEqual(bm.convert("markup"), "markup")
+        self.assertEqual(bm.after_convert("markup"), "markup")
+
+
+class MarkupPoolTests(TestCase):
+    """Tests the ``markupmirror.markup.base.MarkupPool``."""
+
+    def tearDown(self):
+        markup_pool.unregister_markup('dummy')
+
+    def test_register_invalid(self):
+        """Registering a markup class which does not subclass ``BaseMarkup``
+        raises an ``InvalidMarkup`` exception.
+
+        """
+        class InvalidMarkupClass(object):
+            pass
+
+        self.assertRaises(InvalidMarkup, register_markup, InvalidMarkupClass)
+
+    def test_re_register(self):
+        """Registering a markup converter would overwrite it.
+
+        """
+        register_markup(DummyMarkup)
+        dummy_markup = markup_pool['dummy']
+        register_markup(DummyMarkup)
+        self.assertTrue(isinstance(markup_pool['dummy'], DummyMarkup))
+        self.assertFalse(dummy_markup is markup_pool['dummy'])
+
+    def test_register(self):
+        """Registering a markup converter makes it available through its name.
+
+        """
+        # before the markup is registered, we'll get ``KeyError`` if
+        # we try to retrieve it.
+        self.assertRaises(KeyError, markup_pool.get_markup, 'dummy')
+
+        # it is available after registering it
+        register_markup(DummyMarkup)
+        self.assertTrue(isinstance(markup_pool['dummy'], DummyMarkup))
+
+    def test_unregister(self):
+        """Unregistering a markup converter removes it from the pool."""
+        register_markup(DummyMarkup)
+        self.assertTrue(isinstance(markup_pool['dummy'], DummyMarkup))
+        del markup_pool['dummy']
+        self.assertRaises(KeyError, markup_pool.get_markup, 'dummy')
+
+    def test_get_all(self):
+        """``markup_pool.get_all_markups`` returns all markup converters."""
+        all_markups = markup_pool.markups
+        self.assertEqual(
+            ['html', 'markdown', 'plaintext', 'restructuredtext', 'textile'],
+            sorted(all_markups.keys()))
+
+
+__all__ = ('BaseMarkupTests', 'MarkupPoolTests')

tests/tests/markup_html.py

+from django.test import TestCase
+
+from markupmirror.markup.html import HtmlMarkup
+
+
+MARKUP = u"""\
+<h1>A First Level Header</h1>
+
+<h2>A Second Level Header</h2>
+
+<p>Now is the time for all good men to come to the aid of their country.<br />
+This is just a regular paragraph.</p>
+
+<p>The quick brown fox jumped over the lazy dog's back.</p>
+
+<h3>Header 3</h3>
+
+<blockquote>
+    <p>This is a blockquote.</p>
+    <p>This is the second paragraph in the blockquote.</p>
+</blockquote>
+"""
+
+
+class HTMLMarkupTests(TestCase):
+    """Tests the ``markupmirror.markup.html.HtmlMarkup`` class that
+    passes through plain HTML content.
+
+    """
+    def test_convert(self):
+        """The ``HtmlMarkup`` converter does not do anything."""
+        html_markup = HtmlMarkup()
+        self.assertHTMLEqual(html_markup(MARKUP), MARKUP)
+
+
+__all__ = ('HTMLMarkupTests',)

tests/tests/markup_markdown.py

+import textwrap
+
+from django.test import TestCase
+
+from markupmirror.markup.markdown_ import MarkdownMarkup
+
+
+MARKUP = u"""\
+A First Level Header
+====================
+
+A Second Level Header
+---------------------
+
+Now is the time for all good men to come to
+the aid of their country. This is just a
+regular paragraph.
+
+The quick brown fox jumped over the lazy
+dog's back.
+
+### Header 3
+
+> This is a blockquote.
+>
+> This is the second paragraph in the blockquote.
+>
+> ## This is an H2 in a blockquote
+"""
+
+
+class MarkdownMarkupTests(TestCase):
+    """Tests the ``markupmirror.markup.markdown_.MarkdownMarkup`` class that
+    converts Markdown content to HTML.
+
+    """
+    def test_convert(self):
+        """The ``MarkdownMarkup`` converter uses python-markdown to convert
+        markdown to HTML.
+
+        """
+        markdown_markup = MarkdownMarkup()
+        # === becomes h2 because of headerid(level=2) extension
+        self.assertHTMLEqual(
+            markdown_markup(MARKUP),
+            textwrap.dedent(u"""\
+                <h2 id="a-first-level-header">A First Level Header</h2>
+                <h3 id="a-second-level-header">A Second Level Header</h3>
+                <p>Now is the time for all good men to come to
+                    the aid of their country. This is just a
+                    regular paragraph.</p>
+                <p>The quick brown fox jumped over the lazy dog's back.</p>
+                <h4 id="header-3">Header 3</h4>
+                <blockquote>
+                    <p>This is a blockquote.</p>
+                    <p>This is the second paragraph in the blockquote.</p>
+                    <h3 id="this-is-an-h2-in-a-blockquote">
+                        This is an H2 in a blockquote</h3>
+                </blockquote>
+                """))
+
+    # TODO: don't know how to fake an ImportError.
+    #       Excluded in tests.settings.COVERAGE_CODE_EXCLUDES.
+    #
+    # def test_no_markdown(self):
+    #     """If markdown is not installed, the converter will just not be
+    #     available.
+
+    #     """
+    #     # first, remove already registered markdown converter
+    #     markup_pool.unregister_markup('markdown')
+    #     self.assertRaises(KeyError, markup_pool.get_markup, 'markdown')
+
+    #     # trying to import markdown fails
+    #     with self.assertRaises(ImportError):
+    #         from markdown import Markdown
+
+    #     # now try to re-register by importing markdown_ module
+    #     # this tries to import markdown and fails silently
+    #     from markupmirror.markup import markdown_
+
+    #     # markdown should not be found
+    #     self.assertRaises(KeyError, markup_pool.get_markup, 'markdown')
+
+    #     # re-register markdown to restore default state
+    #     register_markup(MarkdownMarkup)
+
+
+__all__ = ('MarkdownMarkupTests',)

tests/tests/markup_plaintext.py

+import textwrap
+
+from django.test import TestCase
+
+from markupmirror.markup.plaintext import PlainTextMarkup
+
+
+MARKUP = u"""\
+This is some plaintext markup.
+It includes http://www.domain.com/ links and
+
+also some linebreaks.
+"""
+
+
+class PlainTextMarkupTests(TestCase):
+    """Tests the ``markupmirror.markup.plaintext.PlainTextMarkup`` class that
+    does simple conversion of linebreaks and URLs.
+
+    """
+
+    def test_convert(self):
+        """The ``PlaintextMarkup`` converter uses ``urlize`` and ``linebreaks``
+        to convert URLs to anchors and linebreaks to paragraphs.
+
+        """
+        plaintext_markup = PlainTextMarkup()
+        self.assertHTMLEqual(
+            plaintext_markup(MARKUP),
+            textwrap.dedent(u"""\
+                <p>This is some plaintext markup.<br />
+                It includes <a href="http://www.domain.com/">
+                    http://www.domain.com/</a> links and</p>
+                <p>also some linebreaks.<br /></p>
+                """))
+
+
+__all__ = ('PlainTextMarkupTests',)

tests/tests/markup_restructuredtext.py

+import textwrap
+
+from django.test import TestCase
+
+from markupmirror.markup.restructuredtext import ReStructuredTextMarkup
+
+
+MARKUP = u"""\
+A First Level Header
+====================
+
+A Second Level Header
+---------------------
+
+Now is the time for all good men to come to
+the aid of their country. This is just a
+regular paragraph.
+
+The quick brown fox jumped over the lazy
+dog's back.
+
+Header 3
+^^^^^^^^
+
+    This is a blockquote.
+
+    This is the second paragraph in the blockquote.
+"""
+
+
+class ReStructuredTextMarkupTests(TestCase):
+    """Tests the
+    ``markupmirror.markup.restructuredtext.ReStructuredTextMarkup`` class that
+    converts reStructuredText content to HTML.
+
+    """
+    def test_convert(self):
+        """The ``ReStructuredTextMarkup`` converter uses docutils to convert
+        reStructuredText markup to HTML.
+
+        """
+        restructuredtext_markup = ReStructuredTextMarkup()
+        self.assertHTMLEqual(
+            restructuredtext_markup(MARKUP),
+            textwrap.dedent(u"""\
+                <div class="document" id="a-first-level-header">
+                    <h1 class="title">A First Level Header</h1>
+                    <h2 class="subtitle" id="a-second-level-header">
+                        A Second Level Header</h2>
+                    <p>Now is the time for all good men to come to
+                        the aid of their country. This is just a
+                        regular paragraph.</p>
+                    <p>The quick brown fox jumped over the lazy dog's back.</p>
+                    <div class="section" id="header-3">
+                        <h1>Header 3</h1>
+                        <blockquote>
+                            <p>This is a blockquote.</p>
+                            <p>This is the second paragraph in the blockquote.
+                                </p>
+                        </blockquote>
+                    </div>
+                </div>
+                """))
+
+
+__all__ = ('ReStructuredTextMarkupTests',)

tests/tests/markup_textile.py

+import textwrap
+
+from django.test import TestCase
+
+from markupmirror.markup.textile_ import TextileMarkup
+
+
+MARKUP = u"""\
+h1. A First Level Header
+
+h2. A Second Level Header
+
+Now is the time for all good men to come to the aid of their country.
+This is just a regular paragraph.
+
+The quick brown fox jumped over the lazy dog's back.
+
+h3. Header 3
+
+bq. This is a blockquote.
+This is the second paragraph in the blockquote.
+"""
+
+
+class TextileMarkupTests(TestCase):
+    """Tests the ``markupmirror.markup.textile_.TextileMarkup`` class that
+    converts Textile content to HTML.
+
+    """
+    def test_convert(self):
+        """The ``TextileMarkup`` converter uses textile to convert Textile
+        markup to HTML.
+
+        """
+        textile_markup = TextileMarkup()
+        self.assertHTMLEqual(
+            textile_markup(MARKUP),
+            textwrap.dedent(u"""\
+                <h1>A First Level Header</h1>
+
+                <h2>A Second Level Header</h2>
+
+                <p>Now is the time for all good men to come to the aid of
+                    their country.<br />
+                    This is just a regular paragraph.</p>
+
+                <p>The quick brown fox jumped over the lazy dog&#8217;s back.
+                    </p>
+
+                <h3>Header 3</h3>
+
+                <blockquote>
+                    <p>This is a blockquote.<br />
+                    This is the second paragraph in the blockquote.</p>
+                </blockquote>
+                """))
+
+
+__all__ = ('TextileMarkupTests',)

tests/tests/version.py

+from django.test import TestCase
+
+import markupmirror
+
+
+class VersionTests(TestCase):
+    """Tests the version information tools in ``markupmirror.__init__``."""
+
+    def setUp(self):
+        self.original_version = markupmirror.VERSION_INFO
+        markupmirror.VERSION_INFO = {
+            'major': 1,
+            'minor': 3,
+            'micro': 0,
+            'sub': 'final',
+            'serial': 1
+        }
+
+    def tearDown(self):
+        markupmirror.VERSION_INFO = self.original_version
+
+    def test_get_version(self):
+        """Tests if ``markupmirror.get_version`` returns the correct dotted
+        version string depending on the settings in ``VERSION_INFO``.
+
+        """
+        self.assertEqual(markupmirror.get_version(), '1.3')
+        # add a micro version
+        markupmirror.VERSION_INFO['micro'] = 7
+        self.assertEqual(markupmirror.get_version(), '1.3.7')
+        # alpha, beta, candidate or final versions with serial numbers
+        markupmirror.VERSION_INFO['sub'] = 'alpha'
+        markupmirror.VERSION_INFO['serial'] = 2
+        self.assertEqual(markupmirror.get_version(), '1.3.7a2')
+        markupmirror.VERSION_INFO['sub'] = 'beta'
+        markupmirror.VERSION_INFO['serial'] = 1
+        self.assertEqual(markupmirror.get_version(), '1.3.7b1')
+        markupmirror.VERSION_INFO['sub'] = 'candidate'
+        markupmirror.VERSION_INFO['serial'] = 3
+        self.assertEqual(markupmirror.get_version(), '1.3.7c3')
+        markupmirror.VERSION_INFO['sub'] = 'final'
+        markupmirror.VERSION_INFO['serial'] = 1
+        self.assertEqual(markupmirror.get_version(), '1.3.7')
+
+    def test_get_short_version(self):
+        """``get_version(short=True)`` should only ever return major and minor
+        version.
+
+        """
+        self.assertEqual(markupmirror.get_version(short=True), '1.3')
+
+    def test_invalid_sub_or_serial(self):
+        """``VERSION_INFO['sub']`` must be one of alpha, beta, candidate or
+        final; ``VERSION_INFO['serial']`` must be an integer >= 1.
+
+        """
+        # invalid sub
+        markupmirror.VERSION_INFO['sub'] = 'betta'
+        markupmirror.VERSION_INFO['serial'] = 1
+        self.assertRaises(AssertionError, markupmirror.get_version)
+        # invalid serial
+        markupmirror.VERSION_INFO['sub'] = 'beta'
+        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
+        markupmirror.VERSION_INFO['major'] = 'one'
+        self.assertRaises(AssertionError, markupmirror.get_version)
+        # invalid minor
+        markupmirror.VERSION_INFO['minor'] = 'three'
+        self.assertRaises(AssertionError, markupmirror.get_version)
+        # invalid micro
+        markupmirror.VERSION_INFO['micro'] = 'seven'
+        self.assertRaises(AssertionError, markupmirror.get_version)
+
+
+__all__ = ('VersionTests',)

tests/tests/views.py

+from django.http import HttpResponse
+from django.http import HttpResponseNotAllowed
+from django.test import TestCase
+from django.core.urlresolvers import reverse
+
+
+class MarkupPreviewViewTests(TestCase):
+    """Tests the ``markupmirror.views.MarkupPreview`` view implementation."""
+
+    def test_url(self):
+        """Tests that the markupmirror namespace is being registered and
+        the preview URL can be resolved correctly.
+
+        """
+        self.assertEqual(
+            reverse('markupmirror:preview',
+                    kwargs={'markup_type': 'plaintext'}),
+            '/markupmirror/preview/plaintext/')
+
+    def test_post_only(self):
+        """The preview view may only be used via POST to make sure text won't
+        be truncated or the like.
+
+        """
+        url = reverse('markupmirror:preview',
+                      kwargs={'markup_type': 'plaintext'})
+        self.assertIsInstance(self.client.get(url), HttpResponseNotAllowed)
+        self.assertIsInstance(self.client.post(url, {'text': "**markup**"}),
+                              HttpResponse)
+
+
+__all__ = ('MarkupPreviewViewTests',)

tests/tests/widgets.py

Empty file added.
+from django.conf.urls.defaults import include
+from django.conf.urls.defaults import patterns
+
+import markupmirror.urls
+
+
+urlpatterns = patterns('',
+    (r'^markupmirror/', include(markupmirror.urls.preview)),
+)
 setenv =
     PYTHONPATH = {toxinidir}
 commands =
-    {envbindir}/django-admin.py test --settings=markupmirror.tests.settings tests
+    {envbindir}/django-admin.py test --settings=tests.settings tests
 deps =
-    -r{toxinidir}/markupmirror/tests/requirements.txt
+    -r{toxinidir}/tests/requirements.txt
     Django == 1.4
 
 [testenv:py26]
 
 [testenv:py27]
 basepython = python2.7
-commands =
-    {envbindir}/django-admin.py test_coverage --settings=markupmirror.tests.settings tests
 
 [testenv:docs]
 basepython = python2.7
 [testenv:pep8]
 basepython = python2.7
 commands =
-    {envbindir}/pep8 --show-source --show-pep8 --count docs markupmirror setup.py
+    {envbindir}/pep8 --show-source --show-pep8 --count docs markupmirror tests setup.py