summaryrefslogtreecommitdiff
path: root/tests/regressiontests
diff options
context:
space:
mode:
authorJustin Bronn <jbronn@gmail.com>2008-07-04 20:16:22 +0000
committerJustin Bronn <jbronn@gmail.com>2008-07-04 20:16:22 +0000
commitbc3d6b49089ef0ea7d174eb383b1019b6a4a061a (patch)
treeb95728880e8a968ae6a921a21cec501f6a278d08 /tests/regressiontests
parentaef8a8305d2190b00386b8b1603deb03a2949f5b (diff)
gis: Merged revisions 7772-7808,7811-7814,7816-7823,7826-7829,7831-7833,7835 via svnmerge from trunk. Modified `GeoWhereNode` accordingly for changes in r7835.
git-svn-id: http://code.djangoproject.com/svn/django/branches/gis@7836 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'tests/regressiontests')
-rw-r--r--tests/regressiontests/bug639/tests.py11
-rw-r--r--tests/regressiontests/datastructures/tests.py25
-rw-r--r--tests/regressiontests/extra_regress/__init__.py0
-rw-r--r--tests/regressiontests/extra_regress/models.py55
-rw-r--r--tests/regressiontests/file_uploads/__init__.py0
-rw-r--r--tests/regressiontests/file_uploads/models.py2
-rw-r--r--tests/regressiontests/file_uploads/tests.py158
-rw-r--r--tests/regressiontests/file_uploads/uploadhandler.py26
-rw-r--r--tests/regressiontests/file_uploads/urls.py10
-rw-r--r--tests/regressiontests/file_uploads/views.py70
-rw-r--r--tests/regressiontests/fixtures_regress/fixtures/big-fixture.json83
-rw-r--r--tests/regressiontests/fixtures_regress/fixtures/model-inheritance.json4
-rw-r--r--tests/regressiontests/fixtures_regress/models.py48
-rw-r--r--tests/regressiontests/forms/error_messages.py9
-rw-r--r--tests/regressiontests/forms/fields.py33
-rw-r--r--tests/regressiontests/forms/forms.py5
-rw-r--r--tests/regressiontests/many_to_one_regress/models.py40
-rw-r--r--tests/regressiontests/model_fields/tests.py17
-rw-r--r--tests/regressiontests/model_inheritance_regress/models.py22
-rw-r--r--tests/regressiontests/model_inheritance_select_related/__init__.py0
-rw-r--r--tests/regressiontests/model_inheritance_select_related/models.py47
-rw-r--r--tests/regressiontests/queries/models.py132
-rw-r--r--tests/regressiontests/select_related_regress/__init__.py0
-rw-r--r--tests/regressiontests/select_related_regress/models.py60
-rw-r--r--tests/regressiontests/string_lookup/models.py6
-rw-r--r--tests/regressiontests/test_client_regress/models.py31
-rw-r--r--tests/regressiontests/test_client_regress/urls.py1
-rw-r--r--tests/regressiontests/test_client_regress/views.py24
28 files changed, 790 insertions, 129 deletions
diff --git a/tests/regressiontests/bug639/tests.py b/tests/regressiontests/bug639/tests.py
index f9596d06cb..2726dec897 100644
--- a/tests/regressiontests/bug639/tests.py
+++ b/tests/regressiontests/bug639/tests.py
@@ -9,6 +9,7 @@ import unittest
from regressiontests.bug639.models import Photo
from django.http import QueryDict
from django.utils.datastructures import MultiValueDict
+from django.core.files.uploadedfile import SimpleUploadedFile
class Bug639Test(unittest.TestCase):
@@ -21,12 +22,8 @@ class Bug639Test(unittest.TestCase):
# Fake a request query dict with the file
qd = QueryDict("title=Testing&image=", mutable=True)
- qd["image_file"] = {
- "filename" : "test.jpg",
- "content-type" : "image/jpeg",
- "content" : img
- }
-
+ qd["image_file"] = SimpleUploadedFile('test.jpg', img, 'image/jpeg')
+
manip = Photo.AddManipulator()
manip.do_html2python(qd)
p = manip.save(qd)
@@ -39,4 +36,4 @@ class Bug639Test(unittest.TestCase):
Make sure to delete the "uploaded" file to avoid clogging /tmp.
"""
p = Photo.objects.get()
- os.unlink(p.get_image_filename()) \ No newline at end of file
+ os.unlink(p.get_image_filename())
diff --git a/tests/regressiontests/datastructures/tests.py b/tests/regressiontests/datastructures/tests.py
index d6141b09ce..62c57bc019 100644
--- a/tests/regressiontests/datastructures/tests.py
+++ b/tests/regressiontests/datastructures/tests.py
@@ -117,14 +117,25 @@ Init from sequence of tuples
>>> d['person']['2']['firstname']
['Adrian']
-### FileDict ################################################################
-
->>> d = FileDict({'content': 'once upon a time...'})
->>> repr(d)
-"{'content': '<omitted>'}"
->>> d = FileDict({'other-key': 'once upon a time...'})
+### ImmutableList ################################################################
+>>> d = ImmutableList(range(10))
+>>> d.sort()
+Traceback (most recent call last):
+ File "<stdin>", line 1, in <module>
+ File "/var/lib/python-support/python2.5/django/utils/datastructures.py", line 359, in complain
+ raise AttributeError, self.warning
+AttributeError: ImmutableList object is immutable.
>>> repr(d)
-"{'other-key': 'once upon a time...'}"
+'(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)'
+>>> d = ImmutableList(range(10), warning="Object is immutable!")
+>>> d[1]
+1
+>>> d[1] = 'test'
+Traceback (most recent call last):
+ File "<stdin>", line 1, in <module>
+ File "/var/lib/python-support/python2.5/django/utils/datastructures.py", line 359, in complain
+ raise AttributeError, self.warning
+AttributeError: Object is immutable!
### DictWrapper #############################################################
diff --git a/tests/regressiontests/extra_regress/__init__.py b/tests/regressiontests/extra_regress/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/regressiontests/extra_regress/__init__.py
diff --git a/tests/regressiontests/extra_regress/models.py b/tests/regressiontests/extra_regress/models.py
new file mode 100644
index 0000000000..e6665222bf
--- /dev/null
+++ b/tests/regressiontests/extra_regress/models.py
@@ -0,0 +1,55 @@
+import copy
+
+from django.db import models
+from django.db.models.query import Q
+
+
+class RevisionableModel(models.Model):
+ base = models.ForeignKey('self', null=True)
+ title = models.CharField(blank=True, max_length=255)
+
+ def __unicode__(self):
+ return u"%s (%s, %s)" % (self.title, self.id, self.base.id)
+
+ def save(self):
+ super(RevisionableModel, self).save()
+ if not self.base:
+ self.base = self
+ super(RevisionableModel, self).save()
+
+ def new_revision(self):
+ new_revision = copy.copy(self)
+ new_revision.pk = None
+ return new_revision
+
+__test__ = {"API_TESTS": """
+### Regression tests for #7314 and #7372
+
+>>> rm = RevisionableModel.objects.create(title='First Revision')
+>>> rm.pk, rm.base.pk
+(1, 1)
+
+>>> rm2 = rm.new_revision()
+>>> rm2.title = "Second Revision"
+>>> rm2.save()
+>>> print u"%s of %s" % (rm2.title, rm2.base.title)
+Second Revision of First Revision
+
+>>> rm2.pk, rm2.base.pk
+(2, 1)
+
+Queryset to match most recent revision:
+>>> qs = RevisionableModel.objects.extra(where=["%(table)s.id IN (SELECT MAX(rev.id) FROM %(table)s rev GROUP BY rev.base_id)" % {'table': RevisionableModel._meta.db_table,}],)
+>>> qs
+[<RevisionableModel: Second Revision (2, 1)>]
+
+Queryset to search for string in title:
+>>> qs2 = RevisionableModel.objects.filter(title__contains="Revision")
+>>> qs2
+[<RevisionableModel: First Revision (1, 1)>, <RevisionableModel: Second Revision (2, 1)>]
+
+Following queryset should return the most recent revision:
+>>> qs & qs2
+[<RevisionableModel: Second Revision (2, 1)>]
+
+"""}
diff --git a/tests/regressiontests/file_uploads/__init__.py b/tests/regressiontests/file_uploads/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/regressiontests/file_uploads/__init__.py
diff --git a/tests/regressiontests/file_uploads/models.py b/tests/regressiontests/file_uploads/models.py
new file mode 100644
index 0000000000..2d5607b2a7
--- /dev/null
+++ b/tests/regressiontests/file_uploads/models.py
@@ -0,0 +1,2 @@
+# This file unintentionally left blank.
+# Oops. \ No newline at end of file
diff --git a/tests/regressiontests/file_uploads/tests.py b/tests/regressiontests/file_uploads/tests.py
new file mode 100644
index 0000000000..8992298470
--- /dev/null
+++ b/tests/regressiontests/file_uploads/tests.py
@@ -0,0 +1,158 @@
+import os
+import sha
+import tempfile
+from django.test import TestCase, client
+from django.utils import simplejson
+
+class FileUploadTests(TestCase):
+ def test_simple_upload(self):
+ post_data = {
+ 'name': 'Ringo',
+ 'file_field': open(__file__),
+ }
+ response = self.client.post('/file_uploads/upload/', post_data)
+ self.assertEqual(response.status_code, 200)
+
+ def test_large_upload(self):
+ tdir = tempfile.gettempdir()
+
+ file1 = tempfile.NamedTemporaryFile(suffix=".file1", dir=tdir)
+ file1.write('a' * (2 ** 21))
+ file1.seek(0)
+
+ file2 = tempfile.NamedTemporaryFile(suffix=".file2", dir=tdir)
+ file2.write('a' * (10 * 2 ** 20))
+ file2.seek(0)
+
+ # This file contains chinese symbols for a name.
+ file3 = open(os.path.join(tdir, u'test_&#20013;&#25991;_Orl\u00e9ans.jpg'), 'w+b')
+ file3.write('b' * (2 ** 10))
+ file3.seek(0)
+
+ post_data = {
+ 'name': 'Ringo',
+ 'file_field1': open(file1.name),
+ 'file_field2': open(file2.name),
+ 'file_unicode': file3,
+ }
+
+ for key in post_data.keys():
+ try:
+ post_data[key + '_hash'] = sha.new(post_data[key].read()).hexdigest()
+ post_data[key].seek(0)
+ except AttributeError:
+ post_data[key + '_hash'] = sha.new(post_data[key]).hexdigest()
+
+ response = self.client.post('/file_uploads/verify/', post_data)
+
+ try:
+ os.unlink(file3.name)
+ except:
+ pass
+
+ self.assertEqual(response.status_code, 200)
+
+ def test_dangerous_file_names(self):
+ """Uploaded file names should be sanitized before ever reaching the view."""
+ # This test simulates possible directory traversal attacks by a
+ # malicious uploader We have to do some monkeybusiness here to construct
+ # a malicious payload with an invalid file name (containing os.sep or
+ # os.pardir). This similar to what an attacker would need to do when
+ # trying such an attack.
+ scary_file_names = [
+ "/tmp/hax0rd.txt", # Absolute path, *nix-style.
+ "C:\\Windows\\hax0rd.txt", # Absolute path, win-syle.
+ "C:/Windows/hax0rd.txt", # Absolute path, broken-style.
+ "\\tmp\\hax0rd.txt", # Absolute path, broken in a different way.
+ "/tmp\\hax0rd.txt", # Absolute path, broken by mixing.
+ "subdir/hax0rd.txt", # Descendant path, *nix-style.
+ "subdir\\hax0rd.txt", # Descendant path, win-style.
+ "sub/dir\\hax0rd.txt", # Descendant path, mixed.
+ "../../hax0rd.txt", # Relative path, *nix-style.
+ "..\\..\\hax0rd.txt", # Relative path, win-style.
+ "../..\\hax0rd.txt" # Relative path, mixed.
+ ]
+
+ payload = []
+ for i, name in enumerate(scary_file_names):
+ payload.extend([
+ '--' + client.BOUNDARY,
+ 'Content-Disposition: form-data; name="file%s"; filename="%s"' % (i, name),
+ 'Content-Type: application/octet-stream',
+ '',
+ 'You got pwnd.'
+ ])
+ payload.extend([
+ '--' + client.BOUNDARY + '--',
+ '',
+ ])
+
+ payload = "\r\n".join(payload)
+ r = {
+ 'CONTENT_LENGTH': len(payload),
+ 'CONTENT_TYPE': client.MULTIPART_CONTENT,
+ 'PATH_INFO': "/file_uploads/echo/",
+ 'REQUEST_METHOD': 'POST',
+ 'wsgi.input': client.FakePayload(payload),
+ }
+ response = self.client.request(**r)
+
+ # The filenames should have been sanitized by the time it got to the view.
+ recieved = simplejson.loads(response.content)
+ for i, name in enumerate(scary_file_names):
+ got = recieved["file%s" % i]
+ self.assertEqual(got, "hax0rd.txt")
+
+ def test_filename_overflow(self):
+ """File names over 256 characters (dangerous on some platforms) get fixed up."""
+ name = "%s.txt" % ("f"*500)
+ payload = "\r\n".join([
+ '--' + client.BOUNDARY,
+ 'Content-Disposition: form-data; name="file"; filename="%s"' % name,
+ 'Content-Type: application/octet-stream',
+ '',
+ 'Oops.'
+ '--' + client.BOUNDARY + '--',
+ '',
+ ])
+ r = {
+ 'CONTENT_LENGTH': len(payload),
+ 'CONTENT_TYPE': client.MULTIPART_CONTENT,
+ 'PATH_INFO': "/file_uploads/echo/",
+ 'REQUEST_METHOD': 'POST',
+ 'wsgi.input': client.FakePayload(payload),
+ }
+ got = simplejson.loads(self.client.request(**r).content)
+ self.assert_(len(got['file']) < 256, "Got a long file name (%s characters)." % len(got['file']))
+
+ def test_custom_upload_handler(self):
+ # A small file (under the 5M quota)
+ smallfile = tempfile.NamedTemporaryFile()
+ smallfile.write('a' * (2 ** 21))
+
+ # A big file (over the quota)
+ bigfile = tempfile.NamedTemporaryFile()
+ bigfile.write('a' * (10 * 2 ** 20))
+
+ # Small file posting should work.
+ response = self.client.post('/file_uploads/quota/', {'f': open(smallfile.name)})
+ got = simplejson.loads(response.content)
+ self.assert_('f' in got)
+
+ # Large files don't go through.
+ response = self.client.post("/file_uploads/quota/", {'f': open(bigfile.name)})
+ got = simplejson.loads(response.content)
+ self.assert_('f' not in got)
+
+ def test_broken_custom_upload_handler(self):
+ f = tempfile.NamedTemporaryFile()
+ f.write('a' * (2 ** 21))
+
+ # AttributeError: You cannot alter upload handlers after the upload has been processed.
+ self.assertRaises(
+ AttributeError,
+ self.client.post,
+ '/file_uploads/quota/broken/',
+ {'f': open(f.name)}
+ )
+ \ No newline at end of file
diff --git a/tests/regressiontests/file_uploads/uploadhandler.py b/tests/regressiontests/file_uploads/uploadhandler.py
new file mode 100644
index 0000000000..54f82f626c
--- /dev/null
+++ b/tests/regressiontests/file_uploads/uploadhandler.py
@@ -0,0 +1,26 @@
+"""
+Upload handlers to test the upload API.
+"""
+
+from django.core.files.uploadhandler import FileUploadHandler, StopUpload
+
+class QuotaUploadHandler(FileUploadHandler):
+ """
+ This test upload handler terminates the connection if more than a quota
+ (5MB) is uploaded.
+ """
+
+ QUOTA = 5 * 2**20 # 5 MB
+
+ def __init__(self, request=None):
+ super(QuotaUploadHandler, self).__init__(request)
+ self.total_upload = 0
+
+ def receive_data_chunk(self, raw_data, start):
+ self.total_upload += len(raw_data)
+ if self.total_upload >= self.QUOTA:
+ raise StopUpload(connection_reset=True)
+ return raw_data
+
+ def file_complete(self, file_size):
+ return None \ No newline at end of file
diff --git a/tests/regressiontests/file_uploads/urls.py b/tests/regressiontests/file_uploads/urls.py
new file mode 100644
index 0000000000..529bee312d
--- /dev/null
+++ b/tests/regressiontests/file_uploads/urls.py
@@ -0,0 +1,10 @@
+from django.conf.urls.defaults import *
+import views
+
+urlpatterns = patterns('',
+ (r'^upload/$', views.file_upload_view),
+ (r'^verify/$', views.file_upload_view_verify),
+ (r'^echo/$', views.file_upload_echo),
+ (r'^quota/$', views.file_upload_quota),
+ (r'^quota/broken/$', views.file_upload_quota_broken),
+)
diff --git a/tests/regressiontests/file_uploads/views.py b/tests/regressiontests/file_uploads/views.py
new file mode 100644
index 0000000000..833cf90531
--- /dev/null
+++ b/tests/regressiontests/file_uploads/views.py
@@ -0,0 +1,70 @@
+import os
+import sha
+from django.core.files.uploadedfile import UploadedFile
+from django.http import HttpResponse, HttpResponseServerError
+from django.utils import simplejson
+from uploadhandler import QuotaUploadHandler
+
+def file_upload_view(request):
+ """
+ Check that a file upload can be updated into the POST dictionary without
+ going pear-shaped.
+ """
+ form_data = request.POST.copy()
+ form_data.update(request.FILES)
+ if isinstance(form_data.get('file_field'), UploadedFile) and isinstance(form_data['name'], unicode):
+ # If a file is posted, the dummy client should only post the file name,
+ # not the full path.
+ if os.path.dirname(form_data['file_field'].file_name) != '':
+ return HttpResponseServerError()
+ return HttpResponse('')
+ else:
+ return HttpResponseServerError()
+
+def file_upload_view_verify(request):
+ """
+ Use the sha digest hash to verify the uploaded contents.
+ """
+ form_data = request.POST.copy()
+ form_data.update(request.FILES)
+
+ # Check to see if unicode names worked out.
+ if not request.FILES['file_unicode'].file_name.endswith(u'test_\u4e2d\u6587_Orl\xe9ans.jpg'):
+ return HttpResponseServerError()
+
+ for key, value in form_data.items():
+ if key.endswith('_hash'):
+ continue
+ if key + '_hash' not in form_data:
+ continue
+ submitted_hash = form_data[key + '_hash']
+ if isinstance(value, UploadedFile):
+ new_hash = sha.new(value.read()).hexdigest()
+ else:
+ new_hash = sha.new(value).hexdigest()
+ if new_hash != submitted_hash:
+ return HttpResponseServerError()
+
+ return HttpResponse('')
+
+def file_upload_echo(request):
+ """
+ Simple view to echo back info about uploaded files for tests.
+ """
+ r = dict([(k, f.file_name) for k, f in request.FILES.items()])
+ return HttpResponse(simplejson.dumps(r))
+
+def file_upload_quota(request):
+ """
+ Dynamically add in an upload handler.
+ """
+ request.upload_handlers.insert(0, QuotaUploadHandler())
+ return file_upload_echo(request)
+
+def file_upload_quota_broken(request):
+ """
+ You can't change handlers after reading FILES; this view shouldn't work.
+ """
+ response = file_upload_echo(request)
+ request.upload_handlers.insert(0, QuotaUploadHandler())
+ return response \ No newline at end of file
diff --git a/tests/regressiontests/fixtures_regress/fixtures/big-fixture.json b/tests/regressiontests/fixtures_regress/fixtures/big-fixture.json
new file mode 100644
index 0000000000..e655fbbf3f
--- /dev/null
+++ b/tests/regressiontests/fixtures_regress/fixtures/big-fixture.json
@@ -0,0 +1,83 @@
+[
+ {
+ "pk": 6,
+ "model": "fixtures_regress.channel",
+ "fields": {
+ "name": "Business"
+ }
+ },
+
+ {
+ "pk": 1,
+ "model": "fixtures_regress.article",
+ "fields": {
+ "title": "Article Title 1",
+ "channels": [6]
+ }
+ },
+ {
+ "pk": 2,
+ "model": "fixtures_regress.article",
+ "fields": {
+ "title": "Article Title 2",
+ "channels": [6]
+ }
+ },
+ {
+ "pk": 3,
+ "model": "fixtures_regress.article",
+ "fields": {
+ "title": "Article Title 3",
+ "channels": [6]
+ }
+ },
+ {
+ "pk": 4,
+ "model": "fixtures_regress.article",
+ "fields": {
+ "title": "Article Title 4",
+ "channels": [6]
+ }
+ },
+
+ {
+ "pk": 5,
+ "model": "fixtures_regress.article",
+ "fields": {
+ "title": "Article Title 5",
+ "channels": [6]
+ }
+ },
+ {
+ "pk": 6,
+ "model": "fixtures_regress.article",
+ "fields": {
+ "title": "Article Title 6",
+ "channels": [6]
+ }
+ },
+ {
+ "pk": 7,
+ "model": "fixtures_regress.article",
+ "fields": {
+ "title": "Article Title 7",
+ "channels": [6]
+ }
+ },
+ {
+ "pk": 8,
+ "model": "fixtures_regress.article",
+ "fields": {
+ "title": "Article Title 8",
+ "channels": [6]
+ }
+ },
+ {
+ "pk": 9,
+ "model": "fixtures_regress.article",
+ "fields": {
+ "title": "Yet Another Article",
+ "channels": [6]
+ }
+ }
+] \ No newline at end of file
diff --git a/tests/regressiontests/fixtures_regress/fixtures/model-inheritance.json b/tests/regressiontests/fixtures_regress/fixtures/model-inheritance.json
new file mode 100644
index 0000000000..00c482b3dd
--- /dev/null
+++ b/tests/regressiontests/fixtures_regress/fixtures/model-inheritance.json
@@ -0,0 +1,4 @@
+[
+ {"pk": 1, "model": "fixtures_regress.parent", "fields": {"name": "fred"}},
+ {"pk": 1, "model": "fixtures_regress.child", "fields": {"data": "apple"}}
+]
diff --git a/tests/regressiontests/fixtures_regress/models.py b/tests/regressiontests/fixtures_regress/models.py
index 59fc167d50..2c048dc0b8 100644
--- a/tests/regressiontests/fixtures_regress/models.py
+++ b/tests/regressiontests/fixtures_regress/models.py
@@ -20,7 +20,7 @@ class Plant(models.Model):
class Stuff(models.Model):
name = models.CharField(max_length=20, null=True)
owner = models.ForeignKey(User, null=True)
-
+
def __unicode__(self):
# Oracle doesn't distinguish between None and the empty string.
# This hack makes the test case pass using Oracle.
@@ -38,13 +38,29 @@ class Absolute(models.Model):
super(Absolute, self).__init__(*args, **kwargs)
Absolute.load_count += 1
+class Parent(models.Model):
+ name = models.CharField(max_length=10)
+
+class Child(Parent):
+ data = models.CharField(max_length=10)
+
+# Models to regresison check #7572
+class Channel(models.Model):
+ name = models.CharField(max_length=255)
+
+class Article(models.Model):
+ title = models.CharField(max_length=255)
+ channels = models.ManyToManyField(Channel)
+
+ class Meta:
+ ordering = ('id',)
__test__ = {'API_TESTS':"""
>>> from django.core import management
# Load a fixture that uses PK=1
>>> management.call_command('loaddata', 'sequence', verbosity=0)
-
+
# Create a new animal. Without a sequence reset, this new object
# will take a PK of 1 (on Postgres), and the save will fail.
# This is a regression test for ticket #3790.
@@ -61,9 +77,9 @@ __test__ = {'API_TESTS':"""
[<Stuff: None is owned by None>]
###############################################
-# Regression test for ticket #6436 --
+# Regression test for ticket #6436 --
# os.path.join will throw away the initial parts of a path if it encounters
-# an absolute path. This means that if a fixture is specified as an absolute path,
+# an absolute path. This means that if a fixture is specified as an absolute path,
# we need to make sure we don't discover the absolute path in every fixture directory.
>>> load_absolute_path = os.path.join(os.path.dirname(__file__), 'fixtures', 'absolute.json')
@@ -94,4 +110,28 @@ No fixture data found for 'bad_fixture2'. (File format may be invalid.)
>>> sys.stderr = savestderr
+###############################################
+# Test for ticket #7565 -- PostgreSQL sequence resetting checks shouldn't
+# ascend to parent models when inheritance is used (since they are treated
+# individually).
+
+>>> management.call_command('loaddata', 'model-inheritance.json', verbosity=0)
+
+###############################################
+# Test for ticket #7572 -- MySQL has a problem if the same connection is
+# used to create tables, load data, and then query over that data.
+# To compensate, we close the connection after running loaddata.
+# This ensures that a new connection is opened when test queries are issued.
+
+>>> management.call_command('loaddata', 'big-fixture.json', verbosity=0)
+
+>>> articles = Article.objects.exclude(id=9)
+>>> articles.values_list('id', flat=True)
+[1, 2, 3, 4, 5, 6, 7, 8]
+
+# Just for good measure, run the same query again. Under the influence of
+# ticket #7572, this will give a different result to the previous call.
+>>> articles.values_list('id', flat=True)
+[1, 2, 3, 4, 5, 6, 7, 8]
+
"""}
diff --git a/tests/regressiontests/forms/error_messages.py b/tests/regressiontests/forms/error_messages.py
index 9f972f5b90..580326f894 100644
--- a/tests/regressiontests/forms/error_messages.py
+++ b/tests/regressiontests/forms/error_messages.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
tests = r"""
>>> from django.newforms import *
+>>> from django.core.files.uploadedfile import SimpleUploadedFile
# CharField ###################################################################
@@ -214,11 +215,11 @@ ValidationError: [u'REQUIRED']
Traceback (most recent call last):
...
ValidationError: [u'INVALID']
->>> f.clean({})
+>>> f.clean(SimpleUploadedFile('name', None))
Traceback (most recent call last):
...
-ValidationError: [u'MISSING']
->>> f.clean({'filename': 'name', 'content':''})
+ValidationError: [u'EMPTY FILE']
+>>> f.clean(SimpleUploadedFile('name', ''))
Traceback (most recent call last):
...
ValidationError: [u'EMPTY FILE']
@@ -237,7 +238,7 @@ ValidationError: [u'REQUIRED']
Traceback (most recent call last):
...
ValidationError: [u'INVALID']
->>> f.clean('http://www.jfoiwjfoi23jfoijoaijfoiwjofiwjefewl.com')
+>>> f.clean('http://www.broken.djangoproject.com')
Traceback (most recent call last):
...
ValidationError: [u'INVALID LINK']
diff --git a/tests/regressiontests/forms/fields.py b/tests/regressiontests/forms/fields.py
index f3b6a96a1e..4725c3ecf3 100644
--- a/tests/regressiontests/forms/fields.py
+++ b/tests/regressiontests/forms/fields.py
@@ -2,6 +2,7 @@
tests = r"""
>>> from django.newforms import *
>>> from django.newforms.widgets import RadioFieldRenderer
+>>> from django.core.files.uploadedfile import SimpleUploadedFile
>>> import datetime
>>> import time
>>> import re
@@ -770,17 +771,17 @@ ValidationError: [u'This field is required.']
>>> f.clean(None, 'files/test2.pdf')
'files/test2.pdf'
->>> f.clean({})
+>>> f.clean(SimpleUploadedFile('', ''))
Traceback (most recent call last):
...
-ValidationError: [u'No file was submitted.']
+ValidationError: [u'No file was submitted. Check the encoding type on the form.']
->>> f.clean({}, '')
+>>> f.clean(SimpleUploadedFile('', ''), '')
Traceback (most recent call last):
...
-ValidationError: [u'No file was submitted.']
+ValidationError: [u'No file was submitted. Check the encoding type on the form.']
->>> f.clean({}, 'files/test3.pdf')
+>>> f.clean(None, 'files/test3.pdf')
'files/test3.pdf'
>>> f.clean('some content that is not a file')
@@ -788,20 +789,20 @@ Traceback (most recent call last):
...
ValidationError: [u'No file was submitted. Check the encoding type on the form.']
->>> f.clean({'filename': 'name', 'content': None})
+>>> f.clean(SimpleUploadedFile('name', None))
Traceback (most recent call last):
...
ValidationError: [u'The submitted file is empty.']
->>> f.clean({'filename': 'name', 'content': ''})
+>>> f.clean(SimpleUploadedFile('name', ''))
Traceback (most recent call last):
...
ValidationError: [u'The submitted file is empty.']
->>> type(f.clean({'filename': 'name', 'content': 'Some File Content'}))
+>>> type(f.clean(SimpleUploadedFile('name', 'Some File Content')))
<class 'django.newforms.fields.UploadedFile'>
->>> type(f.clean({'filename': 'name', 'content': 'Some File Content'}, 'files/test4.pdf'))
+>>> type(f.clean(SimpleUploadedFile('name', 'Some File Content'), 'files/test4.pdf'))
<class 'django.newforms.fields.UploadedFile'>
# URLField ##################################################################
@@ -887,7 +888,7 @@ u'http://www.google.com'
Traceback (most recent call last):
...
ValidationError: [u'Enter a valid URL.']
->>> f.clean('http://www.jfoiwjfoi23jfoijoaijfoiwjofiwjefewl.com') # bad domain
+>>> f.clean('http://www.broken.djangoproject.com') # bad domain
Traceback (most recent call last):
...
ValidationError: [u'This URL appears to be a broken link.']
@@ -937,18 +938,24 @@ ValidationError: [u'This field is required.']
>>> f.clean(True)
True
>>> f.clean(False)
-False
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
>>> f.clean(1)
True
>>> f.clean(0)
-False
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
>>> f.clean('Django rocks')
True
>>> f.clean('True')
True
>>> f.clean('False')
-False
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
>>> f = BooleanField(required=False)
>>> f.clean('')
diff --git a/tests/regressiontests/forms/forms.py b/tests/regressiontests/forms/forms.py
index 7fc206de4c..041fa4054c 100644
--- a/tests/regressiontests/forms/forms.py
+++ b/tests/regressiontests/forms/forms.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
tests = r"""
>>> from django.newforms import *
+>>> from django.core.files.uploadedfile import SimpleUploadedFile
>>> import datetime
>>> import time
>>> import re
@@ -1465,7 +1466,7 @@ not request.POST.
>>> print f
<tr><th>File1:</th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="file" name="file1" /></td></tr>
->>> f = FileForm(data={}, files={'file1': {'filename': 'name', 'content':''}}, auto_id=False)
+>>> f = FileForm(data={}, files={'file1': SimpleUploadedFile('name', '')}, auto_id=False)
>>> print f
<tr><th>File1:</th><td><ul class="errorlist"><li>The submitted file is empty.</li></ul><input type="file" name="file1" /></td></tr>
@@ -1473,7 +1474,7 @@ not request.POST.
>>> print f
<tr><th>File1:</th><td><ul class="errorlist"><li>No file was submitted. Check the encoding type on the form.</li></ul><input type="file" name="file1" /></td></tr>
->>> f = FileForm(data={}, files={'file1': {'filename': 'name', 'content':'some content'}}, auto_id=False)
+>>> f = FileForm(data={}, files={'file1': SimpleUploadedFile('name', 'some content')}, auto_id=False)
>>> print f
<tr><th>File1:</th><td><input type="file" name="file1" /></td></tr>
>>> f.is_valid()
diff --git a/tests/regressiontests/many_to_one_regress/models.py b/tests/regressiontests/many_to_one_regress/models.py
index 4e49df1555..429bdd7558 100644
--- a/tests/regressiontests/many_to_one_regress/models.py
+++ b/tests/regressiontests/many_to_one_regress/models.py
@@ -28,6 +28,24 @@ class Child(models.Model):
parent = models.ForeignKey(Parent)
+# Multiple paths to the same model (#7110, #7125)
+class Category(models.Model):
+ name = models.CharField(max_length=20)
+
+ def __unicode__(self):
+ return self.name
+
+class Record(models.Model):
+ category = models.ForeignKey(Category)
+
+class Relation(models.Model):
+ left = models.ForeignKey(Record, related_name='left_set')
+ right = models.ForeignKey(Record, related_name='right_set')
+
+ def __unicode__(self):
+ return u"%s - %s" % (self.left.category.name, self.right.category.name)
+
+
__test__ = {'API_TESTS':"""
>>> Third.objects.create(id='3', name='An example')
<Third: Third object>
@@ -73,4 +91,26 @@ Traceback (most recent call last):
...
ValueError: Cannot assign "<First: First object>": "Child.parent" must be a "Parent" instance.
+# Test of multiple ForeignKeys to the same model (bug #7125)
+
+>>> c1 = Category.objects.create(name='First')
+>>> c2 = Category.objects.create(name='Second')
+>>> c3 = Category.objects.create(name='Third')
+>>> r1 = Record.objects.create(category=c1)
+>>> r2 = Record.objects.create(category=c1)
+>>> r3 = Record.objects.create(category=c2)
+>>> r4 = Record.objects.create(category=c2)
+>>> r5 = Record.objects.create(category=c3)
+>>> r = Relation.objects.create(left=r1, right=r2)
+>>> r = Relation.objects.create(left=r3, right=r4)
+>>> r = Relation.objects.create(left=r1, right=r3)
+>>> r = Relation.objects.create(left=r5, right=r2)
+>>> r = Relation.objects.create(left=r3, right=r2)
+
+>>> Relation.objects.filter(left__category__name__in=['First'], right__category__name__in=['Second'])
+[<Relation: First - Second>]
+
+>>> Category.objects.filter(record__left_set__right__category__name='Second').order_by('name')
+[<Category: First>, <Category: Second>]
+
"""}
diff --git a/tests/regressiontests/model_fields/tests.py b/tests/regressiontests/model_fields/tests.py
index e279a0669f..c2ba9ee008 100644
--- a/tests/regressiontests/model_fields/tests.py
+++ b/tests/regressiontests/model_fields/tests.py
@@ -15,4 +15,21 @@ Decimal("3.14")
Traceback (most recent call last):
...
ValidationError: [u'This value must be a decimal number.']
+
+>>> f = DecimalField(max_digits=5, decimal_places=1)
+>>> x = f.to_python(2)
+>>> y = f.to_python('2.6')
+
+>>> f.get_db_prep_save(x)
+u'2.0'
+>>> f.get_db_prep_save(y)
+u'2.6'
+>>> f.get_db_prep_save(None)
+>>> f.get_db_prep_lookup('exact', x)
+[u'2.0']
+>>> f.get_db_prep_lookup('exact', y)
+[u'2.6']
+>>> f.get_db_prep_lookup('exact', None)
+[None]
+
"""
diff --git a/tests/regressiontests/model_inheritance_regress/models.py b/tests/regressiontests/model_inheritance_regress/models.py
index 33e2e0e4f6..24d6186150 100644
--- a/tests/regressiontests/model_inheritance_regress/models.py
+++ b/tests/regressiontests/model_inheritance_regress/models.py
@@ -131,4 +131,26 @@ __test__ = {'API_TESTS':"""
>>> Child.objects.dates('created', 'month')
[datetime.datetime(2008, 6, 1, 0, 0)]
+# Regression test for #7276: calling delete() on a model with multi-table
+# inheritance should delete the associated rows from any ancestor tables, as
+# well as any descendent objects.
+
+>>> ident = ItalianRestaurant.objects.all()[0].id
+>>> Place.objects.get(pk=ident)
+<Place: Guido's All New House of Pasta the place>
+>>> xx = Restaurant.objects.create(name='a', address='xx', serves_hot_dogs=True, serves_pizza=False)
+
+# This should delete both Restuarants, plus the related places, plus the ItalianRestaurant.
+>>> Restaurant.objects.all().delete()
+
+>>> Place.objects.get(pk=ident)
+Traceback (most recent call last):
+...
+DoesNotExist: Place matching query does not exist.
+
+>>> ItalianRestaurant.objects.get(pk=ident)
+Traceback (most recent call last):
+...
+DoesNotExist: ItalianRestaurant matching query does not exist.
+
"""}
diff --git a/tests/regressiontests/model_inheritance_select_related/__init__.py b/tests/regressiontests/model_inheritance_select_related/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/regressiontests/model_inheritance_select_related/__init__.py
diff --git a/tests/regressiontests/model_inheritance_select_related/models.py b/tests/regressiontests/model_inheritance_select_related/models.py
new file mode 100644
index 0000000000..a97ecaadea
--- /dev/null
+++ b/tests/regressiontests/model_inheritance_select_related/models.py
@@ -0,0 +1,47 @@
+"""
+Regression tests for the interaction between model inheritance and
+select_related().
+"""
+
+from django.db import models
+
+class Place(models.Model):
+ name = models.CharField(max_length=50)
+
+ class Meta:
+ ordering = ('name',)
+
+ def __unicode__(self):
+ return u"%s the place" % self.name
+
+class Restaurant(Place):
+ serves_sushi = models.BooleanField()
+ serves_steak = models.BooleanField()
+
+ def __unicode__(self):
+ return u"%s the restaurant" % self.name
+
+class Person(models.Model):
+ name = models.CharField(max_length=50)
+ favorite_restaurant = models.ForeignKey(Restaurant)
+
+ def __unicode__(self):
+ return self.name
+
+__test__ = {'API_TESTS':"""
+Regression test for #7246
+
+>>> r1 = Restaurant.objects.create(name="Nobu", serves_sushi=True, serves_steak=False)
+>>> r2 = Restaurant.objects.create(name="Craft", serves_sushi=False, serves_steak=True)
+>>> p1 = Person.objects.create(name="John", favorite_restaurant=r1)
+>>> p2 = Person.objects.create(name="Jane", favorite_restaurant=r2)
+
+>>> Person.objects.order_by('name').select_related()
+[<Person: Jane>, <Person: John>]
+
+>>> jane = Person.objects.order_by('name').select_related('favorite_restaurant')[0]
+>>> jane.favorite_restaurant.name
+u'Craft'
+
+"""}
+
diff --git a/tests/regressiontests/queries/models.py b/tests/regressiontests/queries/models.py
index c02ad73998..566411e513 100644
--- a/tests/regressiontests/queries/models.py
+++ b/tests/regressiontests/queries/models.py
@@ -3,13 +3,15 @@ Various complex queries that have been problematic in the past.
"""
import datetime
+import pickle
from django.db import models
from django.db.models.query import Q
class Tag(models.Model):
name = models.CharField(max_length=10)
- parent = models.ForeignKey('self', blank=True, null=True)
+ parent = models.ForeignKey('self', blank=True, null=True,
+ related_name='children')
def __unicode__(self):
return self.name
@@ -24,6 +26,14 @@ class Note(models.Model):
def __unicode__(self):
return self.note
+class Annotation(models.Model):
+ name = models.CharField(max_length=10)
+ tag = models.ForeignKey(Tag)
+ notes = models.ManyToManyField(Note)
+
+ def __unicode__(self):
+ return self.name
+
class ExtraInfo(models.Model):
info = models.CharField(max_length=100)
note = models.ForeignKey(Note)
@@ -162,85 +172,67 @@ class Child(models.Model):
person = models.OneToOneField(Member, primary_key=True)
parent = models.ForeignKey(Member, related_name="children")
+# Custom primary keys interfered with ordering in the past.
+class CustomPk(models.Model):
+ name = models.CharField(max_length=10, primary_key=True)
+ extra = models.CharField(max_length=10)
+
+ class Meta:
+ ordering = ['name', 'extra']
+
+class Related(models.Model):
+ custom = models.ForeignKey(CustomPk)
+
__test__ = {'API_TESTS':"""
->>> t1 = Tag(name='t1')
->>> t1.save()
->>> t2 = Tag(name='t2', parent=t1)
->>> t2.save()
->>> t3 = Tag(name='t3', parent=t1)
->>> t3.save()
->>> t4 = Tag(name='t4', parent=t3)
->>> t4.save()
->>> t5 = Tag(name='t5', parent=t3)
->>> t5.save()
+>>> t1 = Tag.objects.create(name='t1')
+>>> t2 = Tag.objects.create(name='t2', parent=t1)
+>>> t3 = Tag.objects.create(name='t3', parent=t1)
+>>> t4 = Tag.objects.create(name='t4', parent=t3)
+>>> t5 = Tag.objects.create(name='t5', parent=t3)
->>> n1 = Note(note='n1', misc='foo')
->>> n1.save()
->>> n2 = Note(note='n2', misc='bar')
->>> n2.save()
->>> n3 = Note(note='n3', misc='foo')
->>> n3.save()
+>>> n1 = Note.objects.create(note='n1', misc='foo')
+>>> n2 = Note.objects.create(note='n2', misc='bar')
+>>> n3 = Note.objects.create(note='n3', misc='foo')
Create these out of order so that sorting by 'id' will be different to sorting
by 'info'. Helps detect some problems later.
->>> e2 = ExtraInfo(info='e2', note=n2)
->>> e2.save()
->>> e1 = ExtraInfo(info='e1', note=n1)
->>> e1.save()
+>>> e2 = ExtraInfo.objects.create(info='e2', note=n2)
+>>> e1 = ExtraInfo.objects.create(info='e1', note=n1)
->>> a1 = Author(name='a1', num=1001, extra=e1)
->>> a1.save()
->>> a2 = Author(name='a2', num=2002, extra=e1)
->>> a2.save()
->>> a3 = Author(name='a3', num=3003, extra=e2)
->>> a3.save()
->>> a4 = Author(name='a4', num=4004, extra=e2)
->>> a4.save()
+>>> a1 = Author.objects.create(name='a1', num=1001, extra=e1)
+>>> a2 = Author.objects.create(name='a2', num=2002, extra=e1)
+>>> a3 = Author.objects.create(name='a3', num=3003, extra=e2)
+>>> a4 = Author.objects.create(name='a4', num=4004, extra=e2)
>>> time1 = datetime.datetime(2007, 12, 19, 22, 25, 0)
>>> time2 = datetime.datetime(2007, 12, 19, 21, 0, 0)
>>> time3 = datetime.datetime(2007, 12, 20, 22, 25, 0)
>>> time4 = datetime.datetime(2007, 12, 20, 21, 0, 0)
->>> i1 = Item(name='one', created=time1, modified=time1, creator=a1, note=n3)
->>> i1.save()
+>>> i1 = Item.objects.create(name='one', created=time1, modified=time1, creator=a1, note=n3)
>>> i1.tags = [t1, t2]
->>> i2 = Item(name='two', created=time2, creator=a2, note=n2)
->>> i2.save()
+>>> i2 = Item.objects.create(name='two', created=time2, creator=a2, note=n2)
>>> i2.tags = [t1, t3]
->>> i3 = Item(name='three', created=time3, creator=a2, note=n3)
->>> i3.save()
->>> i4 = Item(name='four', created=time4, creator=a4, note=n3)
->>> i4.save()
+>>> i3 = Item.objects.create(name='three', created=time3, creator=a2, note=n3)
+>>> i4 = Item.objects.create(name='four', created=time4, creator=a4, note=n3)
>>> i4.tags = [t4]
->>> r1 = Report(name='r1', creator=a1)
->>> r1.save()
->>> r2 = Report(name='r2', creator=a3)
->>> r2.save()
->>> r3 = Report(name='r3')
->>> r3.save()
+>>> r1 = Report.objects.create(name='r1', creator=a1)
+>>> r2 = Report.objects.create(name='r2', creator=a3)
+>>> r3 = Report.objects.create(name='r3')
Ordering by 'rank' gives us rank2, rank1, rank3. Ordering by the Meta.ordering
will be rank3, rank2, rank1.
->>> rank1 = Ranking(rank=2, author=a2)
->>> rank1.save()
->>> rank2 = Ranking(rank=1, author=a3)
->>> rank2.save()
->>> rank3 = Ranking(rank=3, author=a1)
->>> rank3.save()
+>>> rank1 = Ranking.objects.create(rank=2, author=a2)
+>>> rank2 = Ranking.objects.create(rank=1, author=a3)
+>>> rank3 = Ranking.objects.create(rank=3, author=a1)
->>> c1 = Cover(title="first", item=i4)
->>> c1.save()
->>> c2 = Cover(title="second", item=i2)
->>> c2.save()
+>>> c1 = Cover.objects.create(title="first", item=i4)
+>>> c2 = Cover.objects.create(title="second", item=i2)
->>> n1 = Number(num=4)
->>> n1.save()
->>> n2 = Number(num=8)
->>> n2.save()
->>> n3 = Number(num=12)
->>> n3.save()
+>>> num1 = Number.objects.create(num=4)
+>>> num2 = Number.objects.create(num=8)
+>>> num3 = Number.objects.create(num=12)
Bug #1050
>>> Item.objects.filter(tags__isnull=True)
@@ -346,6 +338,10 @@ Bug #1878, #2939
4
>>> xx.delete()
+Bug #7323
+>>> Item.objects.values('creator', 'name').count()
+4
+
Bug #2253
>>> q1 = Item.objects.order_by('name')
>>> q2 = Item.objects.filter(id=i1.id)
@@ -387,6 +383,10 @@ Bug #4510
>>> Author.objects.filter(report__name='r1')
[<Author: a1>]
+Bug #7378
+>>> a1.report_set.all()
+[<Report: r1>]
+
Bug #5324, #6704
>>> Item.objects.filter(tags__name='t4')
[<Item: four>]
@@ -791,5 +791,19 @@ Empty querysets can be merged with others.
>>> Note.objects.all() & Note.objects.none()
[]
+Bug #7204, #7506 -- make sure querysets with related fields can be pickled. If
+this doesn't crash, it's a Good Thing.
+>>> out = pickle.dumps(Item.objects.all())
+
+Bug #7277
+>>> ann1 = Annotation.objects.create(name='a1', tag=t1)
+>>> ann1.notes.add(n1)
+>>> n1.annotation_set.filter(Q(tag=t5) | Q(tag__children=t5) | Q(tag__children__children=t5))
+[<Annotation: a1>]
+
+Bug #7371
+>>> Related.objects.order_by('custom')
+[]
+
"""}
diff --git a/tests/regressiontests/select_related_regress/__init__.py b/tests/regressiontests/select_related_regress/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/regressiontests/select_related_regress/__init__.py
diff --git a/tests/regressiontests/select_related_regress/models.py b/tests/regressiontests/select_related_regress/models.py
new file mode 100644
index 0000000000..05b851829d
--- /dev/null
+++ b/tests/regressiontests/select_related_regress/models.py
@@ -0,0 +1,60 @@
+from django.db import models
+
+class Building(models.Model):
+ name = models.CharField(max_length=10)
+
+ def __unicode__(self):
+ return u"Building: %s" % self.name
+
+class Device(models.Model):
+ building = models.ForeignKey('Building')
+ name = models.CharField(max_length=10)
+
+ def __unicode__(self):
+ return u"device '%s' in building %s" % (self.name, self.building)
+
+class Port(models.Model):
+ device = models.ForeignKey('Device')
+ port_number = models.CharField(max_length=10)
+
+ def __unicode__(self):
+ return u"%s/%s" % (self.device.name, self.port_number)
+
+class Connection(models.Model):
+ start = models.ForeignKey(Port, related_name='connection_start',
+ unique=True)
+ end = models.ForeignKey(Port, related_name='connection_end', unique=True)
+
+ def __unicode__(self):
+ return u"%s to %s" % (self.start, self.end)
+
+__test__ = {'API_TESTS': """
+Regression test for bug #7110. When using select_related(), we must query the
+Device and Building tables using two different aliases (each) in order to
+differentiate the start and end Connection fields. The net result is that both
+the "connections = ..." queries here should give the same results.
+
+>>> b=Building.objects.create(name='101')
+>>> dev1=Device.objects.create(name="router", building=b)
+>>> dev2=Device.objects.create(name="switch", building=b)
+>>> dev3=Device.objects.create(name="server", building=b)
+>>> port1=Port.objects.create(port_number='4',device=dev1)
+>>> port2=Port.objects.create(port_number='7',device=dev2)
+>>> port3=Port.objects.create(port_number='1',device=dev3)
+>>> c1=Connection.objects.create(start=port1, end=port2)
+>>> c2=Connection.objects.create(start=port2, end=port3)
+
+>>> connections=Connection.objects.filter(start__device__building=b, end__device__building=b).order_by('id')
+>>> [(c.id, unicode(c.start), unicode(c.end)) for c in connections]
+[(1, u'router/4', u'switch/7'), (2, u'switch/7', u'server/1')]
+
+>>> connections=Connection.objects.filter(start__device__building=b, end__device__building=b).select_related().order_by('id')
+>>> [(c.id, unicode(c.start), unicode(c.end)) for c in connections]
+[(1, u'router/4', u'switch/7'), (2, u'switch/7', u'server/1')]
+
+# This final query should only join seven tables (port, device and building
+# twice each, plus connection once).
+>>> connections.query.count_active_tables()
+7
+
+"""}
diff --git a/tests/regressiontests/string_lookup/models.py b/tests/regressiontests/string_lookup/models.py
index 1bdb2d4452..39e7955592 100644
--- a/tests/regressiontests/string_lookup/models.py
+++ b/tests/regressiontests/string_lookup/models.py
@@ -97,6 +97,12 @@ __test__ = {'API_TESTS': ur"""
>>> Article.objects.get(text__exact='The quick brown fox jumps over the lazy dog.')
<Article: Article Test>
+# Regression tests for #2170: test case sensitiveness
+>>> Article.objects.filter(text__exact='tHe qUick bRown fOx jUmps over tHe lazy dog.')
+[]
+>>> Article.objects.filter(text__iexact='tHe qUick bRown fOx jUmps over tHe lazy dog.')
+[<Article: Article Test>]
+
>>> Article.objects.get(text__contains='quick brown fox')
<Article: Article Test>
diff --git a/tests/regressiontests/test_client_regress/models.py b/tests/regressiontests/test_client_regress/models.py
index a204ec3e72..1eb55e312e 100644
--- a/tests/regressiontests/test_client_regress/models.py
+++ b/tests/regressiontests/test_client_regress/models.py
@@ -6,6 +6,7 @@ from django.test import Client, TestCase
from django.core.urlresolvers import reverse
from django.core.exceptions import SuspiciousOperation
import os
+import sha
class AssertContainsTests(TestCase):
def test_contains(self):
@@ -240,16 +241,6 @@ class AssertFormErrorTests(TestCase):
except AssertionError, e:
self.assertEqual(str(e), "The form 'form' in context 0 does not contain the non-field error 'Some error.' (actual errors: )")
-class FileUploadTests(TestCase):
- def test_simple_upload(self):
- fd = open(os.path.join(os.path.dirname(__file__), "views.py"))
- post_data = {
- 'name': 'Ringo',
- 'file_field': fd,
- }
- response = self.client.post('/test_client_regress/file_upload/', post_data)
- self.assertEqual(response.status_code, 200)
-
class LoginTests(TestCase):
fixtures = ['testdata']
@@ -269,7 +260,6 @@ class LoginTests(TestCase):
# default client.
self.assertRedirects(response, "http://testserver/test_client_regress/get_view/")
-
class URLEscapingTests(TestCase):
def test_simple_argument_get(self):
"Get a view that has a simple string argument"
@@ -318,3 +308,22 @@ class ExceptionTests(TestCase):
self.client.get("/test_client_regress/staff_only/")
except SuspiciousOperation:
self.fail("Staff should be able to visit this page")
+
+# We need two different tests to check URLconf subsitution - one to check
+# it was changed, and another one (without self.urls) to check it was reverted on
+# teardown. This pair of tests relies upon the alphabetical ordering of test execution.
+class UrlconfSubstitutionTests(TestCase):
+ urls = 'regressiontests.test_client_regress.urls'
+
+ def test_urlconf_was_changed(self):
+ "TestCase can enforce a custom URLConf on a per-test basis"
+ url = reverse('arg_view', args=['somename'])
+ self.assertEquals(url, '/arg_view/somename/')
+
+# This test needs to run *after* UrlconfSubstitutionTests; the zz prefix in the
+# name is to ensure alphabetical ordering.
+class zzUrlconfSubstitutionTests(TestCase):
+ def test_urlconf_was_reverted(self):
+ "URLconf is reverted to original value after modification in a TestCase"
+ url = reverse('arg_view', args=['somename'])
+ self.assertEquals(url, '/test_client_regress/arg_view/somename/')
diff --git a/tests/regressiontests/test_client_regress/urls.py b/tests/regressiontests/test_client_regress/urls.py
index dc26d1260a..12f6afacf3 100644
--- a/tests/regressiontests/test_client_regress/urls.py
+++ b/tests/regressiontests/test_client_regress/urls.py
@@ -3,7 +3,6 @@ import views
urlpatterns = patterns('',
(r'^no_template_view/$', views.no_template_view),
- (r'^file_upload/$', views.file_upload_view),
(r'^staff_only/$', views.staff_only_view),
(r'^get_view/$', views.get_view),
url(r'^arg_view/(?P<name>.+)/$', views.view_with_argument, name='arg_view'),
diff --git a/tests/regressiontests/test_client_regress/views.py b/tests/regressiontests/test_client_regress/views.py
index 9632c17284..d703c82124 100644
--- a/tests/regressiontests/test_client_regress/views.py
+++ b/tests/regressiontests/test_client_regress/views.py
@@ -1,36 +1,18 @@
-import os
-
from django.contrib.auth.decorators import login_required
-from django.http import HttpResponse, HttpResponseRedirect, HttpResponseServerError
+from django.http import HttpResponse, HttpResponseRedirect
from django.core.exceptions import SuspiciousOperation
def no_template_view(request):
"A simple view that expects a GET request, and returns a rendered template"
return HttpResponse("No template used. Sample content: twice once twice. Content ends.")
-def file_upload_view(request):
- """
- Check that a file upload can be updated into the POST dictionary without
- going pear-shaped.
- """
- form_data = request.POST.copy()
- form_data.update(request.FILES)
- if isinstance(form_data['file_field'], dict) and isinstance(form_data['name'], unicode):
- # If a file is posted, the dummy client should only post the file name,
- # not the full path.
- if os.path.dirname(form_data['file_field']['filename']) != '':
- return HttpResponseServerError()
- return HttpResponse('')
- else:
- return HttpResponseServerError()
-
def staff_only_view(request):
"A view that can only be visited by staff. Non staff members get an exception"
if request.user.is_staff:
return HttpResponse('')
else:
raise SuspiciousOperation()
-
+
def get_view(request):
"A simple login protected view"
return HttpResponse("Hello world")
@@ -51,4 +33,4 @@ def view_with_argument(request, name):
def login_protected_redirect_view(request):
"A view that redirects all requests to the GET view"
return HttpResponseRedirect('/test_client_regress/get_view/')
-login_protected_redirect_view = login_required(login_protected_redirect_view) \ No newline at end of file
+login_protected_redirect_view = login_required(login_protected_redirect_view)