Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Handle parse_accept_lang_header error #53

Merged
merged 1 commit into from

4 participants

Josh Mize Michael Kelly Kumar McMillan Andy McKay
Josh Mize
Owner

Handle bug described in https://code.djangoproject.com/ticket/21078
The fix has been merged into the Django master branch, but won't be in
a Django release for some time.

Also added test coverage for funfactory.urlresolvers.Prefix class.

Josh Mize
Owner

@Osmose r?

tests/test_urlresolvers.py
@@ -54,3 +57,102 @@ def test_unicode_url(self, get_url_prefix):
# Ensure that UTF-8 characters are escaped properly.
self.assertEqual(result, '/Fran%C3%A7oi/test/')
self.assertEqual(type(result), str)
+
+
+class TestPrefixer(TestCase):
+ def setUp(self):
+ self.factory = RequestFactory()
+
+ @override_settings(LANGUAGE_CODE='en-US')
+ def test_get_language_default_language_code(self):
+ """
+ Should return default set by settings.LANGUAGE_CODE
Michael Kelly Owner
Osmose added a note

Nitpicking: The docstrings could be a bit more descriptive, something like "If there's no lang param or HTTP_ACCEPT_LANGUAGE header, return settings.LANGUAGE_CODE."

Andy McKay Owner

That's a really annoying side effect of nose tests. I would just turn it off by putting this in your test case base class:

https://github.com/mozilla/zamboni/blob/master/apps/amo/tests/__init__.py#L237-L239

Kumar McMillan Owner

or you could run tests with nicedots https://github.com/kumar303/nose-nicedots

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
tests/test_urlresolvers.py
((24 lines not shown))
+ Should return param value
+ """
+ request = self.factory.get('/?lang=de')
+ ok_('lang' in request.GET)
+ ok_('de' in settings.LANGUAGE_URL_MAP)
+ prefixer = Prefixer(request)
+ eq_(prefixer.get_language(), 'de')
+
+ @override_settings(LANGUAGE_CODE='en-US',
+ LANGUAGE_URL_MAP={'en-us': 'en-US'})
+ def test_get_language_invalid_lang_param(self):
+ """
+ Should return default set by settings.LANGUAGE_CODE
+ """
+ request = self.factory.get('/?lang=de')
+ ok_('lang' in request.GET)
Michael Kelly Owner
Osmose added a note

Might be more useful to assert that lang is de, although the line above is pretty clear that that's the case, so the assertions might be excessive anyway.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Michael Kelly
Owner

r+, it's pretty much all nits. I really like the idea of asserting that the tests are set up correctly too.

Nice work! :baby_chick:

Kumar McMillan kumar303 commented on the diff
funfactory/urlresolvers.py
@@ -98,16 +98,18 @@ def get_best_language(self, accept_lang):
langs = dict(LUM)
langs.update((k.split('-')[0], v) for k, v in LUM.items() if
k.split('-')[0] not in langs)
- ranked = parse_accept_lang_header(accept_lang)
- for lang, _ in ranked:
- lang = lang.lower()
- if lang in langs:
- return langs[lang]
- pre = lang.split('-')[0]
- if pre in langs:
- return langs[pre]
- # Could not find an acceptable language.
- return False
Kumar McMillan Owner

I'm not sure if anything was relying on return False but maybe you should add it back in just in case

Josh Mize Owner
jgmize added a note

The only thing I could find that used it was the get_language method in the same class, which was only dependent on it being falsey, and any other libraries that use get_best_language directly should still work just fine as long as they aren't using the "is False" antipattern.

Kumar McMillan Owner

ok, None works for me

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Josh Mize jgmize Handle parse_accept_lang_header error
Handle bug described in https://code.djangoproject.com/ticket/21078
The fix has been merged into the Django master branch, but won't be in
a Django release for some time.

Also added test coverage for funfactory.urlresolvers.Prefix class.
358a5d9
Josh Mize
Owner

Thanks for the feedback. I've amended the commit based on it.

Michael Kelly
Owner

arrplus, merge at your leisure

Josh Mize jgmize merged commit 1ad0eb2 into from
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Sep 10, 2013
  1. Josh Mize

    Handle parse_accept_lang_header error

    jgmize authored
    Handle bug described in https://code.djangoproject.com/ticket/21078
    The fix has been merged into the Django master branch, but won't be in
    a Django release for some time.
    
    Also added test coverage for funfactory.urlresolvers.Prefix class.
This page is out of date. Refresh to see the latest.
Showing with 123 additions and 13 deletions.
  1. +12 −10 funfactory/urlresolvers.py
  2. +111 −3 tests/test_urlresolvers.py
22 funfactory/urlresolvers.py
View
@@ -98,16 +98,18 @@ def get_best_language(self, accept_lang):
langs = dict(LUM)
langs.update((k.split('-')[0], v) for k, v in LUM.items() if
k.split('-')[0] not in langs)
- ranked = parse_accept_lang_header(accept_lang)
- for lang, _ in ranked:
- lang = lang.lower()
- if lang in langs:
- return langs[lang]
- pre = lang.split('-')[0]
- if pre in langs:
- return langs[pre]
- # Could not find an acceptable language.
- return False
Kumar McMillan Owner

I'm not sure if anything was relying on return False but maybe you should add it back in just in case

Josh Mize Owner
jgmize added a note

The only thing I could find that used it was the get_language method in the same class, which was only dependent on it being falsey, and any other libraries that use get_best_language directly should still work just fine as long as they aren't using the "is False" antipattern.

Kumar McMillan Owner

ok, None works for me

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ try:
+ ranked = parse_accept_lang_header(accept_lang)
+ except ValueError: # see https://code.djangoproject.com/ticket/21078
+ return
+ else:
+ for lang, _ in ranked:
+ lang = lang.lower()
+ if lang in langs:
+ return langs[lang]
+ pre = lang.split('-')[0]
+ if pre in langs:
+ return langs[pre]
def fix(self, path):
path = path.lstrip('/')
114 tests/test_urlresolvers.py
View
@@ -1,10 +1,13 @@
# -*- coding: utf-8 -*-
+from django.conf import settings
from django.conf.urls.defaults import patterns, url
from django.test import TestCase
+from django.test.client import RequestFactory
+from django.test.utils import override_settings
-from funfactory.urlresolvers import reverse, split_path
-from mock import patch
-from nose.tools import eq_
+from funfactory.urlresolvers import reverse, split_path, Prefixer
+from mock import patch, Mock
+from nose.tools import eq_, ok_
# split_path tests use a test generator, which cannot be used inside of a
@@ -54,3 +57,108 @@ def test_unicode_url(self, get_url_prefix):
# Ensure that UTF-8 characters are escaped properly.
self.assertEqual(result, '/Fran%C3%A7oi/test/')
self.assertEqual(type(result), str)
+
+
+class TestPrefixer(TestCase):
+ def setUp(self):
+ self.factory = RequestFactory()
+
+ @override_settings(LANGUAGE_CODE='en-US')
+ def test_get_language_default_language_code(self):
+ """
+ Should return default set by settings.LANGUAGE_CODE if no 'lang'
+ url parameter and no Accept-Language header
+ """
+ request = self.factory.get('/')
+ self.assertFalse('lang' in request.GET)
+ self.assertFalse(request.META.get('HTTP_ACCEPT_LANGUAGE'))
+ prefixer = Prefixer(request)
+ eq_(prefixer.get_language(), 'en-US')
+
+ @override_settings(LANGUAGE_URL_MAP={'en-us': 'en-US', 'de': 'de'})
+ def test_get_language_valid_lang_param(self):
+ """
+ Should return lang param value if it is in settings.LANGUAGE_URL_MAP
+ """
+ request = self.factory.get('/?lang=de')
+ eq_(request.GET.get('lang'), 'de')
+ ok_('de' in settings.LANGUAGE_URL_MAP)
+ prefixer = Prefixer(request)
+ eq_(prefixer.get_language(), 'de')
+
+ @override_settings(LANGUAGE_CODE='en-US',
+ LANGUAGE_URL_MAP={'en-us': 'en-US'})
+ def test_get_language_invalid_lang_param(self):
+ """
+ Should return default set by settings.LANGUAGE_CODE if lang
+ param value is not in settings.LANGUAGE_URL_MAP
+ """
+ request = self.factory.get('/?lang=de')
+ ok_('lang' in request.GET)
+ self.assertFalse('de' in settings.LANGUAGE_URL_MAP)
+ prefixer = Prefixer(request)
+ eq_(prefixer.get_language(), 'en-US')
+
+ def test_get_language_returns_best(self):
+ """
+ Should pass Accept-Language header value to get_best_language
+ and return result
+ """
+ request = self.factory.get('/')
+ request.META['HTTP_ACCEPT_LANGUAGE'] = 'de, es'
+ prefixer = Prefixer(request)
+ prefixer.get_best_language = Mock(return_value='de')
+ eq_(prefixer.get_language(), 'de')
+ prefixer.get_best_language.assert_called_once_with('de, es')
+
+ @override_settings(LANGUAGE_CODE='en-US')
+ def test_get_language_no_best(self):
+ """
+ Should return default set by settings.LANGUAGE_CODE if
+ get_best_language return value is None
+ """
+ request = self.factory.get('/')
+ request.META['HTTP_ACCEPT_LANGUAGE'] = 'de, es'
+ prefixer = Prefixer(request)
+ prefixer.get_best_language = Mock(return_value=None)
+ eq_(prefixer.get_language(), 'en-US')
+ prefixer.get_best_language.assert_called_once_with('de, es')
+
+ @override_settings(LANGUAGE_URL_MAP={'en-us': 'en-US', 'de': 'de'})
+ def test_get_best_language_exact_match(self):
+ """
+ Should return exact match if it is in settings.LANGUAGE_URL_MAP
+ """
+ request = self.factory.get('/')
+ prefixer = Prefixer(request)
+ eq_(prefixer.get_best_language('de, es'), 'de')
+
+ @override_settings(LANGUAGE_URL_MAP={'en-us': 'en-US', 'es-ar': 'es-AR'})
+ def test_get_best_language_prefix_match(self):
+ """
+ Should return a language with a matching prefix from
+ settings.LANGUAGE_URL_MAP if it exists but no exact match does
+ """
+ request = self.factory.get('/')
+ prefixer = Prefixer(request)
+ eq_(prefixer.get_best_language('es-CL'), 'es-AR')
+
+ @override_settings(LANGUAGE_URL_MAP={'en-us': 'en-US'})
+ def test_get_best_language_no_match(self):
+ """
+ Should return None if there is no exact match or matching
+ prefix
+ """
+ request = self.factory.get('/')
+ prefixer = Prefixer(request)
+ eq_(prefixer.get_best_language('de'), None)
+
+ @override_settings(LANGUAGE_URL_MAP={'en-us': 'en-US'})
+ def test_get_best_language_handles_parse_accept_lang_header_error(self):
+ """
+ Should return None despite error raised by bug described in
+ https://code.djangoproject.com/ticket/21078
+ """
+ request = self.factory.get('/')
+ prefixer = Prefixer(request)
+ eq_(prefixer.get_best_language('en; q=1,'), None)
Something went wrong with that request. Please try again.