diff options
| author | Justin Bronn <jbronn@gmail.com> | 2008-07-19 13:30:47 +0000 |
|---|---|---|
| committer | Justin Bronn <jbronn@gmail.com> | 2008-07-19 13:30:47 +0000 |
| commit | 149e731c3c5a2cc96b7d3c72070401df6c2a238e (patch) | |
| tree | 2a819f695246ab36139b7f8846085c9df1563bd8 /tests/regressiontests/admin_views | |
| parent | 5bf3565a263533e37b2e1217e8d447cb7e02f5b4 (diff) | |
gis: Merged revisions 7921,7926-7928,7938-7941,7945-7947,7949-7950,7952,7955-7956,7961,7964-7968,7970-7978 via svnmerge from trunk.
This includes the newforms-admin branch, and thus is backwards-incompatible. The geographic admin is _not_ in this changeset, and is forthcoming.
git-svn-id: http://code.djangoproject.com/svn/django/branches/gis@7979 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'tests/regressiontests/admin_views')
| -rw-r--r-- | tests/regressiontests/admin_views/__init__.py | 0 | ||||
| -rw-r--r-- | tests/regressiontests/admin_views/fixtures/admin-views-users.xml | 81 | ||||
| -rw-r--r-- | tests/regressiontests/admin_views/fixtures/string-primary-key.xml | 6 | ||||
| -rw-r--r-- | tests/regressiontests/admin_views/models.py | 61 | ||||
| -rw-r--r-- | tests/regressiontests/admin_views/tests.py | 362 | ||||
| -rw-r--r-- | tests/regressiontests/admin_views/urls.py | 7 |
6 files changed, 517 insertions, 0 deletions
diff --git a/tests/regressiontests/admin_views/__init__.py b/tests/regressiontests/admin_views/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/regressiontests/admin_views/__init__.py diff --git a/tests/regressiontests/admin_views/fixtures/admin-views-users.xml b/tests/regressiontests/admin_views/fixtures/admin-views-users.xml new file mode 100644 index 0000000000..8d6c62b58f --- /dev/null +++ b/tests/regressiontests/admin_views/fixtures/admin-views-users.xml @@ -0,0 +1,81 @@ +<?xml version="1.0" encoding="utf-8"?> +<django-objects version="1.0"> + <object pk="100" model="auth.user"> + <field type="CharField" name="username">super</field> + <field type="CharField" name="first_name">Super</field> + <field type="CharField" name="last_name">User</field> + <field type="CharField" name="email">super@example.com</field> + <field type="CharField" name="password">sha1$995a3$6011485ea3834267d719b4c801409b8b1ddd0158</field> + <field type="BooleanField" name="is_staff">True</field> + <field type="BooleanField" name="is_active">True</field> + <field type="BooleanField" name="is_superuser">True</field> + <field type="DateTimeField" name="last_login">2007-05-30 13:20:10</field> + <field type="DateTimeField" name="date_joined">2007-05-30 13:20:10</field> + <field to="auth.group" name="groups" rel="ManyToManyRel"></field> + <field to="auth.permission" name="user_permissions" rel="ManyToManyRel"></field> + </object> + <object pk="101" model="auth.user"> + <field type="CharField" name="username">adduser</field> + <field type="CharField" name="first_name">Add</field> + <field type="CharField" name="last_name">User</field> + <field type="CharField" name="email">auser@example.com</field> + <field type="CharField" name="password">sha1$995a3$6011485ea3834267d719b4c801409b8b1ddd0158</field> + <field type="BooleanField" name="is_staff">True</field> + <field type="BooleanField" name="is_active">True</field> + <field type="BooleanField" name="is_superuser">False</field> + <field type="DateTimeField" name="last_login">2007-05-30 13:20:10</field> + <field type="DateTimeField" name="date_joined">2007-05-30 13:20:10</field> + <field to="auth.group" name="groups" rel="ManyToManyRel"></field> + <field to="auth.permission" name="user_permissions" rel="ManyToManyRel"></field> + </object> + <object pk="102" model="auth.user"> + <field type="CharField" name="username">changeuser</field> + <field type="CharField" name="first_name">Change</field> + <field type="CharField" name="last_name">User</field> + <field type="CharField" name="email">cuser@example.com</field> + <field type="CharField" name="password">sha1$995a3$6011485ea3834267d719b4c801409b8b1ddd0158</field> + <field type="BooleanField" name="is_staff">True</field> + <field type="BooleanField" name="is_active">True</field> + <field type="BooleanField" name="is_superuser">False</field> + <field type="DateTimeField" name="last_login">2007-05-30 13:20:10</field> + <field type="DateTimeField" name="date_joined">2007-05-30 13:20:10</field> + <field to="auth.group" name="groups" rel="ManyToManyRel"></field> + <field to="auth.permission" name="user_permissions" rel="ManyToManyRel"></field> + </object> + <object pk="103" model="auth.user"> + <field type="CharField" name="username">deleteuser</field> + <field type="CharField" name="first_name">Delete</field> + <field type="CharField" name="last_name">User</field> + <field type="CharField" name="email">duser@example.com</field> + <field type="CharField" name="password">sha1$995a3$6011485ea3834267d719b4c801409b8b1ddd0158</field> + <field type="BooleanField" name="is_staff">True</field> + <field type="BooleanField" name="is_active">True</field> + <field type="BooleanField" name="is_superuser">False</field> + <field type="DateTimeField" name="last_login">2007-05-30 13:20:10</field> + <field type="DateTimeField" name="date_joined">2007-05-30 13:20:10</field> + <field to="auth.group" name="groups" rel="ManyToManyRel"></field> + <field to="auth.permission" name="user_permissions" rel="ManyToManyRel"></field> + </object> + <object pk="104" model="auth.user"> + <field type="CharField" name="username">joepublic</field> + <field type="CharField" name="first_name">Joe</field> + <field type="CharField" name="last_name">Public</field> + <field type="CharField" name="email">joepublic@example.com</field> + <field type="CharField" name="password">sha1$995a3$6011485ea3834267d719b4c801409b8b1ddd0158</field> + <field type="BooleanField" name="is_staff">False</field> + <field type="BooleanField" name="is_active">True</field> + <field type="BooleanField" name="is_superuser">False</field> + <field type="DateTimeField" name="last_login">2007-05-30 13:20:10</field> + <field type="DateTimeField" name="date_joined">2007-05-30 13:20:10</field> + <field to="auth.group" name="groups" rel="ManyToManyRel"></field> + <field to="auth.permission" name="user_permissions" rel="ManyToManyRel"></field> + </object> + <object pk="1" model="admin_views.section"> + <field type="CharField" name="name">Test section</field> + </object> + <object pk="1" model="admin_views.article"> + <field type="TextField" name="content"><p>test content</p></field> + <field type="DateTimeField" name="date">2008-03-18 11:54:58</field> + <field to="admin_views.section" name="section" rel="ManyToOneRel">1</field> + </object> +</django-objects>
\ No newline at end of file diff --git a/tests/regressiontests/admin_views/fixtures/string-primary-key.xml b/tests/regressiontests/admin_views/fixtures/string-primary-key.xml new file mode 100644 index 0000000000..8e1dbf047f --- /dev/null +++ b/tests/regressiontests/admin_views/fixtures/string-primary-key.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<django-objects version="1.0"> + <object pk="1" model="admin_views.modelwithstringprimarykey"> + <field type="CharField" name="id"><![CDATA[abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 1234567890 -_.!~*'() ;/?:@&=+$, <>#%" {}|\^[]`]]></field> + </object> +</django-objects>
\ No newline at end of file diff --git a/tests/regressiontests/admin_views/models.py b/tests/regressiontests/admin_views/models.py new file mode 100644 index 0000000000..2062107397 --- /dev/null +++ b/tests/regressiontests/admin_views/models.py @@ -0,0 +1,61 @@ +from django.db import models +from django.contrib import admin + +class Section(models.Model): + """ + A simple section that links to articles, to test linking to related items + in admin views. + """ + name = models.CharField(max_length=100) + +class Article(models.Model): + """ + A simple article to test admin views. Test backwards compatibility. + """ + content = models.TextField() + date = models.DateTimeField() + section = models.ForeignKey(Section) + +class ArticleAdmin(admin.ModelAdmin): + list_display = ('content', 'date') + list_filter = ('date',) + + def changelist_view(self, request): + "Test that extra_context works" + return super(ArticleAdmin, self).changelist_view( + request, extra_context={ + 'extra_var': 'Hello!' + } + ) + +class CustomArticle(models.Model): + content = models.TextField() + date = models.DateTimeField() + +class CustomArticleAdmin(admin.ModelAdmin): + """ + Tests various hooks for using custom templates and contexts. + """ + change_list_template = 'custom_admin/change_list.html' + change_form_template = 'custom_admin/change_form.html' + object_history_template = 'custom_admin/object_history.html' + delete_confirmation_template = 'custom_admin/delete_confirmation.html' + + def changelist_view(self, request): + "Test that extra_context works" + return super(CustomArticleAdmin, self).changelist_view( + request, extra_context={ + 'extra_var': 'Hello!' + } + ) + +class ModelWithStringPrimaryKey(models.Model): + id = models.CharField(max_length=255, primary_key=True) + + def __unicode__(self): + return self.id + +admin.site.register(Article, ArticleAdmin) +admin.site.register(CustomArticle, CustomArticleAdmin) +admin.site.register(Section) +admin.site.register(ModelWithStringPrimaryKey) diff --git a/tests/regressiontests/admin_views/tests.py b/tests/regressiontests/admin_views/tests.py new file mode 100644 index 0000000000..ad50928aa9 --- /dev/null +++ b/tests/regressiontests/admin_views/tests.py @@ -0,0 +1,362 @@ + +from django.test import TestCase +from django.contrib.auth.models import User, Permission +from django.contrib.contenttypes.models import ContentType +from django.contrib.admin.models import LogEntry +from django.contrib.admin.sites import LOGIN_FORM_KEY, _encode_post_data +from django.contrib.admin.util import quote +from django.utils.html import escape + +# local test models +from models import Article, CustomArticle, Section, ModelWithStringPrimaryKey + +def get_perm(Model, perm): + """Return the permission object, for the Model""" + ct = ContentType.objects.get_for_model(Model) + return Permission.objects.get(content_type=ct,codename=perm) + +class AdminViewPermissionsTest(TestCase): + """Tests for Admin Views Permissions.""" + + fixtures = ['admin-views-users.xml'] + + def setUp(self): + """Test setup.""" + # Setup permissions, for our users who can add, change, and delete. + # We can't put this into the fixture, because the content type id + # and the permission id could be different on each run of the test. + + opts = Article._meta + + # User who can add Articles + add_user = User.objects.get(username='adduser') + add_user.user_permissions.add(get_perm(Article, + opts.get_add_permission())) + + # User who can change Articles + change_user = User.objects.get(username='changeuser') + change_user.user_permissions.add(get_perm(Article, + opts.get_change_permission())) + + # User who can delete Articles + delete_user = User.objects.get(username='deleteuser') + delete_user.user_permissions.add(get_perm(Article, + opts.get_delete_permission())) + + delete_user.user_permissions.add(get_perm(Section, + Section._meta.get_delete_permission())) + + # login POST dicts + self.super_login = {'post_data': _encode_post_data({}), + LOGIN_FORM_KEY: 1, + 'username': 'super', + 'password': 'secret'} + self.super_email_login = {'post_data': _encode_post_data({}), + LOGIN_FORM_KEY: 1, + 'username': 'super@example.com', + 'password': 'secret'} + self.super_email_bad_login = {'post_data': _encode_post_data({}), + LOGIN_FORM_KEY: 1, + 'username': 'super@example.com', + 'password': 'notsecret'} + self.adduser_login = {'post_data': _encode_post_data({}), + LOGIN_FORM_KEY: 1, + 'username': 'adduser', + 'password': 'secret'} + self.changeuser_login = {'post_data': _encode_post_data({}), + LOGIN_FORM_KEY: 1, + 'username': 'changeuser', + 'password': 'secret'} + self.deleteuser_login = {'post_data': _encode_post_data({}), + LOGIN_FORM_KEY: 1, + 'username': 'deleteuser', + 'password': 'secret'} + self.joepublic_login = {'post_data': _encode_post_data({}), + LOGIN_FORM_KEY: 1, + 'username': 'joepublic', + 'password': 'secret'} + + def testTrailingSlashRequired(self): + """ + If you leave off the trailing slash, app should redirect and add it. + """ + self.client.post('/test_admin/admin/', self.super_login) + + request = self.client.get( + '/test_admin/admin/admin_views/article/add' + ) + self.assertRedirects(request, + '/test_admin/admin/admin_views/article/add/' + ) + + def testLogin(self): + """ + Make sure only staff members can log in. + + Successful posts to the login page will redirect to the orignal url. + Unsuccessfull attempts will continue to render the login page with + a 200 status code. + """ + # Super User + request = self.client.get('/test_admin/admin/') + self.failUnlessEqual(request.status_code, 200) + login = self.client.post('/test_admin/admin/', self.super_login) + self.assertRedirects(login, '/test_admin/admin/') + self.assertFalse(login.context) + self.client.get('/test_admin/admin/logout/') + + # Test if user enters e-mail address + request = self.client.get('/test_admin/admin/') + self.failUnlessEqual(request.status_code, 200) + login = self.client.post('/test_admin/admin/', self.super_email_login) + self.assertContains(login, "Your e-mail address is not your username") + # only correct passwords get a username hint + login = self.client.post('/test_admin/admin/', self.super_email_bad_login) + self.assertContains(login, "Usernames cannot contain the '@' character") + new_user = User(username='jondoe', password='secret', email='super@example.com') + new_user.save() + # check to ensure if there are multiple e-mail addresses a user doesn't get a 500 + login = self.client.post('/test_admin/admin/', self.super_email_login) + self.assertContains(login, "Usernames cannot contain the '@' character") + + # Add User + request = self.client.get('/test_admin/admin/') + self.failUnlessEqual(request.status_code, 200) + login = self.client.post('/test_admin/admin/', self.adduser_login) + self.assertRedirects(login, '/test_admin/admin/') + self.assertFalse(login.context) + self.client.get('/test_admin/admin/logout/') + + # Change User + request = self.client.get('/test_admin/admin/') + self.failUnlessEqual(request.status_code, 200) + login = self.client.post('/test_admin/admin/', self.changeuser_login) + self.assertRedirects(login, '/test_admin/admin/') + self.assertFalse(login.context) + self.client.get('/test_admin/admin/logout/') + + # Delete User + request = self.client.get('/test_admin/admin/') + self.failUnlessEqual(request.status_code, 200) + login = self.client.post('/test_admin/admin/', self.deleteuser_login) + self.assertRedirects(login, '/test_admin/admin/') + self.assertFalse(login.context) + self.client.get('/test_admin/admin/logout/') + + # Regular User should not be able to login. + request = self.client.get('/test_admin/admin/') + self.failUnlessEqual(request.status_code, 200) + login = self.client.post('/test_admin/admin/', self.joepublic_login) + self.failUnlessEqual(login.status_code, 200) + # Login.context is a list of context dicts we just need to check the first one. + self.assert_(login.context[0].get('error_message')) + + def testAddView(self): + """Test add view restricts access and actually adds items.""" + + add_dict = {'content': '<p>great article</p>', + 'date_0': '2008-03-18', 'date_1': '10:54:39', + 'section': 1} + + # Change User should not have access to add articles + self.client.get('/test_admin/admin/') + self.client.post('/test_admin/admin/', self.changeuser_login) + request = self.client.get('/test_admin/admin/admin_views/article/add/') + self.failUnlessEqual(request.status_code, 403) + # Try POST just to make sure + post = self.client.post('/test_admin/admin/admin_views/article/add/', add_dict) + self.failUnlessEqual(post.status_code, 403) + self.failUnlessEqual(Article.objects.all().count(), 1) + self.client.get('/test_admin/admin/logout/') + + # Add user may login and POST to add view, then redirect to admin root + self.client.get('/test_admin/admin/') + self.client.post('/test_admin/admin/', self.adduser_login) + post = self.client.post('/test_admin/admin/admin_views/article/add/', add_dict) + self.assertRedirects(post, '/test_admin/admin/') + self.failUnlessEqual(Article.objects.all().count(), 2) + self.client.get('/test_admin/admin/logout/') + + # Super can add too, but is redirected to the change list view + self.client.get('/test_admin/admin/') + self.client.post('/test_admin/admin/', self.super_login) + post = self.client.post('/test_admin/admin/admin_views/article/add/', add_dict) + self.assertRedirects(post, '/test_admin/admin/admin_views/article/') + self.failUnlessEqual(Article.objects.all().count(), 3) + self.client.get('/test_admin/admin/logout/') + + # Check and make sure that if user expires, data still persists + post = self.client.post('/test_admin/admin/admin_views/article/add/', add_dict) + self.assertContains(post, 'Please log in again, because your session has expired.') + self.super_login['post_data'] = _encode_post_data(add_dict) + post = self.client.post('/test_admin/admin/admin_views/article/add/', self.super_login) + self.assertRedirects(post, '/test_admin/admin/admin_views/article/') + self.failUnlessEqual(Article.objects.all().count(), 4) + self.client.get('/test_admin/admin/logout/') + + def testChangeView(self): + """Change view should restrict access and allow users to edit items.""" + + change_dict = {'content': '<p>edited article</p>', + 'date_0': '2008-03-18', 'date_1': '10:54:39', + 'section': 1} + + # add user shoud not be able to view the list of article or change any of them + self.client.get('/test_admin/admin/') + self.client.post('/test_admin/admin/', self.adduser_login) + request = self.client.get('/test_admin/admin/admin_views/article/') + self.failUnlessEqual(request.status_code, 403) + request = self.client.get('/test_admin/admin/admin_views/article/1/') + self.failUnlessEqual(request.status_code, 403) + post = self.client.post('/test_admin/admin/admin_views/article/1/', change_dict) + self.failUnlessEqual(post.status_code, 403) + self.client.get('/test_admin/admin/logout/') + + # change user can view all items and edit them + self.client.get('/test_admin/admin/') + self.client.post('/test_admin/admin/', self.changeuser_login) + request = self.client.get('/test_admin/admin/admin_views/article/') + self.failUnlessEqual(request.status_code, 200) + request = self.client.get('/test_admin/admin/admin_views/article/1/') + self.failUnlessEqual(request.status_code, 200) + post = self.client.post('/test_admin/admin/admin_views/article/1/', change_dict) + self.assertRedirects(post, '/test_admin/admin/admin_views/article/') + self.failUnlessEqual(Article.objects.get(pk=1).content, '<p>edited article</p>') + self.client.get('/test_admin/admin/logout/') + + def testCustomModelAdminTemplates(self): + self.client.get('/test_admin/admin/') + self.client.post('/test_admin/admin/', self.super_login) + + # Test custom change list template with custom extra context + request = self.client.get('/test_admin/admin/admin_views/customarticle/') + self.failUnlessEqual(request.status_code, 200) + self.assert_("var hello = 'Hello!';" in request.content) + self.assertTemplateUsed(request, 'custom_admin/change_list.html') + + # Test custom change form template + request = self.client.get('/test_admin/admin/admin_views/customarticle/add/') + self.assertTemplateUsed(request, 'custom_admin/change_form.html') + + # Add an article so we can test delete and history views + post = self.client.post('/test_admin/admin/admin_views/customarticle/add/', { + 'content': '<p>great article</p>', + 'date_0': '2008-03-18', + 'date_1': '10:54:39' + }) + self.assertRedirects(post, '/test_admin/admin/admin_views/customarticle/') + self.failUnlessEqual(CustomArticle.objects.all().count(), 1) + + # Test custom delete and object history templates + request = self.client.get('/test_admin/admin/admin_views/customarticle/1/delete/') + self.assertTemplateUsed(request, 'custom_admin/delete_confirmation.html') + request = self.client.get('/test_admin/admin/admin_views/customarticle/1/history/') + self.assertTemplateUsed(request, 'custom_admin/object_history.html') + + self.client.get('/test_admin/admin/logout/') + + def testCustomAdminSiteTemplates(self): + from django.contrib import admin + self.assertEqual(admin.site.index_template, None) + self.assertEqual(admin.site.login_template, None) + + self.client.get('/test_admin/admin/logout/') + request = self.client.get('/test_admin/admin/') + self.assertTemplateUsed(request, 'admin/login.html') + self.client.post('/test_admin/admin/', self.changeuser_login) + request = self.client.get('/test_admin/admin/') + self.assertTemplateUsed(request, 'admin/index.html') + + self.client.get('/test_admin/admin/logout/') + admin.site.login_template = 'custom_admin/login.html' + admin.site.index_template = 'custom_admin/index.html' + request = self.client.get('/test_admin/admin/') + self.assertTemplateUsed(request, 'custom_admin/login.html') + self.assert_('Hello from a custom login template' in request.content) + self.client.post('/test_admin/admin/', self.changeuser_login) + request = self.client.get('/test_admin/admin/') + self.assertTemplateUsed(request, 'custom_admin/index.html') + self.assert_('Hello from a custom index template' in request.content) + + # Finally, using monkey patching check we can inject custom_context arguments in to index + original_index = admin.site.index + def index(*args, **kwargs): + kwargs['extra_context'] = {'foo': '*bar*'} + return original_index(*args, **kwargs) + admin.site.index = index + request = self.client.get('/test_admin/admin/') + self.assertTemplateUsed(request, 'custom_admin/index.html') + self.assert_('Hello from a custom index template *bar*' in request.content) + + self.client.get('/test_admin/admin/logout/') + del admin.site.index # Resets to using the original + admin.site.login_template = None + admin.site.index_template = None + + def testDeleteView(self): + """Delete view should restrict access and actually delete items.""" + + delete_dict = {'post': 'yes'} + + # add user shoud not be able to delete articles + self.client.get('/test_admin/admin/') + self.client.post('/test_admin/admin/', self.adduser_login) + request = self.client.get('/test_admin/admin/admin_views/article/1/delete/') + self.failUnlessEqual(request.status_code, 403) + post = self.client.post('/test_admin/admin/admin_views/article/1/delete/', delete_dict) + self.failUnlessEqual(post.status_code, 403) + self.failUnlessEqual(Article.objects.all().count(), 1) + self.client.get('/test_admin/admin/logout/') + + # Delete user can delete + self.client.get('/test_admin/admin/') + self.client.post('/test_admin/admin/', self.deleteuser_login) + response = self.client.get('/test_admin/admin/admin_views/section/1/delete/') + # test response contains link to related Article + self.assertContains(response, "admin_views/article/1/") + + response = self.client.get('/test_admin/admin/admin_views/article/1/delete/') + self.failUnlessEqual(response.status_code, 200) + post = self.client.post('/test_admin/admin/admin_views/article/1/delete/', delete_dict) + self.assertRedirects(post, '/test_admin/admin/') + self.failUnlessEqual(Article.objects.all().count(), 0) + self.client.get('/test_admin/admin/logout/') + +class AdminViewStringPrimaryKeyTest(TestCase): + fixtures = ['admin-views-users.xml', 'string-primary-key.xml'] + + def __init__(self, *args): + super(AdminViewStringPrimaryKeyTest, self).__init__(*args) + self.pk = """abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 1234567890 -_.!~*'() ;/?:@&=+$, <>#%" {}|\^[]`""" + + def setUp(self): + self.client.login(username='super', password='secret') + content_type_pk = ContentType.objects.get_for_model(ModelWithStringPrimaryKey).pk + LogEntry.objects.log_action(100, content_type_pk, self.pk, self.pk, 2, change_message='') + + def tearDown(self): + self.client.logout() + + def test_get_change_view(self): + "Retrieving the object using urlencoded form of primary key should work" + response = self.client.get('/test_admin/admin/admin_views/modelwithstringprimarykey/%s/' % quote(self.pk)) + self.assertContains(response, escape(self.pk)) + self.failUnlessEqual(response.status_code, 200) + + def test_changelist_to_changeform_link(self): + "The link from the changelist referring to the changeform of the object should be quoted" + response = self.client.get('/test_admin/admin/admin_views/modelwithstringprimarykey/') + should_contain = """<tr class="row1"><th><a href="%s/">%s</a></th></tr>""" % (quote(self.pk), escape(self.pk)) + self.assertContains(response, should_contain) + + def test_recentactions_link(self): + "The link from the recent actions list referring to the changeform of the object should be quoted" + response = self.client.get('/test_admin/admin/') + should_contain = """<a href="admin_views/modelwithstringprimarykey/%s/">%s</a>""" % (quote(self.pk), escape(self.pk)) + self.assertContains(response, should_contain) + + def test_deleteconfirmation_link(self): + "The link from the delete confirmation page referring back to the changeform of the object should be quoted" + response = self.client.get('/test_admin/admin/admin_views/modelwithstringprimarykey/%s/delete/' % quote(self.pk)) + should_contain = """<a href="../../%s/">%s</a>""" % (quote(self.pk), escape(self.pk)) + self.assertContains(response, should_contain) diff --git a/tests/regressiontests/admin_views/urls.py b/tests/regressiontests/admin_views/urls.py new file mode 100644 index 0000000000..e556812a45 --- /dev/null +++ b/tests/regressiontests/admin_views/urls.py @@ -0,0 +1,7 @@ +from django.conf.urls.defaults import * +from django.contrib import admin + +urlpatterns = patterns('', + (r'^admin/doc/', include('django.contrib.admindocs.urls')), + (r'^admin/(.*)', admin.site.root), +) |
