diff --git a/django/test/testcases.py b/django/test/testcases.py
index 4c32c87..df75374 100644
a
|
b
|
from contextlib import contextmanager
|
9 | 9 | from copy import copy |
10 | 10 | from functools import wraps |
11 | 11 | from unittest.util import safe_repr |
12 | | from urllib.parse import unquote, urljoin, urlparse, urlsplit |
| 12 | from urllib.parse import ( |
| 13 | parse_qsl, unquote, urlencode, urljoin, urlparse, urlsplit, urlunparse, |
| 14 | ) |
13 | 15 | from urllib.request import url2pathname |
14 | 16 | |
15 | 17 | from django.apps import apps |
… |
… |
class SimpleTestCase(unittest.TestCase):
|
240 | 242 | |
241 | 243 | def assertRedirects(self, response, expected_url, status_code=302, |
242 | 244 | target_status_code=200, msg_prefix='', |
243 | | fetch_redirect_response=True): |
| 245 | fetch_redirect_response=True, strict_query_order=False): |
244 | 246 | """ |
245 | 247 | Assert that a response redirected to a specific URL and that the |
246 | 248 | redirect URL can be loaded. |
… |
… |
class SimpleTestCase(unittest.TestCase):
|
248 | 250 | Won't work for external links since it uses the test client to do a |
249 | 251 | request (use fetch_redirect_response=False to check such links without |
250 | 252 | fetching them). |
| 253 | |
| 254 | By default, the order of the querystring part of the url doesn't matter, |
| 255 | if you you rely on the exact ordering of the querystring, use |
| 256 | strict_query_order=True. |
251 | 257 | """ |
252 | 258 | if msg_prefix: |
253 | 259 | msg_prefix += ": " |
… |
… |
class SimpleTestCase(unittest.TestCase):
|
313 | 319 | % (path, redirect_response.status_code, target_status_code) |
314 | 320 | ) |
315 | 321 | |
| 322 | if not strict_query_order: |
| 323 | def normalize(url): |
| 324 | scheme, netloc, path, params, query, fragment = urlparse(url) |
| 325 | query_parts = sorted(parse_qsl(query), key=lambda o: o[0]) |
| 326 | return urlunparse((scheme, netloc, path, params, urlencode(query_parts), fragment)) |
| 327 | |
| 328 | url, expected_url = normalize(url), normalize(expected_url) |
| 329 | |
316 | 330 | self.assertEqual( |
317 | 331 | url, expected_url, |
318 | 332 | msg_prefix + "Response redirected to '%s', expected '%s'" % (url, expected_url) |
diff --git a/tests/test_client/tests.py b/tests/test_client/tests.py
index f7d32aa..1343dd6 100644
a
|
b
|
class ClientTest(TestCase):
|
167 | 167 | response = self.client.get('/redirect_view/', {'var': 'value'}) |
168 | 168 | self.assertRedirects(response, '/get_view/?var=value') |
169 | 169 | |
| 170 | def test_redirect_with_query_ordering(self): |
| 171 | "GET a URL with two GET paramameters allow both querystring orderings" |
| 172 | response = self.client.get('/redirect_view/', {'var': 'value', 'foo': 'bar'}) |
| 173 | self.assertRedirects(response, '/get_view/?var=value&foo=bar') |
| 174 | self.assertRedirects(response, '/get_view/?foo=bar&var=value') |
| 175 | |
| 176 | with self.assertRaises(AssertionError): |
| 177 | self.assertRedirects(response, '/get_view/?foo=bar&var=value', strict_query_order=True) |
| 178 | |
170 | 179 | def test_permanent_redirect(self): |
171 | 180 | "GET a URL that redirects permanently elsewhere" |
172 | 181 | response = self.client.get('/permanent_redirect_view/') |