Commits

Anonymous committed b07f173

refactored settings and tests

Comments (0)

Files changed (13)

 ---------
 
 Repository:
+  * Moved localeurl settings from localeurl/__init__.py to
+    localeurl/settings.py.  
   * Added ``LocaleurlSitemap`` for easier creation of multilingual
     sitemaps.
   * Added ``LOCALEURL_USE_ACCEPT_LANGUAGE`` setting to check HTTP

localeurl/__init__.py

-import re
-from django.conf import settings
-
-SUPPORTED_LOCALES = dict(settings.LANGUAGES)
-LOCALES_RE = '|'.join(SUPPORTED_LOCALES)
-PATH_RE = re.compile(r'^/(?P<locale>%s)(?P<path>.*)$' % LOCALES_RE)
-
-LOCALE_INDEPENDENT_PATHS = getattr(settings, 'LOCALE_INDEPENDENT_PATHS', ())
-
-LOCALE_INDEPENDENT_MEDIA_URL = getattr(settings,
-        'LOCALE_INDEPENDENT_MEDIA_URL', True)
-
-PREFIX_DEFAULT_LOCALE = getattr(settings, 'PREFIX_DEFAULT_LOCALE', True)
-
-USE_ACCEPT_LANGUAGE = getattr(settings, 'LOCALEURL_USE_ACCEPT_LANGUAGE', False)

localeurl/middleware.py

 from django.utils import translation
 # TODO importing undocumented function
 from django.utils.translation.trans_real import parse_accept_lang_header
-import localeurl
+from localeurl import settings as localeurl_settings
 from localeurl import utils
 
 # Make sure the default language is in the list of supported languages
 
     def process_request(self, request):
         locale, path = utils.strip_path(request.path_info)
-        if localeurl.USE_ACCEPT_LANGUAGE and not locale:
+        if localeurl_settings.USE_ACCEPT_LANGUAGE and not locale:
             accept_langs = filter(lambda x: x, [utils.supported_language(lang[0])
                                                 for lang in
                                                 parse_accept_lang_header(

localeurl/settings.py

+import re
+from django.conf import settings
+
+SUPPORTED_LOCALES = dict(settings.LANGUAGES)
+LOCALES_RE = '|'.join(SUPPORTED_LOCALES)
+PATH_RE = re.compile(r'^/(?P<locale>%s)(?P<path>.*)$' % LOCALES_RE)
+
+LOCALE_INDEPENDENT_PATHS = getattr(settings, 'LOCALE_INDEPENDENT_PATHS', ())
+
+LOCALE_INDEPENDENT_MEDIA_URL = getattr(settings,
+        'LOCALE_INDEPENDENT_MEDIA_URL', True)
+
+PREFIX_DEFAULT_LOCALE = getattr(settings, 'PREFIX_DEFAULT_LOCALE', True)
+
+USE_ACCEPT_LANGUAGE = getattr(settings, 'LOCALEURL_USE_ACCEPT_LANGUAGE', False)

localeurl/test_settings.py

-"""
-Test settings.
-"""
-
-DATABASE_ENGINE = 'sqlite3'
-DATABASE_NAME = ':memory:'
-
-SITE_ID = 1
-
-ROOT_URLCONF = 'localeurl.test_urls'
-
-INSTALLED_APPS = (
-    'localeurl',
-)

localeurl/test_urls.py

-"""
-URLconf for testing.
-"""
-
-from django.conf.urls.defaults import *
-
-urlpatterns = patterns('localeurl.test_urls',
-     url(r'^dummy/$', 'dummy', name='dummy0'),
-     url(r'^dummy/(?P<test>.+)$', 'dummy', name='dummy1'),
-)
-
-def dummy(request, test='test'):
-    pass

localeurl/test_utils.py

-"""
-Test settings manager, originally copied from a `Django snippet`_ by 'carljm'.
-
-.. _`Django snippet`: http://www.djangosnippets.org/snippets/1011/
-"""
-
-from django.conf import settings as django_settings
-from django.core.handlers.wsgi import WSGIRequest
-from django.core.management import call_command
-from django.db.models import loading
-from django import template
-from django.test import Client
-from django.utils import encoding
-
-
-NO_SETTING = object()
-
-class TestSettingsManager(object):
-    """
-    A class which can modify some Django settings temporarily for a
-    test and then revert them to their original values later.
-
-    Automatically handles resyncing the DB if INSTALLED_APPS is
-    modified.
-
-    Based on the work by 'carljm':
-    http://www.djangosnippets.org/snippets/1011/
-    """
-    def __init__(self, settings=django_settings):
-        self._settings = settings
-        self._original_settings = {}
-
-    def set(self, **kwargs):
-        self.set_from_dict(kwargs)
-
-    def set_from_dict(self, settings):
-        for k,v in settings.iteritems():
-            self._original_settings.setdefault(k,
-                    getattr(self._settings, k, NO_SETTING))
-            setattr(self._settings, k, v)
-        if 'INSTALLED_APPS' in settings:
-            self.syncdb()
-
-    def syncdb(self):
-        loading.cache.loaded = False
-        call_command('syncdb', verbosity=0)
-
-    def revert(self):
-        for k,v in self._original_settings.iteritems():
-            if v == NO_SETTING:
-                try:
-                    delattr(self._settings, k)
-                except AttributeError:
-                    # Django < r11825
-                    delattr(self._settings._wrapped, k)
-            else:
-                setattr(self._settings, k, v)
-        if self._settings == django_settings \
-                and 'INSTALLED_APPS' in self._original_settings:
-            self.syncdb()
-        self._original_settings = {}
-
-
-class RequestFactory(Client):
-    """
-    Class that lets you create mock Request objects for use in testing.
-
-    Usage:
-
-    rf = RequestFactory()
-    get_request = rf.get('/hello/')
-    post_request = rf.post('/submit/', {'foo': 'bar'})
-
-    This class re-uses the django.test.client.Client interface, docs here:
-    http://www.djangoproject.com/documentation/testing/#the-test-client
-
-    Once you have a request object you can pass it to any view function,
-    just as if that view had been hooked up using a URLconf.
-
-    Based on the work by Simon Willison:
-    http://www.djangosnippets.org/snippets/963/
-    """
-    def request(self, **request):
-        """
-        Similar to parent class, but returns the request object as soon as it
-        has created it.
-        """
-        environ = {
-            'HTTP_COOKIE': self.cookies,
-            'PATH_INFO': '/',
-            'QUERY_STRING': '',
-            'REQUEST_METHOD': 'GET',
-            'SCRIPT_NAME': '',
-            'SERVER_NAME': 'testserver',
-            'SERVER_PORT': 80,
-            'SERVER_PROTOCOL': 'HTTP/1.1',
-        }
-        environ.update(self.defaults)
-        environ.update(request)
-        return WSGIRequest(environ)
-
-
-class TestTemplate(template.Template):
-    """
-    TestTemplate behaves just like django.template.Template, but you can give
-    it a list of template.Libraries to load before parsing the template. This
-    is equivalent to adding a bunch of {% load %} tags to the beginning of your
-    template string, but you can use custom tag libraries which do not belong
-    to Django applications' templatetags packages.
-
-    Based on the work by Alexander Khodyrev:
-    http://www.djangosnippets.org/snippets/1641/
-    """
-    def __init__(self, template_string, name='<Unknown Template>',
-            libraries=[]):
-        try:
-            template_string = encoding.smart_unicode(template_string)
-        except UnicodeDecodeError:
-            raise template.TemplateEncodingError(
-                    "template content must be unicode or UTF-8 string")
-        origin = template.StringOrigin(template_string)
-        self.nodelist = self.my_compile_string(template_string, origin,
-                libraries)
-        self.name = name
-
-    def my_compile_string(self, template_string, origin, libraries=[]):
-        "Compiles template_string into NodeList ready for rendering"
-        lexer = template.Lexer(template_string, origin)
-        parser = template.Parser(lexer.tokenize())
-        for lib in libraries:
-            parser.add_library(lib)
-        return parser.parse()

localeurl/tests.py

-"""
-Tests for the localeurl application.
-"""
-
-import re
-import localeurl
-from localeurl import middleware
-from localeurl import test_utils
-from localeurl import utils
-from localeurl.sitemaps import LocaleurlSitemap
-from localeurl.templatetags import localeurl_tags
-
-from django.core import urlresolvers
-from django.test import TestCase
-from django import template
-
-def settings_fixture(mgr):
-    mgr.set(
-        INSTALLED_APPS = (
-            'localeurl',
-        ),
-        USE_I18N = True,
-        LANGUAGES = (
-            ('en', 'English'),
-            ('nl-nl', 'Dutch'),
-            ('nl-be', 'Flemish'),
-            ('fr', 'French'),
-        ),
-        LANGUAGE_CODE = 'en-gb',
-        LOCALE_INDEPENDENT_PATHS = (
-            re.compile('^/$'),
-            re.compile('^/test/independent/'),
-        ),
-        LOCALE_INDEPENDENT_MEDIA_URL = True,
-        MEDIA_URL = '/media/',
-        TEMPLATE_CONTEXT_PROCESSORS = (
-            'django.core.context_processors.i18n',
-        ),
-    )
-
-
-class LocaleurlTestCase(TestCase):
-    urls = 'localeurl.test_urls'
-
-    def setUp(self):
-        self.settings_manager = test_utils.TestSettingsManager()
-        settings_fixture(self.settings_manager)
-        reload(localeurl)
-        reload(urlresolvers)
-
-    def tearDown(self):
-        self.settings_manager.revert()
-        reload(localeurl)
-        reload(urlresolvers)
-
-
-class UtilsTestCase(LocaleurlTestCase):
-
-    def test_is_locale_independent(self):
-        self.assertFalse(utils.is_locale_independent('/fr/about'))
-        self.assertFalse(utils.is_locale_independent('/about'))
-        self.assertTrue(utils.is_locale_independent('/media/img/logo.png'))
-        self.assertTrue(utils.is_locale_independent('/'))
-        self.assertTrue(utils.is_locale_independent(
-                '/test/independent/bla/bla'))
-
-    def test_strip_path(self):
-        self.assertEqual(('', '/'), utils.strip_path('/'))
-        self.assertEqual(('', '/about/'), utils.strip_path('/about/'))
-        self.assertEqual(('', '/about/localeurl/'),
-                utils.strip_path('/about/localeurl/'))
-        self.assertEqual(('fr', '/about/localeurl/'),
-                utils.strip_path('/fr/about/localeurl/'))
-        self.assertEqual(('nl-be', '/about/localeurl/'),
-                utils.strip_path('/nl-be/about/localeurl/'))
-        self.assertEqual(('', '/de/about/localeurl/'),
-                utils.strip_path('/de/about/localeurl/'))
-
-    def test_supported_language(self):
-        self.assertEqual('fr', utils.supported_language('fr'))
-        self.assertEqual('nl-be', utils.supported_language('nl-be'))
-        self.assertEqual('en', utils.supported_language('en-gb'))
-        self.assertEqual(None, utils.supported_language('de'))
-
-    def test_is_default_locale(self):
-        self.assertTrue(utils.is_default_locale('en'))
-        self.assertFalse(utils.is_default_locale('en-gb'))
-        self.assertFalse(utils.is_default_locale('fr'))
-        self.assertFalse(utils.is_default_locale('de'))
-
-    def test_locale_path(self):
-        self.assertEqual('/en/about/localeurl/',
-                utils.locale_path('/about/localeurl/'))
-        self.assertEqual('/en/about/localeurl/',
-                utils.locale_path('/about/localeurl/', 'de'))
-        self.assertEqual('/en/about/localeurl/',
-                utils.locale_path('/about/localeurl/', 'en'))
-        self.assertEqual('/en/about/localeurl/',
-                utils.locale_path('/about/localeurl/', 'en-us'))
-        self.assertEqual('/nl-nl/about/localeurl/',
-                utils.locale_path('/about/localeurl/', 'nl-nl'))
-        self.assertEqual('/test/independent/bla/bla',
-                utils.locale_path('/test/independent/bla/bla', 'en'))
-
-    def test_locale_url(self):
-        # We'd like to be able to test using settings.FORCE_SCRIPT_NAME, but
-        # the urlresolvers module caches the prefix.
-        script_name = urlresolvers.get_script_prefix()
-        self.assertEqual(script_name + 'en/about/localeurl/',
-                utils.locale_url('/about/localeurl/'))
-        self.assertEqual(script_name + 'en/about/localeurl/',
-                utils.locale_url('/about/localeurl/', 'de'))
-        self.assertEqual(script_name + 'en/about/localeurl/',
-                utils.locale_url('/about/localeurl/', 'en'))
-        self.assertEqual(script_name + 'en/about/localeurl/',
-                utils.locale_url('/about/localeurl/', 'en-us'))
-        self.assertEqual(script_name + 'nl-nl/about/localeurl/',
-                utils.locale_url('/about/localeurl/', 'nl-nl'))
-        self.assertEqual(script_name + 'test/independent/bla/bla',
-                utils.locale_path('/test/independent/bla/bla', 'en'))
-
-
-class MiddlewareTestCase(LocaleurlTestCase):
-    def setUp(self):
-        super(MiddlewareTestCase, self).setUp()
-        self.request_factory = test_utils.RequestFactory()
-        self.middleware = middleware.LocaleURLMiddleware()
-
-    def test_with_locale(self):
-        r1 = self.request_factory.get('/fr/test/')
-        r2 = self.middleware.process_request(r1)
-        self.assertEqual(None, r2)
-        self.assertEqual('fr', r1.LANGUAGE_CODE)
-        self.assertEqual('/test/', r1.path_info)
-
-    def test_with_sublocale(self):
-        r1 = self.request_factory.get('/nl-nl/test/bla/bla/')
-        r2 = self.middleware.process_request(r1)
-        self.assertEqual(None, r2)
-        self.assertEqual('nl-nl', r1.LANGUAGE_CODE)
-        self.assertEqual('/test/bla/bla/', r1.path_info)
-
-    def test_locale_independent_url(self):
-        r1 = self.request_factory.get('/test/independent/bla/bla/')
-        r2 = self.middleware.process_request(r1)
-        self.assertEqual(None, r2)
-        self.assertEqual('en-gb', r1.LANGUAGE_CODE)
-        self.assertEqual('/test/independent/bla/bla/', r1.path_info)
-
-    def test_locale_specified_on_independent_url_with_query_string(self):
-        r1 = self.request_factory.get('/nl-be/test/independent/?foo=bar')
-        r2 = self.middleware.process_request(r1)
-        self.assertEqual(301, r2.status_code)
-        self.assertEqual('/test/independent/?foo=bar', r2['Location'])
-
-    def test_check_accept_lang(self):
-        self.settings_manager.set(LOCALEURL_USE_ACCEPT_LANGUAGE=True)
-        reload(localeurl)
-
-        r1 = self.request_factory.get('/test/', HTTP_ACCEPT_LANGUAGE='fr, de;q=0.8')
-        r2 = self.middleware.process_request(r1)
-        self.assertEqual(301, r2.status_code)
-        self.assertEqual('/fr/test/', r2['Location'])
-
-class DefaultPrefixMiddlewareTestCase(MiddlewareTestCase):
-    def setUp(self):
-        super(DefaultPrefixMiddlewareTestCase, self).setUp()
-
-    def test_no_locale(self):
-        r1 = self.request_factory.get('/test/')
-        r2 = self.middleware.process_request(r1)
-        self.assertEqual(301, r2.status_code)
-        self.assertEqual('/en/test/', r2['Location'])
-        
-    def test_with_query_string(self):
-        r1 = self.request_factory.get('/test/?somevar=someval')
-        r2 = self.middleware.process_request(r1)
-        self.assertEqual(301, r2.status_code)
-        self.assertEqual('/en/test/?somevar=someval', r2['Location'])
-
-class NoDefaultPrefixMiddlewareTestCase(MiddlewareTestCase):
-    def setUp(self):
-        super(NoDefaultPrefixMiddlewareTestCase, self).setUp()
-        self.settings_manager.set(PREFIX_DEFAULT_LOCALE=False)
-        reload(localeurl)
-        
-    def test_default_locale(self):
-        r1 = self.request_factory.get('/test/foo/')
-        r2 = self.middleware.process_request(r1)
-        self.assertEqual(None, r2)
-        self.assertEqual('en-gb', r1.LANGUAGE_CODE)
-        self.assertEqual('/test/foo/', r1.path_info)
-
-    def test_default_locale_specified(self):
-        r1 = self.request_factory.get('/en/test/foo/')
-        r2 = self.middleware.process_request(r1)
-        self.assertEqual(301, r2.status_code)
-        self.assertEqual('/test/foo/', r2['Location'])
-
-    def test_alternate_locale(self):
-        r1 = self.request_factory.get('/fr/test/foo/')
-        r2 = self.middleware.process_request(r1)
-        self.assertEqual(None, r2)
-        self.assertEqual('fr', r1.LANGUAGE_CODE)
-        self.assertEqual('/test/foo/', r1.path_info)
-
-
-class TagsTestCase(LocaleurlTestCase):
-    def render_template(self, text):
-        t = test_utils.TestTemplate(text, libraries=[localeurl_tags.register])
-        c = template.Context()
-        return t.render(c)
-
-    def test_locale_url_tag(self):
-        self.assertRaises(ValueError, self.render_template,
-                '{% locale_url "nl" dummy0 %}')
-
-        self.assertEqual('/en/dummy/', self.render_template(
-                '{% locale_url "en-us" dummy0 %}'))
-
-        self.assertEqual('/fr/dummy/4', self.render_template(
-            '{% locale_url "fr" dummy1 test=4 %}'))
-
-        self.assertEqual('/en/dummy/4', self.render_template(
-            '{% locale_url "en" dummy1 test=4 as testvar %}{{ testvar }}'))
-
-    def test_chlocale_filter(self):
-        self.assertEqual('/fr/dummy/', self.render_template(
-                '{{ "/dummy/"|chlocale:"fr" }}'))
-
-        self.assertEqual('/en/dummy/', self.render_template(
-                '{{"/fr/dummy/"|chlocale:"en-gb"}}'))
-
-    def test_rmlocale_filter(self):
-        self.assertEqual('/dummy/', self.render_template(
-                '{{ "/dummy/"|rmlocale }}'))
-
-        self.assertEqual('/dummy/', self.render_template(
-                '{{ "/nl-be/dummy/"|rmlocale }}'))
-
-        self.assertEqual('/dummy/', self.render_template(
-                '{{ "/en/dummy/"|rmlocale }}'))
-
-    def test_locale_url_tag_no_default_prefix(self):
-        self.settings_manager.set(PREFIX_DEFAULT_LOCALE=False)
-        reload(localeurl)
-
-        self.assertEqual('/dummy/', self.render_template(
-                '{% locale_url "en-us" dummy0 %}'))
-
-        self.assertEqual('/fr/dummy/', self.render_template(
-            '{% locale_url "fr" dummy0 %}'))
-
-    def test_chlocale_filter_no_default_prefix(self):
-        self.settings_manager.set(PREFIX_DEFAULT_LOCALE=False)
-        reload(localeurl)
-
-        self.assertEqual('/dummy/', self.render_template(
-                '{{ "/nl-nl/dummy/"|chlocale:"en-gb" }}'))
-
-        self.assertEqual('/fr/dummy/', self.render_template(
-                '{{"/nl-nl/dummy/"|chlocale:"fr"}}'))
-
-class DummyModel(object):
-    def __init__(self, num):
-        self.num = num
-
-    def get_absolute_url(self):
-        return '/dummy/%s/' % self.num
-
-class DummySitemap(LocaleurlSitemap):
-    def items(self):
-        return [DummyModel(i) for i in range(3)]
-
-class SitemapTestCase(LocaleurlTestCase):
-    def setUp(self):
-        super(SitemapTestCase, self).setUp()
-        class DummySite(object):
-            domain = 'www.example.com'
-        from django.contrib.sites.models import Site
-        self._orig_get_current = Site.objects.get_current
-        Site.objects.get_current = lambda: DummySite()
-    
-    def test_localeurl_sitemap(self):
-        sitemap = DummySitemap('fr')
-        self.assertEqual(sitemap.get_urls()[0]['location'],
-                         'http://www.example.com/fr/dummy/0/')
-
-    def tearDown(self):
-        super(SitemapTestCase, self).tearDown()
-        from django.contrib.sites.models import Site
-        Site.objects.get_current = self._orig_get_current

localeurl/tests/__init__.py

+"""
+Tests for the localeurl application.
+"""
+
+import re
+from localeurl import settings as localeurl_settings
+from localeurl import middleware
+from localeurl.tests import test_utils
+from localeurl import utils
+from localeurl.sitemaps import LocaleurlSitemap
+from localeurl.templatetags import localeurl_tags
+
+from django.core import urlresolvers
+from django.test import TestCase
+from django import template
+
+def settings_fixture(mgr):
+    mgr.set(
+        INSTALLED_APPS = (
+            'localeurl',
+        ),
+        USE_I18N = True,
+        LANGUAGES = (
+            ('en', 'English'),
+            ('nl-nl', 'Dutch'),
+            ('nl-be', 'Flemish'),
+            ('fr', 'French'),
+        ),
+        LANGUAGE_CODE = 'en-gb',
+        LOCALE_INDEPENDENT_PATHS = (
+            re.compile('^/$'),
+            re.compile('^/test/independent/'),
+        ),
+        LOCALE_INDEPENDENT_MEDIA_URL = True,
+        MEDIA_URL = '/media/',
+        TEMPLATE_CONTEXT_PROCESSORS = (
+            'django.core.context_processors.i18n',
+        ),
+    )
+
+
+class LocaleurlTestCase(TestCase):
+    urls = 'localeurl.tests.test_urls'
+
+    def setUp(self):
+        self.settings_manager = test_utils.TestSettingsManager()
+        settings_fixture(self.settings_manager)
+        reload(localeurl_settings)
+        reload(urlresolvers)
+
+    def tearDown(self):
+        self.settings_manager.revert()
+        reload(localeurl_settings)
+        reload(urlresolvers)
+
+
+class UtilsTestCase(LocaleurlTestCase):
+
+    def test_is_locale_independent(self):
+        self.assertFalse(utils.is_locale_independent('/fr/about'))
+        self.assertFalse(utils.is_locale_independent('/about'))
+        self.assertTrue(utils.is_locale_independent('/media/img/logo.png'))
+        self.assertTrue(utils.is_locale_independent('/'))
+        self.assertTrue(utils.is_locale_independent(
+                '/test/independent/bla/bla'))
+
+    def test_strip_path(self):
+        self.assertEqual(('', '/'), utils.strip_path('/'))
+        self.assertEqual(('', '/about/'), utils.strip_path('/about/'))
+        self.assertEqual(('', '/about/localeurl/'),
+                utils.strip_path('/about/localeurl/'))
+        self.assertEqual(('fr', '/about/localeurl/'),
+                utils.strip_path('/fr/about/localeurl/'))
+        self.assertEqual(('nl-be', '/about/localeurl/'),
+                utils.strip_path('/nl-be/about/localeurl/'))
+        self.assertEqual(('', '/de/about/localeurl/'),
+                utils.strip_path('/de/about/localeurl/'))
+
+    def test_supported_language(self):
+        self.assertEqual('fr', utils.supported_language('fr'))
+        self.assertEqual('nl-be', utils.supported_language('nl-be'))
+        self.assertEqual('en', utils.supported_language('en-gb'))
+        self.assertEqual(None, utils.supported_language('de'))
+
+    def test_is_default_locale(self):
+        self.assertTrue(utils.is_default_locale('en'))
+        self.assertFalse(utils.is_default_locale('en-gb'))
+        self.assertFalse(utils.is_default_locale('fr'))
+        self.assertFalse(utils.is_default_locale('de'))
+
+    def test_locale_path(self):
+        self.assertEqual('/en/about/localeurl/',
+                utils.locale_path('/about/localeurl/'))
+        self.assertEqual('/en/about/localeurl/',
+                utils.locale_path('/about/localeurl/', 'de'))
+        self.assertEqual('/en/about/localeurl/',
+                utils.locale_path('/about/localeurl/', 'en'))
+        self.assertEqual('/en/about/localeurl/',
+                utils.locale_path('/about/localeurl/', 'en-us'))
+        self.assertEqual('/nl-nl/about/localeurl/',
+                utils.locale_path('/about/localeurl/', 'nl-nl'))
+        self.assertEqual('/test/independent/bla/bla',
+                utils.locale_path('/test/independent/bla/bla', 'en'))
+
+    def test_locale_url(self):
+        # We'd like to be able to test using settings.FORCE_SCRIPT_NAME, but
+        # the urlresolvers module caches the prefix.
+        script_name = urlresolvers.get_script_prefix()
+        self.assertEqual(script_name + 'en/about/localeurl/',
+                utils.locale_url('/about/localeurl/'))
+        self.assertEqual(script_name + 'en/about/localeurl/',
+                utils.locale_url('/about/localeurl/', 'de'))
+        self.assertEqual(script_name + 'en/about/localeurl/',
+                utils.locale_url('/about/localeurl/', 'en'))
+        self.assertEqual(script_name + 'en/about/localeurl/',
+                utils.locale_url('/about/localeurl/', 'en-us'))
+        self.assertEqual(script_name + 'nl-nl/about/localeurl/',
+                utils.locale_url('/about/localeurl/', 'nl-nl'))
+        self.assertEqual(script_name + 'test/independent/bla/bla',
+                utils.locale_path('/test/independent/bla/bla', 'en'))
+
+
+class MiddlewareTestCase(LocaleurlTestCase):
+    def setUp(self):
+        super(MiddlewareTestCase, self).setUp()
+        self.request_factory = test_utils.RequestFactory()
+        self.middleware = middleware.LocaleURLMiddleware()
+
+    def test_with_locale(self):
+        r1 = self.request_factory.get('/fr/test/')
+        r2 = self.middleware.process_request(r1)
+        self.assertEqual(None, r2)
+        self.assertEqual('fr', r1.LANGUAGE_CODE)
+        self.assertEqual('/test/', r1.path_info)
+
+    def test_with_sublocale(self):
+        r1 = self.request_factory.get('/nl-nl/test/bla/bla/')
+        r2 = self.middleware.process_request(r1)
+        self.assertEqual(None, r2)
+        self.assertEqual('nl-nl', r1.LANGUAGE_CODE)
+        self.assertEqual('/test/bla/bla/', r1.path_info)
+
+    def test_locale_independent_url(self):
+        r1 = self.request_factory.get('/test/independent/bla/bla/')
+        r2 = self.middleware.process_request(r1)
+        self.assertEqual(None, r2)
+        self.assertEqual('en-gb', r1.LANGUAGE_CODE)
+        self.assertEqual('/test/independent/bla/bla/', r1.path_info)
+
+    def test_locale_specified_on_independent_url_with_query_string(self):
+        r1 = self.request_factory.get('/nl-be/test/independent/?foo=bar')
+        r2 = self.middleware.process_request(r1)
+        self.assertEqual(301, r2.status_code)
+        self.assertEqual('/test/independent/?foo=bar', r2['Location'])
+
+    def test_check_accept_lang(self):
+        self.settings_manager.set(LOCALEURL_USE_ACCEPT_LANGUAGE=True)
+        reload(localeurl_settings)
+
+        r1 = self.request_factory.get('/test/', HTTP_ACCEPT_LANGUAGE='fr, de;q=0.8')
+        r2 = self.middleware.process_request(r1)
+        self.assertEqual(301, r2.status_code)
+        self.assertEqual('/fr/test/', r2['Location'])
+
+class DefaultPrefixMiddlewareTestCase(MiddlewareTestCase):
+    def setUp(self):
+        super(DefaultPrefixMiddlewareTestCase, self).setUp()
+
+    def test_no_locale(self):
+        r1 = self.request_factory.get('/test/')
+        r2 = self.middleware.process_request(r1)
+        self.assertEqual(301, r2.status_code)
+        self.assertEqual('/en/test/', r2['Location'])
+        
+    def test_with_query_string(self):
+        r1 = self.request_factory.get('/test/?somevar=someval')
+        r2 = self.middleware.process_request(r1)
+        self.assertEqual(301, r2.status_code)
+        self.assertEqual('/en/test/?somevar=someval', r2['Location'])
+
+class NoDefaultPrefixMiddlewareTestCase(MiddlewareTestCase):
+    def setUp(self):
+        super(NoDefaultPrefixMiddlewareTestCase, self).setUp()
+        self.settings_manager.set(PREFIX_DEFAULT_LOCALE=False)
+        reload(localeurl_settings)
+        
+    def test_default_locale(self):
+        r1 = self.request_factory.get('/test/foo/')
+        r2 = self.middleware.process_request(r1)
+        self.assertEqual(None, r2)
+        self.assertEqual('en-gb', r1.LANGUAGE_CODE)
+        self.assertEqual('/test/foo/', r1.path_info)
+
+    def test_default_locale_specified(self):
+        r1 = self.request_factory.get('/en/test/foo/')
+        r2 = self.middleware.process_request(r1)
+        self.assertEqual(301, r2.status_code)
+        self.assertEqual('/test/foo/', r2['Location'])
+
+    def test_alternate_locale(self):
+        r1 = self.request_factory.get('/fr/test/foo/')
+        r2 = self.middleware.process_request(r1)
+        self.assertEqual(None, r2)
+        self.assertEqual('fr', r1.LANGUAGE_CODE)
+        self.assertEqual('/test/foo/', r1.path_info)
+
+
+class TagsTestCase(LocaleurlTestCase):
+    def render_template(self, text):
+        t = test_utils.TestTemplate(text, libraries=[localeurl_tags.register])
+        c = template.Context()
+        return t.render(c)
+
+    def test_locale_url_tag(self):
+        self.assertRaises(ValueError, self.render_template,
+                '{% locale_url "nl" dummy0 %}')
+
+        self.assertEqual('/en/dummy/', self.render_template(
+                '{% locale_url "en-us" dummy0 %}'))
+
+        self.assertEqual('/fr/dummy/4', self.render_template(
+            '{% locale_url "fr" dummy1 test=4 %}'))
+
+        self.assertEqual('/en/dummy/4', self.render_template(
+            '{% locale_url "en" dummy1 test=4 as testvar %}{{ testvar }}'))
+
+    def test_chlocale_filter(self):
+        self.assertEqual('/fr/dummy/', self.render_template(
+                '{{ "/dummy/"|chlocale:"fr" }}'))
+
+        self.assertEqual('/en/dummy/', self.render_template(
+                '{{"/fr/dummy/"|chlocale:"en-gb"}}'))
+
+    def test_rmlocale_filter(self):
+        self.assertEqual('/dummy/', self.render_template(
+                '{{ "/dummy/"|rmlocale }}'))
+
+        self.assertEqual('/dummy/', self.render_template(
+                '{{ "/nl-be/dummy/"|rmlocale }}'))
+
+        self.assertEqual('/dummy/', self.render_template(
+                '{{ "/en/dummy/"|rmlocale }}'))
+
+    def test_locale_url_tag_no_default_prefix(self):
+        self.settings_manager.set(PREFIX_DEFAULT_LOCALE=False)
+        reload(localeurl_settings)
+
+        self.assertEqual('/dummy/', self.render_template(
+                '{% locale_url "en-us" dummy0 %}'))
+
+        self.assertEqual('/fr/dummy/', self.render_template(
+            '{% locale_url "fr" dummy0 %}'))
+
+    def test_chlocale_filter_no_default_prefix(self):
+        self.settings_manager.set(PREFIX_DEFAULT_LOCALE=False)
+        reload(localeurl_settings)
+
+        self.assertEqual('/dummy/', self.render_template(
+                '{{ "/nl-nl/dummy/"|chlocale:"en-gb" }}'))
+
+        self.assertEqual('/fr/dummy/', self.render_template(
+                '{{"/nl-nl/dummy/"|chlocale:"fr"}}'))
+
+class DummyModel(object):
+    def __init__(self, num):
+        self.num = num
+
+    def get_absolute_url(self):
+        return '/dummy/%s/' % self.num
+
+class DummySitemap(LocaleurlSitemap):
+    def items(self):
+        return [DummyModel(i) for i in range(3)]
+
+class SitemapTestCase(LocaleurlTestCase):
+    def setUp(self):
+        super(SitemapTestCase, self).setUp()
+        class DummySite(object):
+            domain = 'www.example.com'
+        from django.contrib.sites.models import Site
+        self._orig_get_current = Site.objects.get_current
+        Site.objects.get_current = lambda: DummySite()
+    
+    def test_localeurl_sitemap(self):
+        sitemap = DummySitemap('fr')
+        self.assertEqual(sitemap.get_urls()[0]['location'],
+                         'http://www.example.com/fr/dummy/0/')
+
+    def tearDown(self):
+        super(SitemapTestCase, self).tearDown()
+        from django.contrib.sites.models import Site
+        Site.objects.get_current = self._orig_get_current

localeurl/tests/test_settings.py

+"""
+Test settings.
+"""
+
+DATABASE_ENGINE = 'sqlite3'
+DATABASE_NAME = ':memory:'
+
+SITE_ID = 1
+
+ROOT_URLCONF = 'localeurl.tests.test_urls'
+
+INSTALLED_APPS = (
+    'localeurl',
+)

localeurl/tests/test_urls.py

+"""
+URLconf for testing.
+"""
+
+from django.conf.urls.defaults import *
+
+urlpatterns = patterns('localeurl.tests.test_urls',
+     url(r'^dummy/$', 'dummy', name='dummy0'),
+     url(r'^dummy/(?P<test>.+)$', 'dummy', name='dummy1'),
+)
+
+def dummy(request, test='test'):
+    pass

localeurl/tests/test_utils.py

+"""
+Test settings manager, originally copied from a `Django snippet`_ by 'carljm'.
+
+.. _`Django snippet`: http://www.djangosnippets.org/snippets/1011/
+"""
+
+from django.conf import settings as django_settings
+from django.core.handlers.wsgi import WSGIRequest
+from django.core.management import call_command
+from django.db.models import loading
+from django import template
+from django.test import Client
+from django.utils import encoding
+
+
+NO_SETTING = object()
+
+class TestSettingsManager(object):
+    """
+    A class which can modify some Django settings temporarily for a
+    test and then revert them to their original values later.
+
+    Automatically handles resyncing the DB if INSTALLED_APPS is
+    modified.
+
+    Based on the work by 'carljm':
+    http://www.djangosnippets.org/snippets/1011/
+    """
+    def __init__(self, settings=django_settings):
+        self._settings = settings
+        self._original_settings = {}
+
+    def set(self, **kwargs):
+        self.set_from_dict(kwargs)
+
+    def set_from_dict(self, settings):
+        for k,v in settings.iteritems():
+            self._original_settings.setdefault(k,
+                    getattr(self._settings, k, NO_SETTING))
+            setattr(self._settings, k, v)
+        if 'INSTALLED_APPS' in settings:
+            self.syncdb()
+
+    def syncdb(self):
+        loading.cache.loaded = False
+        call_command('syncdb', verbosity=0)
+
+    def revert(self):
+        for k,v in self._original_settings.iteritems():
+            if v == NO_SETTING:
+                try:
+                    delattr(self._settings, k)
+                except AttributeError:
+                    # Django < r11825
+                    delattr(self._settings._wrapped, k)
+            else:
+                setattr(self._settings, k, v)
+        if self._settings == django_settings \
+                and 'INSTALLED_APPS' in self._original_settings:
+            self.syncdb()
+        self._original_settings = {}
+
+
+class RequestFactory(Client):
+    """
+    Class that lets you create mock Request objects for use in testing.
+
+    Usage:
+
+    rf = RequestFactory()
+    get_request = rf.get('/hello/')
+    post_request = rf.post('/submit/', {'foo': 'bar'})
+
+    This class re-uses the django.test.client.Client interface, docs here:
+    http://www.djangoproject.com/documentation/testing/#the-test-client
+
+    Once you have a request object you can pass it to any view function,
+    just as if that view had been hooked up using a URLconf.
+
+    Based on the work by Simon Willison:
+    http://www.djangosnippets.org/snippets/963/
+    """
+    def request(self, **request):
+        """
+        Similar to parent class, but returns the request object as soon as it
+        has created it.
+        """
+        environ = {
+            'HTTP_COOKIE': self.cookies,
+            'PATH_INFO': '/',
+            'QUERY_STRING': '',
+            'REQUEST_METHOD': 'GET',
+            'SCRIPT_NAME': '',
+            'SERVER_NAME': 'testserver',
+            'SERVER_PORT': 80,
+            'SERVER_PROTOCOL': 'HTTP/1.1',
+        }
+        environ.update(self.defaults)
+        environ.update(request)
+        return WSGIRequest(environ)
+
+
+class TestTemplate(template.Template):
+    """
+    TestTemplate behaves just like django.template.Template, but you can give
+    it a list of template.Libraries to load before parsing the template. This
+    is equivalent to adding a bunch of {% load %} tags to the beginning of your
+    template string, but you can use custom tag libraries which do not belong
+    to Django applications' templatetags packages.
+
+    Based on the work by Alexander Khodyrev:
+    http://www.djangosnippets.org/snippets/1641/
+    """
+    def __init__(self, template_string, name='<Unknown Template>',
+            libraries=[]):
+        try:
+            template_string = encoding.smart_unicode(template_string)
+        except UnicodeDecodeError:
+            raise template.TemplateEncodingError(
+                    "template content must be unicode or UTF-8 string")
+        origin = template.StringOrigin(template_string)
+        self.nodelist = self.my_compile_string(template_string, origin,
+                libraries)
+        self.name = name
+
+    def my_compile_string(self, template_string, origin, libraries=[]):
+        "Compiles template_string into NodeList ready for rendering"
+        lexer = template.Lexer(template_string, origin)
+        parser = template.Parser(lexer.tokenize())
+        for lib in libraries:
+            parser.add_library(lib)
+        return parser.parse()

localeurl/utils.py

 from django.conf import settings
 from django.core import urlresolvers
 from django.core import urlresolvers
-import localeurl
+from localeurl import settings as localeurl_settings
 
 def is_locale_independent(path):
     """
     Returns whether the path is locale-independent.
     """
-    if localeurl.LOCALE_INDEPENDENT_MEDIA_URL and settings.MEDIA_URL \
+    if localeurl_settings.LOCALE_INDEPENDENT_MEDIA_URL and settings.MEDIA_URL \
             and path.startswith(settings.MEDIA_URL):
         return True
-    for regex in localeurl.LOCALE_INDEPENDENT_PATHS:
+    for regex in localeurl_settings.LOCALE_INDEPENDENT_PATHS:
         if regex.search(path):
             return True
     return False
     Separates the locale prefix from the rest of the path. If the path does not
     begin with a locale it is returned without change.
     """
-    check = localeurl.PATH_RE.match(path)
+    check = localeurl_settings.PATH_RE.match(path)
     if check:
         path_info = check.group('path') or '/'
         if path_info.startswith('/'):
     """
     Returns the supported language (from settings.LANGUAGES) for the locale.
     """
-    if locale in localeurl.SUPPORTED_LOCALES:
+    if locale in localeurl_settings.SUPPORTED_LOCALES:
         return locale
-    elif locale[:2] in localeurl.SUPPORTED_LOCALES:
+    elif locale[:2] in localeurl_settings.SUPPORTED_LOCALES:
         return locale[:2]
     else:
         return None
         locale = supported_language(settings.LANGUAGE_CODE)
     if is_locale_independent(path):
         return path
-    elif is_default_locale(locale) and not localeurl.PREFIX_DEFAULT_LOCALE:
+    elif is_default_locale(locale) and not localeurl_settings.PREFIX_DEFAULT_LOCALE:
         return path
     else:
         return ''.join([u'/', locale, path])