2014-04-20 17:12:43 +00:00
# -*- coding: utf-8 -*-
2008-08-31 11:11:20 +00:00
"""
Unit tests for reverse URL lookups .
"""
2013-07-29 17:19:04 +00:00
from __future__ import unicode_literals
2011-10-13 21:34:56 +00:00
2014-04-20 17:12:43 +00:00
import sys
2013-07-01 12:22:27 +00:00
import unittest
2014-06-03 11:30:14 +00:00
import warnings
2013-07-01 12:22:27 +00:00
2012-09-07 17:17:09 +00:00
from django . contrib . auth . models import User
2014-04-05 06:04:46 +00:00
from django . conf import settings
2011-06-16 16:41:14 +00:00
from django . core . exceptions import ImproperlyConfigured , ViewDoesNotExist
2013-09-06 18:43:58 +00:00
from django . core . urlresolvers import ( reverse , reverse_lazy , resolve , get_callable ,
2012-09-01 20:07:18 +00:00
get_resolver , NoReverseMatch , Resolver404 , ResolverMatch , RegexURLResolver ,
2012-08-14 19:12:08 +00:00
RegexURLPattern )
2013-03-10 22:24:34 +00:00
from django . http import HttpRequest , HttpResponseRedirect , HttpResponsePermanentRedirect
2009-03-21 13:09:13 +00:00
from django . shortcuts import redirect
2013-12-23 15:01:13 +00:00
from django . test import TestCase , override_settings
2013-07-01 12:22:27 +00:00
from django . utils import six
2014-06-03 11:30:14 +00:00
from django . utils . deprecation import RemovedInDjango20Warning
2006-07-28 02:08:36 +00:00
2014-02-18 09:19:04 +00:00
from admin_scripts . tests import AdminScriptTestCase
2012-09-07 17:17:09 +00:00
from . import urlconf_outer , middleware , views
2013-11-01 20:15:41 +00:00
from . views import empty_view
2011-10-13 21:34:56 +00:00
2010-08-05 07:09:47 +00:00
resolve_test_data = (
2013-10-03 07:20:04 +00:00
# These entries are in the format: (path, url_name, app_name, namespace, view_name, func, args, kwargs)
2010-08-05 07:09:47 +00:00
# Simple case
2013-10-03 07:20:04 +00:00
( ' /normal/42/37/ ' , ' normal-view ' , None , ' ' , ' normal-view ' , views . empty_view , tuple ( ) , { ' arg1 ' : ' 42 ' , ' arg2 ' : ' 37 ' } ) ,
( ' /view_class/42/37/ ' , ' view-class ' , None , ' ' , ' view-class ' , views . view_class_instance , tuple ( ) , { ' arg1 ' : ' 42 ' , ' arg2 ' : ' 37 ' } ) ,
( ' /included/normal/42/37/ ' , ' inc-normal-view ' , None , ' ' , ' inc-normal-view ' , views . empty_view , tuple ( ) , { ' arg1 ' : ' 42 ' , ' arg2 ' : ' 37 ' } ) ,
( ' /included/view_class/42/37/ ' , ' inc-view-class ' , None , ' ' , ' inc-view-class ' , views . view_class_instance , tuple ( ) , { ' arg1 ' : ' 42 ' , ' arg2 ' : ' 37 ' } ) ,
2010-08-05 07:09:47 +00:00
# Unnamed args are dropped if you have *any* kwargs in a pattern
2013-10-03 07:20:04 +00:00
( ' /mixed_args/42/37/ ' , ' mixed-args ' , None , ' ' , ' mixed-args ' , views . empty_view , tuple ( ) , { ' arg2 ' : ' 37 ' } ) ,
( ' /included/mixed_args/42/37/ ' , ' inc-mixed-args ' , None , ' ' , ' inc-mixed-args ' , views . empty_view , tuple ( ) , { ' arg2 ' : ' 37 ' } ) ,
2010-08-05 07:09:47 +00:00
2013-10-03 07:20:04 +00:00
# Unnamed views should have None as the url_name. Regression data for #21157.
( ' /unnamed/normal/42/37/ ' , None , None , ' ' , ' urlpatterns_reverse.views.empty_view ' , views . empty_view , tuple ( ) , { ' arg1 ' : ' 42 ' , ' arg2 ' : ' 37 ' } ) ,
( ' /unnamed/view_class/42/37/ ' , None , None , ' ' , ' urlpatterns_reverse.views.ViewClass ' , views . view_class_instance , tuple ( ) , { ' arg1 ' : ' 42 ' , ' arg2 ' : ' 37 ' } ) ,
2010-08-06 13:47:56 +00:00
2010-08-05 07:09:47 +00:00
# If you have no kwargs, you get an args list.
2013-10-03 07:20:04 +00:00
( ' /no_kwargs/42/37/ ' , ' no-kwargs ' , None , ' ' , ' no-kwargs ' , views . empty_view , ( ' 42 ' , ' 37 ' ) , { } ) ,
( ' /included/no_kwargs/42/37/ ' , ' inc-no-kwargs ' , None , ' ' , ' inc-no-kwargs ' , views . empty_view , ( ' 42 ' , ' 37 ' ) , { } ) ,
2010-08-05 07:09:47 +00:00
# Namespaces
2013-10-03 07:20:04 +00:00
( ' /test1/inner/42/37/ ' , ' urlobject-view ' , ' testapp ' , ' test-ns1 ' , ' test-ns1:urlobject-view ' , views . empty_view , tuple ( ) , { ' arg1 ' : ' 42 ' , ' arg2 ' : ' 37 ' } ) ,
( ' /included/test3/inner/42/37/ ' , ' urlobject-view ' , ' testapp ' , ' test-ns3 ' , ' test-ns3:urlobject-view ' , views . empty_view , tuple ( ) , { ' arg1 ' : ' 42 ' , ' arg2 ' : ' 37 ' } ) ,
( ' /ns-included1/normal/42/37/ ' , ' inc-normal-view ' , None , ' inc-ns1 ' , ' inc-ns1:inc-normal-view ' , views . empty_view , tuple ( ) , { ' arg1 ' : ' 42 ' , ' arg2 ' : ' 37 ' } ) ,
( ' /included/test3/inner/42/37/ ' , ' urlobject-view ' , ' testapp ' , ' test-ns3 ' , ' test-ns3:urlobject-view ' , views . empty_view , tuple ( ) , { ' arg1 ' : ' 42 ' , ' arg2 ' : ' 37 ' } ) ,
( ' /default/inner/42/37/ ' , ' urlobject-view ' , ' testapp ' , ' testapp ' , ' testapp:urlobject-view ' , views . empty_view , tuple ( ) , { ' arg1 ' : ' 42 ' , ' arg2 ' : ' 37 ' } ) ,
( ' /other2/inner/42/37/ ' , ' urlobject-view ' , ' nodefault ' , ' other-ns2 ' , ' other-ns2:urlobject-view ' , views . empty_view , tuple ( ) , { ' arg1 ' : ' 42 ' , ' arg2 ' : ' 37 ' } ) ,
( ' /other1/inner/42/37/ ' , ' urlobject-view ' , ' nodefault ' , ' other-ns1 ' , ' other-ns1:urlobject-view ' , views . empty_view , tuple ( ) , { ' arg1 ' : ' 42 ' , ' arg2 ' : ' 37 ' } ) ,
2010-08-05 07:09:47 +00:00
# Nested namespaces
2013-10-03 07:20:04 +00:00
( ' /ns-included1/test3/inner/42/37/ ' , ' urlobject-view ' , ' testapp ' , ' inc-ns1:test-ns3 ' , ' inc-ns1:test-ns3:urlobject-view ' , views . empty_view , tuple ( ) , { ' arg1 ' : ' 42 ' , ' arg2 ' : ' 37 ' } ) ,
( ' /ns-included1/ns-included4/ns-included2/test3/inner/42/37/ ' , ' urlobject-view ' , ' testapp ' , ' inc-ns1:inc-ns4:inc-ns2:test-ns3 ' , ' inc-ns1:inc-ns4:inc-ns2:test-ns3:urlobject-view ' , views . empty_view , tuple ( ) , { ' arg1 ' : ' 42 ' , ' arg2 ' : ' 37 ' } ) ,
2011-12-22 23:03:48 +00:00
# Namespaces capturing variables
2013-10-03 07:20:04 +00:00
( ' /inc70/ ' , ' inner-nothing ' , None , ' inc-ns5 ' , ' inc-ns5:inner-nothing ' , views . empty_view , tuple ( ) , { ' outer ' : ' 70 ' } ) ,
( ' /inc78/extra/foobar/ ' , ' inner-extra ' , None , ' inc-ns5 ' , ' inc-ns5:inner-extra ' , views . empty_view , tuple ( ) , { ' outer ' : ' 78 ' , ' extra ' : ' foobar ' } ) ,
2010-08-05 07:09:47 +00:00
)
2009-11-16 01:58:00 +00:00
2006-07-28 02:08:36 +00:00
test_data = (
2008-08-31 11:11:20 +00:00
( ' places ' , ' /places/3/ ' , [ 3 ] , { } ) ,
( ' places ' , ' /places/3/ ' , [ ' 3 ' ] , { } ) ,
( ' places ' , NoReverseMatch , [ ' a ' ] , { } ) ,
( ' places ' , NoReverseMatch , [ ] , { } ) ,
( ' places? ' , ' /place/ ' , [ ] , { } ) ,
( ' places+ ' , ' /places/ ' , [ ] , { } ) ,
( ' places* ' , ' /place/ ' , [ ] , { } ) ,
( ' places2? ' , ' / ' , [ ] , { } ) ,
( ' places2+ ' , ' /places/ ' , [ ] , { } ) ,
( ' places2* ' , ' / ' , [ ] , { } ) ,
( ' places3 ' , ' /places/4/ ' , [ 4 ] , { } ) ,
( ' places3 ' , ' /places/harlem/ ' , [ ' harlem ' ] , { } ) ,
( ' places3 ' , NoReverseMatch , [ ' harlem64 ' ] , { } ) ,
( ' places4 ' , ' /places/3/ ' , [ ] , { ' id ' : 3 } ) ,
( ' people ' , NoReverseMatch , [ ] , { } ) ,
( ' people ' , ' /people/adrian/ ' , [ ' adrian ' ] , { } ) ,
( ' people ' , ' /people/adrian/ ' , [ ] , { ' name ' : ' adrian ' } ) ,
( ' people ' , NoReverseMatch , [ ' name with spaces ' ] , { } ) ,
( ' people ' , NoReverseMatch , [ ] , { ' name ' : ' name with spaces ' } ) ,
( ' people2 ' , ' /people/name/ ' , [ ] , { } ) ,
( ' people2a ' , ' /people/name/fred/ ' , [ ' fred ' ] , { } ) ,
2012-01-03 22:49:13 +00:00
( ' people_backref ' , ' /people/nate-nate/ ' , [ ' nate ' ] , { } ) ,
( ' people_backref ' , ' /people/nate-nate/ ' , [ ] , { ' name ' : ' nate ' } ) ,
2008-08-31 11:11:20 +00:00
( ' optional ' , ' /optional/fred/ ' , [ ] , { ' name ' : ' fred ' } ) ,
( ' optional ' , ' /optional/fred/ ' , [ ' fred ' ] , { } ) ,
( ' hardcoded ' , ' /hardcoded/ ' , [ ] , { } ) ,
( ' hardcoded2 ' , ' /hardcoded/doc.pdf ' , [ ] , { } ) ,
( ' people3 ' , ' /people/il/adrian/ ' , [ ] , { ' state ' : ' il ' , ' name ' : ' adrian ' } ) ,
( ' people3 ' , NoReverseMatch , [ ] , { ' state ' : ' il ' } ) ,
( ' people3 ' , NoReverseMatch , [ ] , { ' name ' : ' adrian ' } ) ,
( ' people4 ' , NoReverseMatch , [ ] , { ' state ' : ' il ' , ' name ' : ' adrian ' } ) ,
( ' people6 ' , ' /people/il/test/adrian/ ' , [ ' il/test ' , ' adrian ' ] , { } ) ,
( ' people6 ' , ' /people//adrian/ ' , [ ' adrian ' ] , { } ) ,
( ' range ' , ' /character_set/a/ ' , [ ] , { } ) ,
( ' range2 ' , ' /character_set/x/ ' , [ ] , { } ) ,
( ' price ' , ' /price/$10/ ' , [ ' 10 ' ] , { } ) ,
( ' price2 ' , ' /price/$10/ ' , [ ' 10 ' ] , { } ) ,
( ' price3 ' , ' /price/$10/ ' , [ ' 10 ' ] , { } ) ,
( ' product ' , ' /product/chocolate+($2.00)/ ' , [ ] , { ' price ' : ' 2.00 ' , ' product ' : ' chocolate ' } ) ,
( ' headlines ' , ' /headlines/2007.5.21/ ' , [ ] , dict ( year = 2007 , month = 5 , day = 21 ) ) ,
( ' windows ' , r ' /windows_path/C: % 5CDocuments %20a nd % 20Settings % 5Cspam/ ' , [ ] , dict ( drive_name = ' C ' , path = r ' Documents and Settings \ spam ' ) ) ,
2014-06-26 14:55:36 +00:00
( ' special ' , r ' /special_chars/~@+ % 5C$* % 7C/ ' , [ r ' ~@+ \ $*| ' ] , { } ) ,
2013-03-18 20:52:16 +00:00
( ' special ' , r ' /special_chars/some %20r esource/ ' , [ r ' some resource ' ] , { } ) ,
( ' special ' , r ' /special_chars/10 %25% 20complete/ ' , [ r ' 10 % c omplete ' ] , { } ) ,
( ' special ' , r ' /special_chars/some %20r esource/ ' , [ ] , { ' chars ' : r ' some resource ' } ) ,
( ' special ' , r ' /special_chars/10 %25% 20complete/ ' , [ ] , { ' chars ' : r ' 10 % c omplete ' } ) ,
2008-08-31 11:11:20 +00:00
( ' special ' , NoReverseMatch , [ ' ' ] , { } ) ,
( ' mixed ' , ' /john/0/ ' , [ ] , { ' name ' : ' john ' } ) ,
( ' repeats ' , ' /repeats/a/ ' , [ ] , { } ) ,
( ' repeats2 ' , ' /repeats/aa/ ' , [ ] , { } ) ,
2008-09-01 23:03:03 +00:00
( ' repeats3 ' , ' /repeats/aa/ ' , [ ] , { } ) ,
2008-08-31 11:11:20 +00:00
( ' insensitive ' , ' /CaseInsensitive/fred ' , [ ' fred ' ] , { } ) ,
( ' test ' , ' /test/1 ' , [ ] , { } ) ,
( ' test2 ' , ' /test/2 ' , [ ] , { } ) ,
( ' inner-nothing ' , ' /outer/42/ ' , [ ] , { ' outer ' : ' 42 ' } ) ,
( ' inner-nothing ' , ' /outer/42/ ' , [ ' 42 ' ] , { } ) ,
( ' inner-nothing ' , NoReverseMatch , [ ' foo ' ] , { } ) ,
( ' inner-extra ' , ' /outer/42/extra/inner/ ' , [ ] , { ' extra ' : ' inner ' , ' outer ' : ' 42 ' } ) ,
( ' inner-extra ' , ' /outer/42/extra/inner/ ' , [ ' 42 ' , ' inner ' ] , { } ) ,
( ' inner-extra ' , NoReverseMatch , [ ' fred ' , ' inner ' ] , { } ) ,
2014-02-27 15:32:20 +00:00
( ' inner-no-kwargs ' , ' /outer-no-kwargs/42/inner-no-kwargs/1/ ' , [ ' 42 ' , ' 1 ' ] , { } ) ,
2008-08-31 11:11:20 +00:00
( ' disjunction ' , NoReverseMatch , [ ' foo ' ] , { } ) ,
( ' inner-disjunction ' , NoReverseMatch , [ ' 10 ' , ' 11 ' ] , { } ) ,
2008-08-31 17:20:40 +00:00
( ' extra-places ' , ' /e-places/10/ ' , [ ' 10 ' ] , { } ) ,
( ' extra-people ' , ' /e-people/fred/ ' , [ ' fred ' ] , { } ) ,
( ' extra-people ' , ' /e-people/fred/ ' , [ ] , { ' name ' : ' fred ' } ) ,
2008-09-30 05:52:35 +00:00
( ' part ' , ' /part/one/ ' , [ ] , { ' value ' : ' one ' } ) ,
( ' part ' , ' /prefix/xx/part/one/ ' , [ ] , { ' value ' : ' one ' , ' prefix ' : ' xx ' } ) ,
( ' part2 ' , ' /part2/one/ ' , [ ] , { ' value ' : ' one ' } ) ,
( ' part2 ' , ' /part2/ ' , [ ] , { } ) ,
( ' part2 ' , ' /prefix/xx/part2/one/ ' , [ ] , { ' value ' : ' one ' , ' prefix ' : ' xx ' } ) ,
( ' part2 ' , ' /prefix/xx/part2/ ' , [ ] , { ' prefix ' : ' xx ' } ) ,
2008-09-27 06:14:11 +00:00
# Regression for #9038
# These views are resolved by method name. Each method is deployed twice -
# once with an explicit argument, and once using the default value on
# the method. This is potentially ambiguous, as you have to pick the
# correct view for the arguments provided.
2013-02-26 12:19:18 +00:00
( ' urlpatterns_reverse.views.absolute_kwargs_view ' , ' /absolute_arg_view/ ' , [ ] , { } ) ,
2013-10-26 19:15:03 +00:00
( ' urlpatterns_reverse.views.absolute_kwargs_view ' , ' /absolute_arg_view/10/ ' , [ ] , { ' arg1 ' : 10 } ) ,
2011-05-07 16:59:25 +00:00
( ' non_path_include ' , ' /includes/non_path_include/ ' , [ ] , { } ) ,
2008-09-27 06:14:11 +00:00
2011-05-07 16:59:25 +00:00
# Tests for #13154
( ' defaults ' , ' /defaults_view1/3/ ' , [ ] , { ' arg1 ' : 3 , ' arg2 ' : 1 } ) ,
( ' defaults ' , ' /defaults_view2/3/ ' , [ ] , { ' arg1 ' : 3 , ' arg2 ' : 2 } ) ,
( ' defaults ' , NoReverseMatch , [ ] , { ' arg1 ' : 3 , ' arg2 ' : 3 } ) ,
( ' defaults ' , NoReverseMatch , [ ] , { ' arg2 ' : 1 } ) ,
2014-07-17 19:59:28 +00:00
# Security tests
( ' security ' , ' / %2F example.com/security/ ' , [ ' /example.com ' ] , { } ) ,
2006-07-28 02:08:36 +00:00
)
2013-11-02 21:34:05 +00:00
2014-04-05 06:04:46 +00:00
@override_settings ( ROOT_URLCONF = ' urlpatterns_reverse.no_urls ' )
2010-09-27 15:16:46 +00:00
class NoURLPatternsTests ( TestCase ) :
def test_no_urls_exception ( self ) :
"""
RegexURLResolver should raise an exception when no urlpatterns exist .
"""
2014-04-05 06:04:46 +00:00
resolver = RegexURLResolver ( r ' ^$ ' , settings . ROOT_URLCONF )
2010-09-27 15:16:46 +00:00
2011-08-13 00:42:08 +00:00
self . assertRaisesMessage ( ImproperlyConfigured ,
2014-02-22 14:36:49 +00:00
" The included urlconf ' urlpatterns_reverse.no_urls ' does not "
" appear to have any patterns in it. If you see valid patterns in "
" the file then the issue is probably caused by a circular import. " ,
getattr , resolver , ' url_patterns ' )
2010-09-27 15:16:46 +00:00
2013-11-02 21:34:05 +00:00
2014-04-05 06:04:46 +00:00
@override_settings ( ROOT_URLCONF = ' urlpatterns_reverse.urls ' )
2008-08-31 11:11:20 +00:00
class URLPatternReverse ( TestCase ) :
2006-08-27 13:59:47 +00:00
def test_urlpattern_reverse ( self ) :
2014-06-03 11:30:14 +00:00
with warnings . catch_warnings ( ) :
warnings . filterwarnings ( " ignore " , category = RemovedInDjango20Warning )
for name , expected , args , kwargs in test_data :
try :
got = reverse ( name , args = args , kwargs = kwargs )
except NoReverseMatch :
self . assertEqual ( expected , NoReverseMatch )
else :
self . assertEqual ( got , expected )
2006-07-28 02:08:36 +00:00
2010-08-06 14:34:10 +00:00
def test_reverse_none ( self ) :
# Reversing None should raise an error, not return the last un-named view.
self . assertRaises ( NoReverseMatch , reverse , None )
2012-11-03 20:06:57 +00:00
def test_prefix_braces ( self ) :
self . assertEqual ( ' / % 7B % 7Binvalid % 7D % 7D/includes/non_path_include/ ' ,
reverse ( ' non_path_include ' , prefix = ' / {{ invalid}}/ ' ) )
def test_prefix_parenthesis ( self ) :
self . assertEqual ( ' /bogus % 29/includes/non_path_include/ ' ,
reverse ( ' non_path_include ' , prefix = ' /bogus)/ ' ) )
def test_prefix_format_char ( self ) :
self . assertEqual ( ' /bump % 2520map/includes/non_path_include/ ' ,
reverse ( ' non_path_include ' , prefix = ' /bump % 20map/ ' ) )
2013-03-13 17:19:29 +00:00
def test_non_urlsafe_prefix_with_args ( self ) :
# Regression for #20022
self . assertEqual ( ' / %7E me/places/1/ ' ,
reverse ( ' places ' , args = [ 1 ] , prefix = ' /~me/ ' ) )
2013-06-13 12:55:18 +00:00
def test_patterns_reported ( self ) :
# Regression for #17076
try :
# this url exists, but requires an argument
reverse ( " people " , args = [ ] )
except NoReverseMatch as e :
pattern_description = r " 1 pattern(s) tried: [ ' people/(?P<name> \\ w+)/$ ' ] "
self . assertIn ( pattern_description , str ( e ) )
else :
# we can't use .assertRaises, since we want to inspect the
# exception
self . fail ( " Expected a NoReverseMatch, but none occurred. " )
2014-09-18 20:03:09 +00:00
def test_reverse_returns_unicode ( self ) :
name , expected , args , kwargs = test_data [ 0 ]
self . assertIsInstance (
reverse ( name , args = args , kwargs = kwargs ) ,
six . text_type
)
2013-06-13 12:55:18 +00:00
2009-06-29 14:02:17 +00:00
class ResolverTests ( unittest . TestCase ) :
2012-09-01 20:07:18 +00:00
def test_resolver_repr ( self ) :
"""
Test repr of RegexURLResolver , especially when urlconf_name is a list
( #17892).
"""
# Pick a resolver from a namespaced urlconf
2013-02-26 12:19:18 +00:00
resolver = get_resolver ( ' urlpatterns_reverse.namespace_urls ' )
2012-09-01 20:07:18 +00:00
sub_resolver = resolver . namespace_dict [ ' test-ns1 ' ] [ 1 ]
self . assertIn ( ' <RegexURLPattern list> ' , repr ( sub_resolver ) )
2013-09-06 18:43:58 +00:00
def test_reverse_lazy_object_coercion_by_resolve ( self ) :
"""
Verifies lazy object returned by reverse_lazy is coerced to
text by resolve ( ) . Previous to #21043, this would raise a TypeError.
"""
urls = ' urlpatterns_reverse.named_urls '
proxy_url = reverse_lazy ( ' named-url1 ' , urlconf = urls )
resolver = get_resolver ( urls )
try :
2013-10-19 12:31:38 +00:00
resolver . resolve ( proxy_url )
2013-09-06 18:43:58 +00:00
except TypeError :
self . fail ( ' Failed to coerce lazy object to text ' )
2009-06-29 14:02:17 +00:00
def test_non_regex ( self ) :
"""
Verifies that we raise a Resolver404 if what we are resolving doesn ' t
meet the basic requirements of a path to match - i . e . , at the very
least , it matches the root pattern ' ^/ ' . We must never return None
from resolve , or we will get a TypeError further down the line .
Regression for #10834.
"""
self . assertRaises ( Resolver404 , resolve , ' ' )
self . assertRaises ( Resolver404 , resolve , ' a ' )
self . assertRaises ( Resolver404 , resolve , ' \\ ' )
self . assertRaises ( Resolver404 , resolve , ' . ' )
2010-09-27 15:16:46 +00:00
2010-09-12 19:27:33 +00:00
def test_404_tried_urls_have_names ( self ) :
"""
Verifies that the list of URLs that come back from a Resolver404
exception contains a list in the right format for printing out in
the DEBUG 404 page with both the patterns and URL names , if available .
"""
2013-02-26 12:19:18 +00:00
urls = ' urlpatterns_reverse.named_urls '
2010-09-12 19:27:33 +00:00
# this list matches the expected URL types and names returned when
# you try to resolve a non-existent URL in the first level of included
# URLs in named_urls.py (e.g., '/included/non-existent-url')
url_types_names = [
[ { ' type ' : RegexURLPattern , ' name ' : ' named-url1 ' } ] ,
[ { ' type ' : RegexURLPattern , ' name ' : ' named-url2 ' } ] ,
[ { ' type ' : RegexURLPattern , ' name ' : None } ] ,
[ { ' type ' : RegexURLResolver } , { ' type ' : RegexURLPattern , ' name ' : ' named-url3 ' } ] ,
[ { ' type ' : RegexURLResolver } , { ' type ' : RegexURLPattern , ' name ' : ' named-url4 ' } ] ,
[ { ' type ' : RegexURLResolver } , { ' type ' : RegexURLPattern , ' name ' : None } ] ,
[ { ' type ' : RegexURLResolver } , { ' type ' : RegexURLResolver } ] ,
]
try :
resolve ( ' /included/non-existent-url ' , urlconf = urls )
self . fail ( ' resolve did not raise a 404 ' )
2012-04-28 16:09:37 +00:00
except Resolver404 as e :
2010-09-12 19:27:33 +00:00
# make sure we at least matched the root ('/') url resolver:
2014-10-28 10:02:56 +00:00
self . assertIn ( ' tried ' , e . args [ 0 ] )
2014-02-15 16:45:16 +00:00
tried = e . args [ 0 ] [ ' tried ' ]
self . assertEqual ( len ( e . args [ 0 ] [ ' tried ' ] ) , len ( url_types_names ) , ' Wrong number of tried URLs returned. Expected %s , got %s . ' % ( len ( url_types_names ) , len ( e . args [ 0 ] [ ' tried ' ] ) ) )
for tried , expected in zip ( e . args [ 0 ] [ ' tried ' ] , url_types_names ) :
2010-09-12 19:27:33 +00:00
for t , e in zip ( tried , expected ) :
2013-05-21 09:42:15 +00:00
self . assertIsInstance ( t , e [ ' type ' ] ) , str ( ' %s is not an instance of %s ' ) % ( t , e [ ' type ' ] )
2010-09-12 19:27:33 +00:00
if ' name ' in e :
if not e [ ' name ' ] :
2014-10-28 10:02:56 +00:00
self . assertIsNone ( t . name , ' Expected no URL name but found %s . ' % t . name )
2010-09-12 19:27:33 +00:00
else :
self . assertEqual ( t . name , e [ ' name ' ] , ' Wrong URL name. Expected " %s " , got " %s " . ' % ( e [ ' name ' ] , t . name ) )
2009-06-29 14:02:17 +00:00
2013-11-02 21:34:05 +00:00
2014-04-05 06:04:46 +00:00
@override_settings ( ROOT_URLCONF = ' urlpatterns_reverse.reverse_lazy_urls ' )
2011-04-29 11:49:59 +00:00
class ReverseLazyTest ( TestCase ) :
def test_redirect_with_lazy_reverse ( self ) :
response = self . client . get ( ' /redirect/ ' )
self . assertRedirects ( response , " /redirected_to/ " , status_code = 301 )
def test_user_permission_with_lazy_reverse ( self ) :
2013-10-19 12:31:38 +00:00
User . objects . create_user ( ' alfred ' , ' alfred@example.com ' , password = ' testpw ' )
2011-04-29 11:49:59 +00:00
response = self . client . get ( ' /login_required_view/ ' )
self . assertRedirects ( response , " /login/?next=/login_required_view/ " , status_code = 302 )
self . client . login ( username = ' alfred ' , password = ' testpw ' )
response = self . client . get ( ' /login_required_view/ ' )
self . assertEqual ( response . status_code , 200 )
2013-11-02 21:34:05 +00:00
2014-02-18 09:19:04 +00:00
class ReverseLazySettingsTest ( AdminScriptTestCase ) :
"""
Test that reverse_lazy can be used in settings without causing a circular
import error .
"""
def setUp ( self ) :
self . write_settings ( ' settings.py ' , extra = """
from django . core . urlresolvers import reverse_lazy
LOGIN_URL = reverse_lazy ( ' login ' ) """ )
def tearDown ( self ) :
self . remove_settings ( ' settings.py ' )
def test_lazy_in_settings ( self ) :
2014-06-16 19:59:24 +00:00
out , err = self . run_manage ( [ ' validate ' ] )
2014-02-18 12:20:02 +00:00
self . assertNoOutput ( err )
2014-02-18 09:19:04 +00:00
2014-04-05 06:04:46 +00:00
@override_settings ( ROOT_URLCONF = ' urlpatterns_reverse.urls ' )
2009-03-21 13:09:13 +00:00
class ReverseShortcutTests ( TestCase ) :
2009-04-04 06:54:56 +00:00
2009-03-21 13:09:13 +00:00
def test_redirect_to_object ( self ) :
# We don't really need a model; just something with a get_absolute_url
class FakeObj ( object ) :
def get_absolute_url ( self ) :
return " /hi-there/ "
2009-04-04 06:54:56 +00:00
2009-03-21 13:09:13 +00:00
res = redirect ( FakeObj ( ) )
2013-05-21 09:42:15 +00:00
self . assertIsInstance ( res , HttpResponseRedirect )
2013-02-13 08:55:43 +00:00
self . assertEqual ( res . url , ' /hi-there/ ' )
2009-04-04 06:54:56 +00:00
2009-03-21 13:09:13 +00:00
res = redirect ( FakeObj ( ) , permanent = True )
2013-05-21 09:42:15 +00:00
self . assertIsInstance ( res , HttpResponsePermanentRedirect )
2013-02-13 08:55:43 +00:00
self . assertEqual ( res . url , ' /hi-there/ ' )
2009-04-04 06:54:56 +00:00
2009-03-21 13:09:13 +00:00
def test_redirect_to_view_name ( self ) :
res = redirect ( ' hardcoded2 ' )
2013-02-13 08:55:43 +00:00
self . assertEqual ( res . url , ' /hardcoded/doc.pdf ' )
2009-03-21 13:09:13 +00:00
res = redirect ( ' places ' , 1 )
2013-02-13 08:55:43 +00:00
self . assertEqual ( res . url , ' /places/1/ ' )
2009-03-21 13:09:13 +00:00
res = redirect ( ' headlines ' , year = ' 2008 ' , month = ' 02 ' , day = ' 17 ' )
2013-02-13 08:55:43 +00:00
self . assertEqual ( res . url , ' /headlines/2008.02.17/ ' )
2009-03-21 13:09:13 +00:00
self . assertRaises ( NoReverseMatch , redirect , ' not-a-view ' )
2009-04-04 06:54:56 +00:00
2009-03-21 13:09:13 +00:00
def test_redirect_to_url ( self ) :
res = redirect ( ' /foo/ ' )
2013-02-13 08:55:43 +00:00
self . assertEqual ( res . url , ' /foo/ ' )
2009-03-21 13:09:13 +00:00
res = redirect ( ' http://example.com/ ' )
2013-02-13 08:55:43 +00:00
self . assertEqual ( res . url , ' http://example.com/ ' )
2014-04-20 17:12:43 +00:00
# Assert that we can redirect using UTF-8 strings
res = redirect ( ' /æøå/abc/ ' )
self . assertEqual ( res . url , ' / % C3 % A6 % C3 % B8 % C3 % A5/abc/ ' )
# Assert that no imports are attempted when dealing with a relative path
# (previously, the below would resolve in a UnicodeEncodeError from __import__ )
res = redirect ( ' /æøå.abc/ ' )
self . assertEqual ( res . url , ' / % C3 % A6 % C3 % B8 % C3 % A5.abc/ ' )
res = redirect ( ' os.path ' )
self . assertEqual ( res . url , ' os.path ' )
def test_no_illegal_imports ( self ) :
# modules that are not listed in urlpatterns should not be importable
redirect ( " urlpatterns_reverse.nonimported_module.view " )
self . assertNotIn ( " urlpatterns_reverse.nonimported_module " , sys . modules )
def test_reverse_by_path_nested ( self ) :
# Views that are added to urlpatterns using include() should be
2014-06-03 11:30:14 +00:00
# reversible by doted path.
with warnings . catch_warnings ( ) :
warnings . filterwarnings ( " ignore " , category = RemovedInDjango20Warning )
self . assertEqual ( reverse ( ' urlpatterns_reverse.views.nested_view ' ) , ' /includes/nested_path/ ' )
2009-07-16 16:16:13 +00:00
2010-01-10 18:44:39 +00:00
def test_redirect_view_object ( self ) :
2011-10-13 21:34:56 +00:00
from . views import absolute_kwargs_view
2010-01-10 18:44:39 +00:00
res = redirect ( absolute_kwargs_view )
2013-02-13 08:55:43 +00:00
self . assertEqual ( res . url , ' /absolute_arg_view/ ' )
2010-01-10 18:44:39 +00:00
self . assertRaises ( NoReverseMatch , redirect , absolute_kwargs_view , wrong_argument = None )
2009-07-16 16:16:13 +00:00
2014-04-05 06:04:46 +00:00
@override_settings ( ROOT_URLCONF = ' urlpatterns_reverse.namespace_urls ' )
2009-07-16 16:16:13 +00:00
class NamespaceTests ( TestCase ) :
def test_ambiguous_object ( self ) :
" Names deployed via dynamic URL objects that require namespaces can ' t be resolved "
self . assertRaises ( NoReverseMatch , reverse , ' urlobject-view ' )
2013-10-26 19:15:03 +00:00
self . assertRaises ( NoReverseMatch , reverse , ' urlobject-view ' , args = [ 37 , 42 ] )
self . assertRaises ( NoReverseMatch , reverse , ' urlobject-view ' , kwargs = { ' arg1 ' : 42 , ' arg2 ' : 37 } )
2009-07-16 16:16:13 +00:00
def test_ambiguous_urlpattern ( self ) :
" Names deployed via dynamic URL objects that require namespaces can ' t be resolved "
self . assertRaises ( NoReverseMatch , reverse , ' inner-nothing ' )
2013-10-26 19:15:03 +00:00
self . assertRaises ( NoReverseMatch , reverse , ' inner-nothing ' , args = [ 37 , 42 ] )
self . assertRaises ( NoReverseMatch , reverse , ' inner-nothing ' , kwargs = { ' arg1 ' : 42 , ' arg2 ' : 37 } )
2009-07-16 16:16:13 +00:00
def test_non_existent_namespace ( self ) :
" Non-existent namespaces raise errors "
self . assertRaises ( NoReverseMatch , reverse , ' blahblah:urlobject-view ' )
self . assertRaises ( NoReverseMatch , reverse , ' test-ns1:blahblah:urlobject-view ' )
def test_normal_name ( self ) :
" Normal lookups work as expected "
2011-03-03 15:04:39 +00:00
self . assertEqual ( ' /normal/ ' , reverse ( ' normal-view ' ) )
2013-10-26 19:15:03 +00:00
self . assertEqual ( ' /normal/37/42/ ' , reverse ( ' normal-view ' , args = [ 37 , 42 ] ) )
self . assertEqual ( ' /normal/42/37/ ' , reverse ( ' normal-view ' , kwargs = { ' arg1 ' : 42 , ' arg2 ' : 37 } ) )
2011-11-07 01:09:13 +00:00
self . assertEqual ( ' /+ % 5C$*/ ' , reverse ( ' special-view ' ) )
2009-07-16 16:16:13 +00:00
def test_simple_included_name ( self ) :
" Normal lookups work on names included from other patterns "
2011-03-03 15:04:39 +00:00
self . assertEqual ( ' /included/normal/ ' , reverse ( ' inc-normal-view ' ) )
2013-10-26 19:15:03 +00:00
self . assertEqual ( ' /included/normal/37/42/ ' , reverse ( ' inc-normal-view ' , args = [ 37 , 42 ] ) )
self . assertEqual ( ' /included/normal/42/37/ ' , reverse ( ' inc-normal-view ' , kwargs = { ' arg1 ' : 42 , ' arg2 ' : 37 } ) )
2011-11-07 01:09:13 +00:00
self . assertEqual ( ' /included/+ % 5C$*/ ' , reverse ( ' inc-special-view ' ) )
2009-07-16 16:16:13 +00:00
def test_namespace_object ( self ) :
" Dynamic URL objects can be found using a namespace "
2011-03-03 15:04:39 +00:00
self . assertEqual ( ' /test1/inner/ ' , reverse ( ' test-ns1:urlobject-view ' ) )
2013-10-26 19:15:03 +00:00
self . assertEqual ( ' /test1/inner/37/42/ ' , reverse ( ' test-ns1:urlobject-view ' , args = [ 37 , 42 ] ) )
self . assertEqual ( ' /test1/inner/42/37/ ' , reverse ( ' test-ns1:urlobject-view ' , kwargs = { ' arg1 ' : 42 , ' arg2 ' : 37 } ) )
2011-11-07 01:09:13 +00:00
self . assertEqual ( ' /test1/inner/+ % 5C$*/ ' , reverse ( ' test-ns1:urlobject-special-view ' ) )
2009-07-16 16:16:13 +00:00
def test_embedded_namespace_object ( self ) :
" Namespaces can be installed anywhere in the URL pattern tree "
2011-03-03 15:04:39 +00:00
self . assertEqual ( ' /included/test3/inner/ ' , reverse ( ' test-ns3:urlobject-view ' ) )
2013-10-26 19:15:03 +00:00
self . assertEqual ( ' /included/test3/inner/37/42/ ' , reverse ( ' test-ns3:urlobject-view ' , args = [ 37 , 42 ] ) )
self . assertEqual ( ' /included/test3/inner/42/37/ ' , reverse ( ' test-ns3:urlobject-view ' , kwargs = { ' arg1 ' : 42 , ' arg2 ' : 37 } ) )
2011-11-07 01:09:13 +00:00
self . assertEqual ( ' /included/test3/inner/+ % 5C$*/ ' , reverse ( ' test-ns3:urlobject-special-view ' ) )
2009-07-16 16:16:13 +00:00
def test_namespace_pattern ( self ) :
" Namespaces can be applied to include() ' d urlpatterns "
2011-03-03 15:04:39 +00:00
self . assertEqual ( ' /ns-included1/normal/ ' , reverse ( ' inc-ns1:inc-normal-view ' ) )
2013-10-26 19:15:03 +00:00
self . assertEqual ( ' /ns-included1/normal/37/42/ ' , reverse ( ' inc-ns1:inc-normal-view ' , args = [ 37 , 42 ] ) )
self . assertEqual ( ' /ns-included1/normal/42/37/ ' , reverse ( ' inc-ns1:inc-normal-view ' , kwargs = { ' arg1 ' : 42 , ' arg2 ' : 37 } ) )
2011-11-07 01:09:13 +00:00
self . assertEqual ( ' /ns-included1/+ % 5C$*/ ' , reverse ( ' inc-ns1:inc-special-view ' ) )
2009-07-16 16:16:13 +00:00
2011-08-12 14:15:50 +00:00
def test_namespace_pattern_with_variable_prefix ( self ) :
2014-05-29 00:39:14 +00:00
" When using an include with namespaces when there is a regex variable in front of it "
2013-10-26 19:15:03 +00:00
self . assertEqual ( ' /ns-outer/42/normal/ ' , reverse ( ' inc-outer:inc-normal-view ' , kwargs = { ' outer ' : 42 } ) )
2011-08-12 14:15:50 +00:00
self . assertEqual ( ' /ns-outer/42/normal/ ' , reverse ( ' inc-outer:inc-normal-view ' , args = [ 42 ] ) )
2013-10-26 19:15:03 +00:00
self . assertEqual ( ' /ns-outer/42/normal/37/4/ ' , reverse ( ' inc-outer:inc-normal-view ' , kwargs = { ' outer ' : 42 , ' arg1 ' : 37 , ' arg2 ' : 4 } ) )
2011-08-12 14:15:50 +00:00
self . assertEqual ( ' /ns-outer/42/normal/37/4/ ' , reverse ( ' inc-outer:inc-normal-view ' , args = [ 42 , 37 , 4 ] ) )
2013-11-02 19:37:48 +00:00
self . assertEqual ( ' /ns-outer/42/+ % 5C$*/ ' , reverse ( ' inc-outer:inc-special-view ' , kwargs = { ' outer ' : 42 } ) )
self . assertEqual ( ' /ns-outer/42/+ % 5C$*/ ' , reverse ( ' inc-outer:inc-special-view ' , args = [ 42 ] ) )
2011-08-12 14:15:50 +00:00
2009-07-16 16:16:13 +00:00
def test_multiple_namespace_pattern ( self ) :
" Namespaces can be embedded "
2011-03-03 15:04:39 +00:00
self . assertEqual ( ' /ns-included1/test3/inner/ ' , reverse ( ' inc-ns1:test-ns3:urlobject-view ' ) )
2013-10-26 19:15:03 +00:00
self . assertEqual ( ' /ns-included1/test3/inner/37/42/ ' , reverse ( ' inc-ns1:test-ns3:urlobject-view ' , args = [ 37 , 42 ] ) )
self . assertEqual ( ' /ns-included1/test3/inner/42/37/ ' , reverse ( ' inc-ns1:test-ns3:urlobject-view ' , kwargs = { ' arg1 ' : 42 , ' arg2 ' : 37 } ) )
2011-11-07 01:09:13 +00:00
self . assertEqual ( ' /ns-included1/test3/inner/+ % 5C$*/ ' , reverse ( ' inc-ns1:test-ns3:urlobject-special-view ' ) )
2009-07-16 16:16:13 +00:00
2010-08-05 07:09:47 +00:00
def test_nested_namespace_pattern ( self ) :
" Namespaces can be nested "
2011-03-03 15:04:39 +00:00
self . assertEqual ( ' /ns-included1/ns-included4/ns-included1/test3/inner/ ' , reverse ( ' inc-ns1:inc-ns4:inc-ns1:test-ns3:urlobject-view ' ) )
2013-10-26 19:15:03 +00:00
self . assertEqual ( ' /ns-included1/ns-included4/ns-included1/test3/inner/37/42/ ' , reverse ( ' inc-ns1:inc-ns4:inc-ns1:test-ns3:urlobject-view ' , args = [ 37 , 42 ] ) )
self . assertEqual ( ' /ns-included1/ns-included4/ns-included1/test3/inner/42/37/ ' , reverse ( ' inc-ns1:inc-ns4:inc-ns1:test-ns3:urlobject-view ' , kwargs = { ' arg1 ' : 42 , ' arg2 ' : 37 } ) )
2011-11-07 01:09:13 +00:00
self . assertEqual ( ' /ns-included1/ns-included4/ns-included1/test3/inner/+ % 5C$*/ ' , reverse ( ' inc-ns1:inc-ns4:inc-ns1:test-ns3:urlobject-special-view ' ) )
2010-08-05 07:09:47 +00:00
2009-07-16 16:16:13 +00:00
def test_app_lookup_object ( self ) :
" A default application namespace can be used for lookup "
2011-03-03 15:04:39 +00:00
self . assertEqual ( ' /default/inner/ ' , reverse ( ' testapp:urlobject-view ' ) )
2013-10-26 19:15:03 +00:00
self . assertEqual ( ' /default/inner/37/42/ ' , reverse ( ' testapp:urlobject-view ' , args = [ 37 , 42 ] ) )
self . assertEqual ( ' /default/inner/42/37/ ' , reverse ( ' testapp:urlobject-view ' , kwargs = { ' arg1 ' : 42 , ' arg2 ' : 37 } ) )
2011-11-07 01:09:13 +00:00
self . assertEqual ( ' /default/inner/+ % 5C$*/ ' , reverse ( ' testapp:urlobject-special-view ' ) )
2009-07-16 16:16:13 +00:00
def test_app_lookup_object_with_default ( self ) :
" A default application namespace is sensitive to the ' current ' app can be used for lookup "
2011-03-03 15:04:39 +00:00
self . assertEqual ( ' /included/test3/inner/ ' , reverse ( ' testapp:urlobject-view ' , current_app = ' test-ns3 ' ) )
2013-10-26 19:15:03 +00:00
self . assertEqual ( ' /included/test3/inner/37/42/ ' , reverse ( ' testapp:urlobject-view ' , args = [ 37 , 42 ] , current_app = ' test-ns3 ' ) )
self . assertEqual ( ' /included/test3/inner/42/37/ ' , reverse ( ' testapp:urlobject-view ' , kwargs = { ' arg1 ' : 42 , ' arg2 ' : 37 } , current_app = ' test-ns3 ' ) )
2011-11-07 01:09:13 +00:00
self . assertEqual ( ' /included/test3/inner/+ % 5C$*/ ' , reverse ( ' testapp:urlobject-special-view ' , current_app = ' test-ns3 ' ) )
2009-07-16 16:16:13 +00:00
def test_app_lookup_object_without_default ( self ) :
" An application namespace without a default is sensitive to the ' current ' app can be used for lookup "
2011-03-03 15:04:39 +00:00
self . assertEqual ( ' /other2/inner/ ' , reverse ( ' nodefault:urlobject-view ' ) )
2013-10-26 19:15:03 +00:00
self . assertEqual ( ' /other2/inner/37/42/ ' , reverse ( ' nodefault:urlobject-view ' , args = [ 37 , 42 ] ) )
self . assertEqual ( ' /other2/inner/42/37/ ' , reverse ( ' nodefault:urlobject-view ' , kwargs = { ' arg1 ' : 42 , ' arg2 ' : 37 } ) )
2011-11-07 01:09:13 +00:00
self . assertEqual ( ' /other2/inner/+ % 5C$*/ ' , reverse ( ' nodefault:urlobject-special-view ' ) )
2009-07-16 16:16:13 +00:00
2011-03-03 15:04:39 +00:00
self . assertEqual ( ' /other1/inner/ ' , reverse ( ' nodefault:urlobject-view ' , current_app = ' other-ns1 ' ) )
2013-10-26 19:15:03 +00:00
self . assertEqual ( ' /other1/inner/37/42/ ' , reverse ( ' nodefault:urlobject-view ' , args = [ 37 , 42 ] , current_app = ' other-ns1 ' ) )
self . assertEqual ( ' /other1/inner/42/37/ ' , reverse ( ' nodefault:urlobject-view ' , kwargs = { ' arg1 ' : 42 , ' arg2 ' : 37 } , current_app = ' other-ns1 ' ) )
2011-11-07 01:09:13 +00:00
self . assertEqual ( ' /other1/inner/+ % 5C$*/ ' , reverse ( ' nodefault:urlobject-special-view ' , current_app = ' other-ns1 ' ) )
def test_special_chars_namespace ( self ) :
self . assertEqual ( ' /+ % 5C$*/included/normal/ ' , reverse ( ' special:inc-normal-view ' ) )
2013-10-26 19:15:03 +00:00
self . assertEqual ( ' /+ % 5C$*/included/normal/37/42/ ' , reverse ( ' special:inc-normal-view ' , args = [ 37 , 42 ] ) )
self . assertEqual ( ' /+ % 5C$*/included/normal/42/37/ ' , reverse ( ' special:inc-normal-view ' , kwargs = { ' arg1 ' : 42 , ' arg2 ' : 37 } ) )
2011-11-07 01:09:13 +00:00
self . assertEqual ( ' /+ % 5C$*/included/+ % 5C$*/ ' , reverse ( ' special:inc-special-view ' ) )
2009-07-16 16:16:13 +00:00
2011-12-22 23:03:48 +00:00
def test_namespaces_with_variables ( self ) :
" Namespace prefixes can capture variables: see #15900 "
self . assertEqual ( ' /inc70/ ' , reverse ( ' inc-ns5:inner-nothing ' , kwargs = { ' outer ' : ' 70 ' } ) )
2013-10-26 19:15:03 +00:00
self . assertEqual ( ' /inc78/extra/foobar/ ' , reverse ( ' inc-ns5:inner-extra ' , kwargs = { ' outer ' : ' 78 ' , ' extra ' : ' foobar ' } ) )
2011-12-22 23:03:48 +00:00
self . assertEqual ( ' /inc70/ ' , reverse ( ' inc-ns5:inner-nothing ' , args = [ ' 70 ' ] ) )
2013-10-26 19:15:03 +00:00
self . assertEqual ( ' /inc78/extra/foobar/ ' , reverse ( ' inc-ns5:inner-extra ' , args = [ ' 78 ' , ' foobar ' ] ) )
2011-12-22 23:03:48 +00:00
2009-11-16 01:58:00 +00:00
2013-11-02 21:34:05 +00:00
@override_settings ( ROOT_URLCONF = urlconf_outer . __name__ )
2013-10-14 13:14:17 +00:00
class RequestURLconfTests ( TestCase ) :
2009-11-16 01:58:00 +00:00
def test_urlconf ( self ) :
response = self . client . get ( ' /test/me/ ' )
self . assertEqual ( response . status_code , 200 )
2012-08-14 09:57:18 +00:00
self . assertEqual ( response . content , b ' outer:/test/me/, '
b ' inner:/inner_urlconf/second_test/ ' )
2009-11-16 01:58:00 +00:00
response = self . client . get ( ' /inner_urlconf/second_test/ ' )
self . assertEqual ( response . status_code , 200 )
response = self . client . get ( ' /second_test/ ' )
self . assertEqual ( response . status_code , 404 )
2013-10-14 13:14:17 +00:00
@override_settings (
MIDDLEWARE_CLASSES = (
2009-11-16 01:58:00 +00:00
' %s .ChangeURLconfMiddleware ' % middleware . __name__ ,
)
2013-10-14 13:14:17 +00:00
)
def test_urlconf_overridden ( self ) :
2009-11-16 01:58:00 +00:00
response = self . client . get ( ' /test/me/ ' )
self . assertEqual ( response . status_code , 404 )
response = self . client . get ( ' /inner_urlconf/second_test/ ' )
self . assertEqual ( response . status_code , 404 )
response = self . client . get ( ' /second_test/ ' )
self . assertEqual ( response . status_code , 200 )
2012-08-14 09:57:18 +00:00
self . assertEqual ( response . content , b ' outer:,inner:/second_test/ ' )
2009-12-13 20:29:04 +00:00
2013-10-14 13:14:17 +00:00
@override_settings (
MIDDLEWARE_CLASSES = (
2010-03-26 15:08:24 +00:00
' %s .NullChangeURLconfMiddleware ' % middleware . __name__ ,
)
2013-10-14 13:14:17 +00:00
)
def test_urlconf_overridden_with_null ( self ) :
2010-03-26 15:08:24 +00:00
self . assertRaises ( ImproperlyConfigured , self . client . get , ' /test/me/ ' )
2013-10-14 13:14:17 +00:00
@override_settings (
MIDDLEWARE_CLASSES = (
' %s .ChangeURLconfMiddleware ' % middleware . __name__ ,
' %s .ReverseInnerInResponseMiddleware ' % middleware . __name__ ,
)
)
2013-03-06 23:33:51 +00:00
def test_reverse_inner_in_response_middleware ( self ) :
"""
Test reversing an URL from the * overridden * URLconf from inside
a response middleware .
"""
response = self . client . get ( ' /second_test/ ' )
self . assertEqual ( response . status_code , 200 )
self . assertEqual ( response . content , b ' /second_test/ ' )
2013-10-14 13:14:17 +00:00
@override_settings (
MIDDLEWARE_CLASSES = (
' %s .ChangeURLconfMiddleware ' % middleware . __name__ ,
' %s .ReverseOuterInResponseMiddleware ' % middleware . __name__ ,
)
)
2013-03-06 23:33:51 +00:00
def test_reverse_outer_in_response_middleware ( self ) :
"""
Test reversing an URL from the * default * URLconf from inside
a response middleware .
"""
message = " Reverse for ' outer ' with arguments ' () ' and keyword arguments ' {} ' not found. "
with self . assertRaisesMessage ( NoReverseMatch , message ) :
self . client . get ( ' /second_test/ ' )
2013-10-14 13:14:17 +00:00
@override_settings (
MIDDLEWARE_CLASSES = (
' %s .ChangeURLconfMiddleware ' % middleware . __name__ ,
' %s .ReverseInnerInStreaming ' % middleware . __name__ ,
)
)
2013-03-06 23:33:51 +00:00
def test_reverse_inner_in_streaming ( self ) :
"""
Test reversing an URL from the * overridden * URLconf from inside
a streaming response .
"""
response = self . client . get ( ' /second_test/ ' )
self . assertEqual ( response . status_code , 200 )
self . assertEqual ( b ' ' . join ( response ) , b ' /second_test/ ' )
2013-10-14 13:14:17 +00:00
@override_settings (
MIDDLEWARE_CLASSES = (
' %s .ChangeURLconfMiddleware ' % middleware . __name__ ,
' %s .ReverseOuterInStreaming ' % middleware . __name__ ,
)
)
2013-03-06 23:33:51 +00:00
def test_reverse_outer_in_streaming ( self ) :
"""
Test reversing an URL from the * default * URLconf from inside
a streaming response .
"""
message = " Reverse for ' outer ' with arguments ' () ' and keyword arguments ' {} ' not found. "
with self . assertRaisesMessage ( NoReverseMatch , message ) :
self . client . get ( ' /second_test/ ' )
b ' ' . join ( self . client . get ( ' /second_test/ ' ) )
2013-11-02 21:34:05 +00:00
2009-12-13 20:29:04 +00:00
class ErrorHandlerResolutionTests ( TestCase ) :
2013-05-15 23:14:28 +00:00
""" Tests for handler400, handler404 and handler500 """
2010-03-26 15:08:24 +00:00
2009-12-13 20:29:04 +00:00
def setUp ( self ) :
2013-02-26 12:19:18 +00:00
urlconf = ' urlpatterns_reverse.urls_error_handlers '
urlconf_callables = ' urlpatterns_reverse.urls_error_handlers_callables '
2009-12-13 20:29:04 +00:00
self . resolver = RegexURLResolver ( r ' ^$ ' , urlconf )
self . callable_resolver = RegexURLResolver ( r ' ^$ ' , urlconf_callables )
2010-03-26 15:08:24 +00:00
2009-12-13 20:29:04 +00:00
def test_named_handlers ( self ) :
handler = ( empty_view , { } )
2014-06-22 03:32:14 +00:00
self . assertEqual ( self . resolver . resolve_error_handler ( 400 ) , handler )
self . assertEqual ( self . resolver . resolve_error_handler ( 404 ) , handler )
self . assertEqual ( self . resolver . resolve_error_handler ( 500 ) , handler )
2009-12-13 20:29:04 +00:00
def test_callable_handers ( self ) :
handler = ( empty_view , { } )
2014-06-22 03:32:14 +00:00
self . assertEqual ( self . callable_resolver . resolve_error_handler ( 400 ) , handler )
self . assertEqual ( self . callable_resolver . resolve_error_handler ( 404 ) , handler )
self . assertEqual ( self . callable_resolver . resolve_error_handler ( 500 ) , handler )
2010-03-26 15:08:24 +00:00
2013-11-02 21:34:05 +00:00
2014-04-05 06:04:46 +00:00
@override_settings ( ROOT_URLCONF = ' urlpatterns_reverse.urls_without_full_import ' )
2010-08-14 14:27:35 +00:00
class DefaultErrorHandlerTests ( TestCase ) :
def test_default_handler ( self ) :
" If the urls.py doesn ' t specify handlers, the defaults are used "
try :
response = self . client . get ( ' /test/ ' )
2011-03-03 15:04:39 +00:00
self . assertEqual ( response . status_code , 404 )
2010-08-14 14:27:35 +00:00
except AttributeError :
self . fail ( " Shouldn ' t get an AttributeError due to undefined 404 handler " )
try :
self . assertRaises ( ValueError , self . client . get , ' /bad_view/ ' )
except AttributeError :
self . fail ( " Shouldn ' t get an AttributeError due to undefined 500 handler " )
2013-11-02 21:34:05 +00:00
2014-04-05 06:04:46 +00:00
@override_settings ( ROOT_URLCONF = None )
2010-03-26 15:08:24 +00:00
class NoRootUrlConfTests ( TestCase ) :
""" Tests for handler404 and handler500 if urlconf is None """
def test_no_handler_exception ( self ) :
self . assertRaises ( ImproperlyConfigured , self . client . get , ' /test/me/ ' )
2010-08-05 07:09:47 +00:00
2013-11-02 21:34:05 +00:00
2014-04-05 06:04:46 +00:00
@override_settings ( ROOT_URLCONF = ' urlpatterns_reverse.namespace_urls ' )
2010-08-05 07:09:47 +00:00
class ResolverMatchTests ( TestCase ) :
def test_urlpattern_resolve ( self ) :
2013-10-03 07:20:04 +00:00
for path , url_name , app_name , namespace , view_name , func , args , kwargs in resolve_test_data :
2010-08-05 07:09:47 +00:00
# Test legacy support for extracting "function, args, kwargs"
match_func , match_args , match_kwargs = resolve ( path )
self . assertEqual ( match_func , func )
self . assertEqual ( match_args , args )
self . assertEqual ( match_kwargs , kwargs )
# Test ResolverMatch capabilities.
match = resolve ( path )
self . assertEqual ( match . __class__ , ResolverMatch )
2013-10-03 07:20:04 +00:00
self . assertEqual ( match . url_name , url_name )
2010-08-05 07:09:47 +00:00
self . assertEqual ( match . app_name , app_name )
self . assertEqual ( match . namespace , namespace )
2013-10-03 07:20:04 +00:00
self . assertEqual ( match . view_name , view_name )
2010-08-05 07:09:47 +00:00
self . assertEqual ( match . func , func )
2013-10-03 07:20:04 +00:00
self . assertEqual ( match . args , args )
self . assertEqual ( match . kwargs , kwargs )
2010-08-05 07:09:47 +00:00
# ... and for legacy purposes:
2011-03-03 15:04:39 +00:00
self . assertEqual ( match [ 0 ] , func )
self . assertEqual ( match [ 1 ] , args )
self . assertEqual ( match [ 2 ] , kwargs )
2011-06-16 16:41:14 +00:00
2012-09-27 13:06:58 +00:00
def test_resolver_match_on_request ( self ) :
response = self . client . get ( ' /resolver_match/ ' )
resolver_match = response . resolver_match
self . assertEqual ( resolver_match . url_name , ' test-resolver-match ' )
2013-03-10 22:24:34 +00:00
def test_resolver_match_on_request_before_resolution ( self ) :
request = HttpRequest ( )
self . assertIsNone ( request . resolver_match )
2013-11-02 21:34:05 +00:00
2014-04-05 06:04:46 +00:00
@override_settings ( ROOT_URLCONF = ' urlpatterns_reverse.erroneous_urls ' )
2011-06-16 16:41:14 +00:00
class ErroneousViewTests ( TestCase ) :
def test_erroneous_resolve ( self ) :
self . assertRaises ( ImportError , self . client . get , ' /erroneous_inner/ ' )
self . assertRaises ( ImportError , self . client . get , ' /erroneous_outer/ ' )
self . assertRaises ( ViewDoesNotExist , self . client . get , ' /missing_inner/ ' )
self . assertRaises ( ViewDoesNotExist , self . client . get , ' /missing_outer/ ' )
self . assertRaises ( ViewDoesNotExist , self . client . get , ' /uncallable/ ' )
2013-10-03 07:20:04 +00:00
# Regression test for #21157
self . assertRaises ( ImportError , self . client . get , ' /erroneous_unqualified/ ' )
2012-07-21 20:30:34 +00:00
def test_erroneous_reverse ( self ) :
"""
Ensure that a useful exception is raised when a regex is invalid in the
URLConf .
Refs #6170.
"""
# The regex error will be hit before NoReverseMatch can be raised
self . assertRaises ( ImproperlyConfigured , reverse , ' whatever blah blah ' )
2012-08-14 19:12:08 +00:00
2013-11-02 21:34:05 +00:00
2012-08-14 19:12:08 +00:00
class ViewLoadingTests ( TestCase ) :
def test_view_loading ( self ) :
2013-11-01 20:15:41 +00:00
self . assertEqual ( get_callable ( ' urlpatterns_reverse.views.empty_view ' ) ,
empty_view )
# passing a callable should return the callable
self . assertEqual ( get_callable ( empty_view ) , empty_view )
def test_exceptions ( self ) :
2012-08-14 19:12:08 +00:00
# A missing view (identified by an AttributeError) should raise
# ViewDoesNotExist, ...
2013-11-01 20:15:41 +00:00
six . assertRaisesRegex ( self , ViewDoesNotExist ,
" .*View does not exist in.* " ,
get_callable ,
' urlpatterns_reverse.views.i_should_not_exist ' )
2012-08-14 19:12:08 +00:00
# ... but if the AttributeError is caused by something else don't
# swallow it.
self . assertRaises ( AttributeError , get_callable ,
2013-11-01 20:15:41 +00:00
' urlpatterns_reverse.views_broken.i_am_broken ' )