diff options
| author | Alex Gaynor <alex.gaynor@gmail.com> | 2010-06-07 17:52:53 +0000 |
|---|---|---|
| committer | Alex Gaynor <alex.gaynor@gmail.com> | 2010-06-07 17:52:53 +0000 |
| commit | a61b34b048d84b2a8af78a42a4e635371252bd3f (patch) | |
| tree | 6c0733ffe75a10b95719ac7b99bcd9b9abc6b578 /tests/regressiontests | |
| parent | 9d3e6668d91af5ef442d07192b5508707d7e0a2a (diff) | |
[soc2010/query-refactor] Merged up to trunk r13328.
git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2010/query-refactor@13329 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'tests/regressiontests')
| -rw-r--r-- | tests/regressiontests/backends/models.py | 19 | ||||
| -rw-r--r-- | tests/regressiontests/backends/tests.py | 53 | ||||
| -rw-r--r-- | tests/regressiontests/httpwrappers/tests.py | 658 | ||||
| -rw-r--r-- | tests/regressiontests/m2m_through_regress/models.py | 158 | ||||
| -rw-r--r-- | tests/regressiontests/m2m_through_regress/tests.py | 126 | ||||
| -rw-r--r-- | tests/regressiontests/multiple_database/tests.py | 31 | ||||
| -rw-r--r-- | tests/regressiontests/serializers_regress/tests.py | 71 | ||||
| -rw-r--r-- | tests/regressiontests/utils/timesince.py | 14 |
8 files changed, 445 insertions, 685 deletions
diff --git a/tests/regressiontests/backends/models.py b/tests/regressiontests/backends/models.py index 423bead1ad..e3137f2710 100644 --- a/tests/regressiontests/backends/models.py +++ b/tests/regressiontests/backends/models.py @@ -1,5 +1,7 @@ +from django.conf import settings from django.db import models -from django.db import connection +from django.db import connection, DEFAULT_DB_ALIAS + class Square(models.Model): root = models.IntegerField() @@ -8,6 +10,7 @@ class Square(models.Model): def __unicode__(self): return "%s ** 2 == %s" % (self.root, self.square) + class Person(models.Model): first_name = models.CharField(max_length=20) last_name = models.CharField(max_length=20) @@ -15,11 +18,25 @@ class Person(models.Model): def __unicode__(self): return u'%s %s' % (self.first_name, self.last_name) + class SchoolClass(models.Model): year = models.PositiveIntegerField() day = models.CharField(max_length=9, blank=True) last_updated = models.DateTimeField() +# Unfortunately, the following model breaks MySQL hard. +# Until #13711 is fixed, this test can't be run under MySQL. +if settings.DATABASES[DEFAULT_DB_ALIAS]['ENGINE'] != 'django.db.backends.mysql': + class VeryLongModelNameZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ(models.Model): + class Meta: + # We need to use a short actual table name or + # we hit issue #8548 which we're not testing! + verbose_name = 'model_with_long_table_name' + primary_key_is_quite_long_zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz = models.AutoField(primary_key=True) + charfield_is_quite_long_zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz = models.CharField(max_length=100) + m2m_also_quite_long_zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz = models.ManyToManyField(Person,blank=True) + + qn = connection.ops.quote_name __test__ = {'API_TESTS': """ diff --git a/tests/regressiontests/backends/tests.py b/tests/regressiontests/backends/tests.py index 6a26a608eb..ee3ccdc72f 100644 --- a/tests/regressiontests/backends/tests.py +++ b/tests/regressiontests/backends/tests.py @@ -1,13 +1,17 @@ # -*- coding: utf-8 -*- # Unit and doctests for specific database backends. import datetime -import models import unittest + +from django.conf import settings +from django.core import management +from django.core.management.color import no_style from django.db import backend, connection, DEFAULT_DB_ALIAS from django.db.backends.signals import connection_created -from django.conf import settings from django.test import TestCase +from regressiontests.backends import models + class Callproc(unittest.TestCase): def test_dbms_session(self): @@ -76,6 +80,7 @@ class DateQuotingTest(TestCase): classes = models.SchoolClass.objects.filter(last_updated__day=20) self.assertEqual(len(classes), 1) + class ParameterHandlingTest(TestCase): def test_bad_parameter_count(self): "An executemany call with too many/not enough parameters will raise an exception (Refs #12612)" @@ -88,6 +93,50 @@ class ParameterHandlingTest(TestCase): self.assertRaises(Exception, cursor.executemany, query, [(1,2,3),]) self.assertRaises(Exception, cursor.executemany, query, [(1,),]) +# Unfortunately, the following tests would be a good test to run on all +# backends, but it breaks MySQL hard. Until #13711 is fixed, it can't be run +# everywhere (although it would be an effective test of #13711). +if settings.DATABASES[DEFAULT_DB_ALIAS]['ENGINE'] != 'django.db.backends.mysql': + class LongNameTest(TestCase): + """Long primary keys and model names can result in a sequence name + that exceeds the database limits, which will result in truncation + on certain databases (e.g., Postgres). The backend needs to use + the correct sequence name in last_insert_id and other places, so + check it is. Refs #8901. + """ + + def test_sequence_name_length_limits_create(self): + """Test creation of model with long name and long pk name doesn't error. Ref #8901""" + models.VeryLongModelNameZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ.objects.create() + + def test_sequence_name_length_limits_m2m(self): + """Test an m2m save of a model with a long name and a long m2m field name doesn't error as on Django >=1.2 this now uses object saves. Ref #8901""" + obj = models.VeryLongModelNameZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ.objects.create() + rel_obj = models.Person.objects.create(first_name='Django', last_name='Reinhardt') + obj.m2m_also_quite_long_zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.add(rel_obj) + + def test_sequence_name_length_limits_flush(self): + """Test that sequence resetting as part of a flush with model with long name and long pk name doesn't error. Ref #8901""" + # A full flush is expensive to the full test, so we dig into the + # internals to generate the likely offending SQL and run it manually + + # Some convenience aliases + VLM = models.VeryLongModelNameZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ + VLM_m2m = VLM.m2m_also_quite_long_zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.through + tables = [ + VLM._meta.db_table, + VLM_m2m._meta.db_table, + ] + sequences = [ + { + 'column': VLM._meta.pk.column, + 'table': VLM._meta.db_table + }, + ] + cursor = connection.cursor() + for statement in connection.ops.sql_flush(no_style(), tables, sequences): + cursor.execute(statement) + def connection_created_test(sender, **kwargs): print 'connection_created signal' diff --git a/tests/regressiontests/httpwrappers/tests.py b/tests/regressiontests/httpwrappers/tests.py index 132472ca37..23aa526a37 100644 --- a/tests/regressiontests/httpwrappers/tests.py +++ b/tests/regressiontests/httpwrappers/tests.py @@ -1,476 +1,228 @@ -""" -################### -# Empty QueryDict # -################### +import copy +import pickle +import unittest +from django.http import QueryDict, HttpResponse, CompatCookie, BadHeaderError ->>> q = QueryDict('') +class QueryDictTests(unittest.TestCase): + def test_missing_key(self): + q = QueryDict('') + self.assertRaises(KeyError, q.__getitem__, 'foo') ->>> q['foo'] -Traceback (most recent call last): -... -MultiValueDictKeyError: "Key 'foo' not found in <QueryDict: {}>" + def test_immutability(self): + q = QueryDict('') + self.assertRaises(AttributeError, q.__setitem__, 'something', 'bar') + self.assertRaises(AttributeError, q.setlist, 'foo', ['bar']) + self.assertRaises(AttributeError, q.appendlist, 'foo', ['bar']) + self.assertRaises(AttributeError, q.update, {'foo': 'bar'}) + self.assertRaises(AttributeError, q.pop, 'foo') + self.assertRaises(AttributeError, q.popitem) + self.assertRaises(AttributeError, q.clear) + + def test_immutable_get_with_default(self): + q = QueryDict('') + self.assertEqual(q.get('foo', 'default'), 'default') ->>> q['something'] = 'bar' -Traceback (most recent call last): -... -AttributeError: This QueryDict instance is immutable + def test_immutable_basic_operations(self): + q = QueryDict('') + self.assertEqual(q.getlist('foo'), []) + self.assertEqual(q.has_key('foo'), False) + self.assertEqual('foo' in q, False) + self.assertEqual(q.items(), []) + self.assertEqual(q.lists(), []) + self.assertEqual(q.items(), []) + self.assertEqual(q.keys(), []) + self.assertEqual(q.values(), []) + self.assertEqual(len(q), 0) + self.assertEqual(q.urlencode(), '') + + def test_single_key_value(self): + """Test QueryDict with one key/value pair""" ->>> q.get('foo', 'default') -'default' + q = QueryDict('foo=bar') + self.assertEqual(q['foo'], 'bar') + self.assertRaises(KeyError, q.__getitem__, 'bar') + self.assertRaises(AttributeError, q.__setitem__, 'something', 'bar') ->>> q.getlist('foo') -[] + self.assertEqual(q.get('foo', 'default'), 'bar') + self.assertEqual(q.get('bar', 'default'), 'default') + self.assertEqual(q.getlist('foo'), ['bar']) + self.assertEqual(q.getlist('bar'), []) + + self.assertRaises(AttributeError, q.setlist, 'foo', ['bar']) + self.assertRaises(AttributeError, q.appendlist, 'foo', ['bar']) ->>> q.setlist('foo', ['bar', 'baz']) -Traceback (most recent call last): -... -AttributeError: This QueryDict instance is immutable + self.failUnless(q.has_key('foo')) + self.failUnless('foo' in q) + self.failIf(q.has_key('bar')) + self.failIf('bar' in q) ->>> q.appendlist('foo', ['bar']) -Traceback (most recent call last): -... -AttributeError: This QueryDict instance is immutable + self.assertEqual(q.items(), [(u'foo', u'bar')]) + self.assertEqual(q.lists(), [(u'foo', [u'bar'])]) + self.assertEqual(q.keys(), ['foo']) + self.assertEqual(q.values(), ['bar']) + self.assertEqual(len(q), 1) ->>> q.has_key('foo') -False + self.assertRaises(AttributeError, q.update, {'foo': 'bar'}) + self.assertRaises(AttributeError, q.pop, 'foo') + self.assertRaises(AttributeError, q.popitem) + self.assertRaises(AttributeError, q.clear) + self.assertRaises(AttributeError, q.setdefault, 'foo', 'bar') + + self.assertEqual(q.urlencode(), 'foo=bar') + + def test_mutable_copy(self): + """A copy of a QueryDict is mutable.""" + q = QueryDict('').copy() + self.assertRaises(KeyError, q.__getitem__, "foo") + q['name'] = 'john' + self.assertEqual(q['name'], 'john') + + def test_mutable_delete(self): + q = QueryDict('').copy() + q['name'] = 'john' + del q['name'] + self.failIf('name' in q) ->>> 'foo' in q -False + def test_basic_mutable_operations(self): + q = QueryDict('').copy() + q['name'] = 'john' + self.assertEqual(q.get('foo', 'default'), 'default') + self.assertEqual(q.get('name', 'default'), 'john') + self.assertEqual(q.getlist('name'), ['john']) + self.assertEqual(q.getlist('foo'), []) ->>> q.items() -[] + q.setlist('foo', ['bar', 'baz']) + self.assertEqual(q.get('foo', 'default'), 'baz') + self.assertEqual(q.getlist('foo'), ['bar', 'baz']) ->>> q.lists() -[] + q.appendlist('foo', 'another') + self.assertEqual(q.getlist('foo'), ['bar', 'baz', 'another']) + self.assertEqual(q['foo'], 'another') + self.failUnless(q.has_key('foo')) + self.failUnless('foo' in q) ->>> q.keys() -[] + self.assertEqual(q.items(), [(u'foo', u'another'), (u'name', u'john')]) + self.assertEqual(q.lists(), [(u'foo', [u'bar', u'baz', u'another']), (u'name', [u'john'])]) + self.assertEqual(q.keys(), [u'foo', u'name']) + self.assertEqual(q.values(), [u'another', u'john']) + self.assertEqual(len(q), 2) ->>> q.values() -[] + q.update({'foo': 'hello'}) + self.assertEqual(q['foo'], 'hello') + self.assertEqual(q.get('foo', 'not available'), 'hello') + self.assertEqual(q.getlist('foo'), [u'bar', u'baz', u'another', u'hello']) + self.assertEqual(q.pop('foo'), [u'bar', u'baz', u'another', u'hello']) + self.assertEqual(q.pop('foo', 'not there'), 'not there') + self.assertEqual(q.get('foo', 'not there'), 'not there') + self.assertEqual(q.setdefault('foo', 'bar'), 'bar') + self.assertEqual(q['foo'], 'bar') + self.assertEqual(q.getlist('foo'), ['bar']) + self.assertEqual(q.urlencode(), 'foo=bar&name=john') ->>> len(q) -0 + q.clear() + self.assertEqual(len(q), 0) ->>> q.update({'foo': 'bar'}) -Traceback (most recent call last): -... -AttributeError: This QueryDict instance is immutable + def test_multiple_keys(self): + """Test QueryDict with two key/value pairs with same keys.""" ->>> q.pop('foo') -Traceback (most recent call last): -... -AttributeError: This QueryDict instance is immutable + q = QueryDict('vote=yes&vote=no') + + self.assertEqual(q['vote'], u'no') + self.assertRaises(AttributeError, q.__setitem__, 'something', 'bar') + + self.assertEqual(q.get('vote', 'default'), u'no') + self.assertEqual(q.get('foo', 'default'), 'default') + self.assertEqual(q.getlist('vote'), [u'yes', u'no']) + self.assertEqual(q.getlist('foo'), []) + + self.assertRaises(AttributeError, q.setlist, 'foo', ['bar', 'baz']) + self.assertRaises(AttributeError, q.setlist, 'foo', ['bar', 'baz']) + self.assertRaises(AttributeError, q.appendlist, 'foo', ['bar']) ->>> q.popitem() -Traceback (most recent call last): -... -AttributeError: This QueryDict instance is immutable - ->>> q.clear() -Traceback (most recent call last): -... -AttributeError: This QueryDict instance is immutable - ->>> q.setdefault('foo', 'bar') -Traceback (most recent call last): -... -AttributeError: This QueryDict instance is immutable - ->>> q.urlencode() -'' - -################################### -# Mutable copy of empty QueryDict # -################################### - ->>> q = q.copy() - ->>> q['foo'] -Traceback (most recent call last): -... -MultiValueDictKeyError: "Key 'foo' not found in <QueryDict: {}>" - ->>> q['name'] = 'john' - ->>> q['name'] -u'john' - ->>> del q['name'] ->>> 'name' in q -False - ->>> q['name'] = 'john' - ->>> q.get('foo', 'default') -'default' - ->>> q.get('name', 'default') -u'john' - ->>> q.getlist('name') -[u'john'] - ->>> q.getlist('foo') -[] - ->>> q.setlist('foo', ['bar', 'baz']) - ->>> q.get('foo', 'default') -u'baz' - ->>> q.getlist('foo') -[u'bar', u'baz'] - ->>> q.appendlist('foo', 'another') - ->>> q.getlist('foo') -[u'bar', u'baz', u'another'] - ->>> q['foo'] -u'another' - ->>> q.has_key('foo') -True - ->>> 'foo' in q -True - ->>> q.items() -[(u'foo', u'another'), (u'name', u'john')] - ->>> q.lists() -[(u'foo', [u'bar', u'baz', u'another']), (u'name', [u'john'])] - ->>> q.keys() -[u'foo', u'name'] - ->>> q.values() -[u'another', u'john'] - ->>> len(q) -2 - ->>> q.update({'foo': 'hello'}) - -# Displays last value ->>> q['foo'] -u'hello' - ->>> q.get('foo', 'not available') -u'hello' - ->>> q.getlist('foo') -[u'bar', u'baz', u'another', u'hello'] - ->>> q.pop('foo') -[u'bar', u'baz', u'another', u'hello'] - ->>> q.pop('foo', 'not there') -'not there' - ->>> q.get('foo', 'not there') -'not there' - ->>> q.setdefault('foo', 'bar') -u'bar' - ->>> q['foo'] -u'bar' - ->>> q.getlist('foo') -[u'bar'] - ->>> q.urlencode() -'foo=bar&name=john' - ->>> q.clear() - ->>> len(q) -0 - -##################################### -# QueryDict with one key/value pair # -##################################### - ->>> q = QueryDict('foo=bar') - ->>> q['foo'] -u'bar' - ->>> q['bar'] -Traceback (most recent call last): -... -MultiValueDictKeyError: "Key 'bar' not found in <QueryDict: {u'foo': [u'bar']}>" - ->>> q['something'] = 'bar' -Traceback (most recent call last): -... -AttributeError: This QueryDict instance is immutable - ->>> q.get('foo', 'default') -u'bar' - ->>> q.get('bar', 'default') -'default' - ->>> q.getlist('foo') -[u'bar'] - ->>> q.getlist('bar') -[] - ->>> q.setlist('foo', ['bar', 'baz']) -Traceback (most recent call last): -... -AttributeError: This QueryDict instance is immutable - ->>> q.appendlist('foo', ['bar']) -Traceback (most recent call last): -... -AttributeError: This QueryDict instance is immutable - ->>> q.has_key('foo') -True - ->>> 'foo' in q -True - ->>> q.has_key('bar') -False - ->>> 'bar' in q -False - ->>> q.items() -[(u'foo', u'bar')] - ->>> q.lists() -[(u'foo', [u'bar'])] - ->>> q.keys() -[u'foo'] - ->>> q.values() -[u'bar'] - ->>> len(q) -1 - ->>> q.update({'foo': 'bar'}) -Traceback (most recent call last): -... -AttributeError: This QueryDict instance is immutable - ->>> q.pop('foo') -Traceback (most recent call last): -... -AttributeError: This QueryDict instance is immutable - ->>> q.popitem() -Traceback (most recent call last): -... -AttributeError: This QueryDict instance is immutable - ->>> q.clear() -Traceback (most recent call last): -... -AttributeError: This QueryDict instance is immutable - ->>> q.setdefault('foo', 'bar') -Traceback (most recent call last): -... -AttributeError: This QueryDict instance is immutable - ->>> q.urlencode() -'foo=bar' - -##################################################### -# QueryDict with two key/value pairs with same keys # -##################################################### - ->>> q = QueryDict('vote=yes&vote=no') - ->>> q['vote'] -u'no' - ->>> q['something'] = 'bar' -Traceback (most recent call last): -... -AttributeError: This QueryDict instance is immutable - ->>> q.get('vote', 'default') -u'no' - ->>> q.get('foo', 'default') -'default' - ->>> q.getlist('vote') -[u'yes', u'no'] - ->>> q.getlist('foo') -[] - ->>> q.setlist('foo', ['bar', 'baz']) -Traceback (most recent call last): -... -AttributeError: This QueryDict instance is immutable - ->>> q.appendlist('foo', ['bar']) -Traceback (most recent call last): -... -AttributeError: This QueryDict instance is immutable - ->>> q.has_key('vote') -True - ->>> 'vote' in q -True - ->>> q.has_key('foo') -False - ->>> 'foo' in q -False - ->>> q.items() -[(u'vote', u'no')] - ->>> q.lists() -[(u'vote', [u'yes', u'no'])] - ->>> q.keys() -[u'vote'] - ->>> q.values() -[u'no'] - ->>> len(q) -1 - ->>> q.update({'foo': 'bar'}) -Traceback (most recent call last): -... -AttributeError: This QueryDict instance is immutable - ->>> q.pop('foo') -Traceback (most recent call last): -... -AttributeError: This QueryDict instance is immutable - ->>> q.popitem() -Traceback (most recent call last): -... -AttributeError: This QueryDict instance is immutable - ->>> q.clear() -Traceback (most recent call last): -... -AttributeError: This QueryDict instance is immutable - ->>> q.setdefault('foo', 'bar') -Traceback (most recent call last): -... -AttributeError: This QueryDict instance is immutable - ->>> q.urlencode() -'vote=yes&vote=no' - ->>> del q['vote'] -Traceback (most recent call last): -... -AttributeError: This QueryDict instance is immutable - -# QueryDicts must be able to handle invalid input encoding (in this case, bad -# UTF-8 encoding). ->>> q = QueryDict('foo=bar&foo=\xff') - ->>> q['foo'] -u'\ufffd' - ->>> q.getlist('foo') -[u'bar', u'\ufffd'] - - -######################## -# Pickling a QueryDict # -######################## ->>> import pickle ->>> q = QueryDict('') ->>> q1 = pickle.loads(pickle.dumps(q, 2)) ->>> q == q1 -True ->>> q = QueryDict('a=b&c=d') ->>> q1 = pickle.loads(pickle.dumps(q, 2)) ->>> q == q1 -True ->>> q = QueryDict('a=b&c=d&a=1') ->>> q1 = pickle.loads(pickle.dumps(q, 2)) ->>> q == q1 -True - -###################################### -# HttpResponse with Unicode headers # -###################################### - ->>> r = HttpResponse() - -If we insert a unicode value it will be converted to an ascii -string. This makes sure we comply with the HTTP specifications. - ->>> r['value'] = u'test value' ->>> isinstance(r['value'], str) -True - -An error is raised When a unicode object with non-ascii is assigned. - ->>> r['value'] = u't\xebst value' # doctest:+ELLIPSIS -Traceback (most recent call last): -... -UnicodeEncodeError: ..., HTTP response headers must be in US-ASCII format - -The response also converts unicode keys to strings. - ->>> r[u'test'] = 'testing key' ->>> l = list(r.items()) ->>> l.sort() ->>> l[1] -('test', 'testing key') - -It will also raise errors for keys with non-ascii data. - ->>> r[u't\xebst'] = 'testing key' # doctest:+ELLIPSIS -Traceback (most recent call last): -... -UnicodeEncodeError: ..., HTTP response headers must be in US-ASCII format - -# Bug #10188: Do not allow newlines in headers (CR or LF) ->>> r['test\\rstr'] = 'test' -Traceback (most recent call last): -... -BadHeaderError: Header values can't contain newlines (got 'test\\rstr') - ->>> r['test\\nstr'] = 'test' -Traceback (most recent call last): -... -BadHeaderError: Header values can't contain newlines (got 'test\\nstr') + self.assertEqual(q.has_key('vote'), True) + self.assertEqual('vote' in q, True) + self.assertEqual(q.has_key('foo'), False) + self.assertEqual('foo' in q, False) + self.assertEqual(q.items(), [(u'vote', u'no')]) + self.assertEqual(q.lists(), [(u'vote', [u'yes', u'no'])]) + self.assertEqual(q.keys(), [u'vote']) + self.assertEqual(q.values(), [u'no']) + self.assertEqual(len(q), 1) + + self.assertRaises(AttributeError, q.update, {'foo': 'bar'}) + self.assertRaises(AttributeError, q.pop, 'foo') + self.assertRaises(AttributeError, q.popitem) + self.assertRaises(AttributeError, q.clear) + self.assertRaises(AttributeError, q.setdefault, 'foo', 'bar') + self.assertRaises(AttributeError, q.__delitem__, 'vote') + + def test_invalid_input_encoding(self): + """ + QueryDicts must be able to handle invalid input encoding (in this + case, bad UTF-8 encoding). + """ + q = QueryDict('foo=bar&foo=\xff') + self.assertEqual(q['foo'], u'\ufffd') + self.assertEqual(q.getlist('foo'), [u'bar', u'\ufffd']) + + def test_pickle(self): + q = QueryDict('') + q1 = pickle.loads(pickle.dumps(q, 2)) + self.assertEqual(q == q1, True) + q = QueryDict('a=b&c=d') + q1 = pickle.loads(pickle.dumps(q, 2)) + self.assertEqual(q == q1, True) + q = QueryDict('a=b&c=d&a=1') + q1 = pickle.loads(pickle.dumps(q, 2)) + self.assertEqual(q == q1 , True) -# -# Regression test for #8278: QueryDict.update(QueryDict) -# ->>> x = QueryDict("a=1&a=2", mutable=True) ->>> y = QueryDict("a=3&a=4") ->>> x.update(y) ->>> x.getlist('a') -[u'1', u'2', u'3', u'4'] -""" + def test_update_from_querydict(self): + """Regression test for #8278: QueryDict.update(QueryDict)""" + x = QueryDict("a=1&a=2", mutable=True) + y = QueryDict("a=3&a=4") + x.update(y) + self.assertEqual(x.getlist('a'), [u'1', u'2', u'3', u'4']) -from django.http import QueryDict, HttpResponse, CompatCookie -from django.test import TestCase + def test_non_default_encoding(self): + """#13572 - QueryDict with a non-default encoding""" + q = QueryDict('sbb=one', encoding='rot_13') + self.assertEqual(q.encoding , 'rot_13' ) + self.assertEqual(q.items() , [(u'foo', u'bar')] ) + self.assertEqual(q.urlencode() , 'sbb=one' ) + q = q.copy() + self.assertEqual(q.encoding , 'rot_13' ) + self.assertEqual(q.items() , [(u'foo', u'bar')] ) + self.assertEqual(q.urlencode() , 'sbb=one' ) + self.assertEqual(copy.copy(q).encoding , 'rot_13' ) + self.assertEqual(copy.deepcopy(q).encoding , 'rot_13') + +class HttpResponseTests(unittest.TestCase): + def test_unicode_headers(self): + r = HttpResponse() + # If we insert a unicode value it will be converted to an ascii + r['value'] = u'test value' + self.failUnless(isinstance(r['value'], str)) + + # An error is raised When a unicode object with non-ascii is assigned. + self.assertRaises(UnicodeEncodeError, r.__setitem__, 'value', u't\xebst value') + + # The response also converts unicode keys to strings.) + r[u'test'] = 'testing key' + l = list(r.items()) + l.sort() + self.assertEqual(l[1], ('test', 'testing key')) + + # It will also raise errors for keys with non-ascii data. + self.assertRaises(UnicodeEncodeError, r.__setitem__, u't\xebst key', 'value') -class Cookies(TestCase): + def test_newlines_in_headers(self): + # Bug #10188: Do not allow newlines in headers (CR or LF) + r = HttpResponse() + self.assertRaises(BadHeaderError, r.__setitem__, 'test\rstr', 'test') + self.assertRaises(BadHeaderError, r.__setitem__, 'test\nstr', 'test') +class CookieTests(unittest.TestCase): def test_encode(self): """ Test that we don't output tricky characters in encoded value @@ -502,7 +254,3 @@ class Cookies(TestCase): c2 = CompatCookie() c2.load(c.output()) self.assertEqual(c['test'].value, c2['test'].value) - -if __name__ == "__main__": - import doctest - doctest.testmod() diff --git a/tests/regressiontests/m2m_through_regress/models.py b/tests/regressiontests/m2m_through_regress/models.py index 56aecd6975..ec87985765 100644 --- a/tests/regressiontests/m2m_through_regress/models.py +++ b/tests/regressiontests/m2m_through_regress/models.py @@ -1,8 +1,10 @@ from datetime import datetime + from django.contrib.auth.models import User from django.core import management from django.db import models + # Forward declared intermediate model class Membership(models.Model): person = models.ForeignKey('Person') @@ -51,159 +53,3 @@ class Through(ThroughBase): class B(models.Model): b_text = models.CharField(max_length=20) a_list = models.ManyToManyField(A, through=Through) - - -__test__ = {'API_TESTS':""" -# Create some dummy data ->>> bob = Person.objects.create(name='Bob') ->>> jim = Person.objects.create(name='Jim') - ->>> rock = Group.objects.create(name='Rock') ->>> roll = Group.objects.create(name='Roll') - ->>> frank = User.objects.create_user('frank','frank@example.com','password') ->>> jane = User.objects.create_user('jane','jane@example.com','password') - -# Now test that the forward declared Membership works ->>> Membership.objects.create(person=bob, group=rock) -<Membership: Bob is a member of Rock> - ->>> Membership.objects.create(person=bob, group=roll) -<Membership: Bob is a member of Roll> - ->>> Membership.objects.create(person=jim, group=rock) -<Membership: Jim is a member of Rock> - ->>> bob.group_set.all() -[<Group: Rock>, <Group: Roll>] - ->>> roll.members.all() -[<Person: Bob>] - -# Error messages use the model name, not repr of the class name ->>> bob.group_set = [] -Traceback (most recent call last): -... -AttributeError: Cannot set values on a ManyToManyField which specifies an intermediary model. Use m2m_through_regress.Membership's Manager instead. - ->>> roll.members = [] -Traceback (most recent call last): -... -AttributeError: Cannot set values on a ManyToManyField which specifies an intermediary model. Use m2m_through_regress.Membership's Manager instead. - ->>> rock.members.create(name='Anne') -Traceback (most recent call last): -... -AttributeError: Cannot use create() on a ManyToManyField which specifies an intermediary model. Use m2m_through_regress.Membership's Manager instead. - ->>> bob.group_set.create(name='Funk') -Traceback (most recent call last): -... -AttributeError: Cannot use create() on a ManyToManyField which specifies an intermediary model. Use m2m_through_regress.Membership's Manager instead. - -# Now test that the intermediate with a relationship outside -# the current app (i.e., UserMembership) workds ->>> UserMembership.objects.create(user=frank, group=rock) -<UserMembership: frank is a user and member of Rock> - ->>> UserMembership.objects.create(user=frank, group=roll) -<UserMembership: frank is a user and member of Roll> - ->>> UserMembership.objects.create(user=jane, group=rock) -<UserMembership: jane is a user and member of Rock> - ->>> frank.group_set.all() -[<Group: Rock>, <Group: Roll>] - ->>> roll.user_members.all() -[<User: frank>] - -# Regression test for #8134 -- -# m2m-through models shouldn't be serialized as m2m fields on the model. - -# First, clean up a lot of objects we don't need. -# The serialization test only requires three objects to work - -# one for each end of the m2m, plus the through model. - ->>> User.objects.all().delete() ->>> UserMembership.objects.all().delete() ->>> frank.delete() ->>> rock.delete() ->>> jim.delete() - -# Dump the current contents of the database as a JSON fixture ->>> management.call_command('dumpdata', 'm2m_through_regress', format='json', indent=2) -[ - { - "pk": 2, - "model": "m2m_through_regress.membership", - "fields": { - "person": 1, - "price": 100, - "group": 2 - } - }, - { - "pk": 1, - "model": "m2m_through_regress.person", - "fields": { - "name": "Bob" - } - }, - { - "pk": 2, - "model": "m2m_through_regress.group", - "fields": { - "name": "Roll" - } - } -] - -# Check the XML serializer too, since it doesn't use the common implementation ->>> management.call_command('dumpdata', 'm2m_through_regress', format='xml', indent=2) -<?xml version="1.0" encoding="utf-8"?> -<django-objects version="1.0"> - <object pk="2" model="m2m_through_regress.membership"> - <field to="m2m_through_regress.person" name="person" rel="ManyToOneRel">1</field> - <field to="m2m_through_regress.group" name="group" rel="ManyToOneRel">2</field> - <field type="IntegerField" name="price">100</field> - </object> - <object pk="1" model="m2m_through_regress.person"> - <field type="CharField" name="name">Bob</field> - </object> - <object pk="2" model="m2m_through_regress.group"> - <field type="CharField" name="name">Roll</field> - </object> -</django-objects> - -## Regression test for #8046: -Check that we don't involve too many copies of the intermediate table when -doing a join. - ->>> bob = Person.objects.create(name='Bob') ->>> jim = Person.objects.create(name='Jim') ->>> rock = Group.objects.create(name='Rock') ->>> roll = Group.objects.create(name='Roll') ->>> _ = Membership.objects.create(person=bob, group=rock) ->>> _ = Membership.objects.create(person=jim, group=rock, price=50) ->>> _ = Membership.objects.create(person=bob, group=roll, price=50) ->>> rock.members.filter(membership__price=50) -[<Person: Jim>] - -## Regression test for #8254 ->>> bob.group_set.filter(membership__price=50) -[<Group: Roll>] - -## Regression test for #9804 -# Flush the database, just to make sure we can. ->>> management.call_command('flush', verbosity=0, interactive=False) - -## Regression test for #11107 -Ensure that sequences on m2m_through tables are being created for the through -model, not for a phantom auto-generated m2m table. - ->>> management.call_command('loaddata', 'm2m_through', verbosity=0) ->>> management.call_command('dumpdata', 'm2m_through_regress', format='json') -[{"pk": 1, "model": "m2m_through_regress.usermembership", "fields": {"price": 100, "group": 1, "user": 1}}, {"pk": 1, "model": "m2m_through_regress.person", "fields": {"name": "Guido"}}, {"pk": 1, "model": "m2m_through_regress.group", "fields": {"name": "Python Core Group"}}] - -"""} diff --git a/tests/regressiontests/m2m_through_regress/tests.py b/tests/regressiontests/m2m_through_regress/tests.py new file mode 100644 index 0000000000..ff1d95020e --- /dev/null +++ b/tests/regressiontests/m2m_through_regress/tests.py @@ -0,0 +1,126 @@ +try: + from cStringIO import StringIO +except ImportError: + from StringIO import StringIO + +from django.core import management +from django.contrib.auth.models import User +from django.test import TestCase + +from models import Person, Group, Membership, UserMembership + + +class M2MThroughTestCase(TestCase): + def test_everything(self): + bob = Person.objects.create(name="Bob") + jim = Person.objects.create(name="Jim") + + rock = Group.objects.create(name="Rock") + roll = Group.objects.create(name="Roll") + + frank = User.objects.create_user("frank", "frank@example.com", "password") + jane = User.objects.create_user("jane", "jane@example.com", "password") + + Membership.objects.create(person=bob, group=rock) + Membership.objects.create(person=bob, group=roll) + Membership.objects.create(person=jim, group=rock) + + self.assertQuerysetEqual( + bob.group_set.all(), [ + "<Group: Rock>", + "<Group: Roll>", + ] + ) + + self.assertQuerysetEqual( + roll.members.all(), [ + "<Person: Bob>", + ] + ) + + self.assertRaises(AttributeError, setattr, bob, "group_set", []) + self.assertRaises(AttributeError, setattr, roll, "members", []) + + self.assertRaises(AttributeError, rock.members.create, name="Anne") + self.assertRaises(AttributeError, bob.group_set.create, name="Funk") + + UserMembership.objects.create(user=frank, group=rock) + UserMembership.objects.create(user=frank, group=roll) + UserMembership.objects.create(user=jane, group=rock) + + self.assertQuerysetEqual( + frank.group_set.all(), [ + "<Group: Rock>", + "<Group: Roll>", + ] + ) + + self.assertQuerysetEqual( + roll.user_members.all(), [ + "<User: frank>", + ] + ) + + def test_serialization(self): + "m2m-through models aren't serialized as m2m fields. Refs #8134" + + p = Person.objects.create(name="Bob") + g = Group.objects.create(name="Roll") + Membership.objects.create(person=p, group=g) + + out = StringIO() + management.call_command("dumpdata", "m2m_through_regress", format="json", stdout=out) + self.assertEqual(out.getvalue().strip(), """[{"pk": 1, "model": "m2m_through_regress.membership", "fields": {"person": 1, "price": 100, "group": 1}}, {"pk": 1, "model": "m2m_through_regress.person", "fields": {"name": "Bob"}}, {"pk": 1, "model": "m2m_through_regress.group", "fields": {"name": "Roll"}}]""") + + out = StringIO() + management.call_command("dumpdata", "m2m_through_regress", format="xml", + indent=2, stdout=out) + self.assertEqual(out.getvalue().strip(), """ +<?xml version="1.0" encoding="utf-8"?> +<django-objects version="1.0"> + <object pk="1" model="m2m_through_regress.membership"> + <field to="m2m_through_regress.person" name="person" rel="ManyToOneRel">1</field> + <field to="m2m_through_regress.group" name="group" rel="ManyToOneRel">1</field> + <field type="IntegerField" name="price">100</field> + </object> + <object pk="1" model="m2m_through_regress.person"> + <field type="CharField" name="name">Bob</field> + </object> + <object pk="1" model="m2m_through_regress.group"> + <field type="CharField" name="name">Roll</field> + </object> +</django-objects> + """.strip()) + + def test_join_trimming(self): + "Check that we don't involve too many copies of the intermediate table when doing a join. Refs #8046, #8254" + bob = Person.objects.create(name="Bob") + jim = Person.objects.create(name="Jim") + + rock = Group.objects.create(name="Rock") + roll = Group.objects.create(name="Roll") + + Membership.objects.create(person=bob, group=rock) + Membership.objects.create(person=jim, group=rock, price=50) + Membership.objects.create(person=bob, group=roll, price=50) + + self.assertQuerysetEqual( + rock.members.filter(membership__price=50), [ + "<Person: Jim>", + ] + ) + + self.assertQuerysetEqual( + bob.group_set.filter(membership__price=50), [ + "<Group: Roll>", + ] + ) + +class ThroughLoadDataTestCase(TestCase): + fixtures = ["m2m_through"] + + def test_sequence_creation(self): + "Check that sequences on an m2m_through are created for the through model, not a phantom auto-generated m2m table. Refs #11107" + out = StringIO() + management.call_command("dumpdata", "m2m_through_regress", format="json", stdout=out) + self.assertEqual(out.getvalue().strip(), """[{"pk": 1, "model": "m2m_through_regress.usermembership", "fields": {"price": 100, "group": 1, "user": 1}}, {"pk": 1, "model": "m2m_through_regress.person", "fields": {"name": "Guido"}}, {"pk": 1, "model": "m2m_through_regress.group", "fields": {"name": "Python Core Group"}}]""") diff --git a/tests/regressiontests/multiple_database/tests.py b/tests/regressiontests/multiple_database/tests.py index 7bde8bf037..6675fdcc6c 100644 --- a/tests/regressiontests/multiple_database/tests.py +++ b/tests/regressiontests/multiple_database/tests.py @@ -883,7 +883,13 @@ class QueryTestCase(TestCase): self.assertRaises(ValueError, str, qs.query) # Evaluating the query shouldn't work, either - self.assertRaises(ValueError, list, qs) + try: + for obj in qs: + pass + self.fail('Iterating over query should raise ValueError') + except ValueError: + pass + class TestRouter(object): # A test router. The behaviour is vaguely master/slave, but the @@ -1491,19 +1497,10 @@ class AuthTestCase(TestCase): self.old_routers = router.routers router.routers = [AuthRouter()] - # Redirect stdout to a buffer so we can test - # the output of a management command - self.old_stdout = sys.stdout - self.stdout = StringIO() - sys.stdout = self.stdout - def tearDown(self): # Restore the 'other' database as an independent database router.routers = self.old_routers - # Restore stdout - sys.stdout = self.old_stdout - def test_auth_manager(self): "The methods on the auth manager obey database hints" # Create one user using default allocation policy @@ -1539,14 +1536,16 @@ class AuthTestCase(TestCase): # Check that dumping the default database doesn't try to include auth # because allow_syncdb prohibits auth on default - self.stdout.flush() - management.call_command('dumpdata', 'auth', format='json', database='default') - self.assertEquals(self.stdout.getvalue(), '[]\n') + new_io = StringIO() + management.call_command('dumpdata', 'auth', format='json', database='default', stdout=new_io) + command_output = new_io.getvalue().strip() + self.assertEqual(command_output, '[]') # Check that dumping the other database does include auth - self.stdout.flush() - management.call_command('dumpdata', 'auth', format='json', database='other') - self.assertTrue('alice@example.com' in self.stdout.getvalue()) + new_io = StringIO() + management.call_command('dumpdata', 'auth', format='json', database='other', stdout=new_io) + command_output = new_io.getvalue().strip() + self.assertTrue('"email": "alice@example.com",' in command_output) class UserProfileTestCase(TestCase): def setUp(self): diff --git a/tests/regressiontests/serializers_regress/tests.py b/tests/regressiontests/serializers_regress/tests.py index 84e90ff7e1..be920c6920 100644 --- a/tests/regressiontests/serializers_regress/tests.py +++ b/tests/regressiontests/serializers_regress/tests.py @@ -10,14 +10,16 @@ forward, backwards and self references. import datetime import decimal -import unittest -from cStringIO import StringIO +try: + from cStringIO import StringIO +except ImportError: + from StringIO import StringIO -from django.utils.functional import curry -from django.core import serializers -from django.db import transaction, DEFAULT_DB_ALIAS -from django.core import management from django.conf import settings +from django.core import serializers, management +from django.db import transaction, DEFAULT_DB_ALIAS +from django.test import TestCase +from django.utils.functional import curry from models import * @@ -59,10 +61,10 @@ def im2m_create(pk, klass, data): def im_create(pk, klass, data): instance = klass(id=pk) - setattr(instance, 'right_id', data['right']) - setattr(instance, 'left_id', data['left']) + instance.right_id = data['right'] + instance.left_id = data['left'] if 'extra' in data: - setattr(instance, 'extra', data['extra']) + instance.extra = data['extra'] models.Model.save_base(instance, raw=True) return [instance] @@ -96,7 +98,9 @@ def inherited_create(pk, klass, data): def data_compare(testcase, pk, klass, data): instance = klass.objects.get(id=pk) testcase.assertEqual(data, instance.data, - "Objects with PK=%d not equal; expected '%s' (%s), got '%s' (%s)" % (pk,data, type(data), instance.data, type(instance.data))) + "Objects with PK=%d not equal; expected '%s' (%s), got '%s' (%s)" % ( + pk, data, type(data), instance.data, type(instance.data)) + ) def generic_compare(testcase, pk, klass, data): instance = klass.objects.get(id=pk) @@ -348,28 +352,16 @@ if settings.DATABASES[DEFAULT_DB_ALIAS]['ENGINE'] != 'django.db.backends.mysql': # Dynamically create serializer tests to ensure that all # registered serializers are automatically tested. -class SerializerTests(unittest.TestCase): +class SerializerTests(TestCase): pass def serializerTest(format, self): - # Clear the database first - management.call_command('flush', verbosity=0, interactive=False) # Create all the objects defined in the test data objects = [] instance_count = {} - transaction.enter_transaction_management() - try: - transaction.managed(True) - for (func, pk, klass, datum) in test_data: - objects.extend(func[0](pk, klass, datum)) - instance_count[klass] = 0 - transaction.commit() - except: - transaction.rollback() - transaction.leave_transaction_management() - raise - transaction.leave_transaction_management() + for (func, pk, klass, datum) in test_data: + objects.extend(func[0](pk, klass, datum)) # Get a count of the number of objects created for each class for klass in instance_count: @@ -381,19 +373,8 @@ def serializerTest(format, self): # Serialize the test database serialized_data = serializers.serialize(format, objects, indent=2) - # Flush the database and recreate from the serialized data - management.call_command('flush', verbosity=0, interactive=False) - transaction.enter_transaction_management() - try: - transaction.managed(True) - for obj in serializers.deserialize(format, serialized_data): - obj.save() - transaction.commit() - except: - transaction.rollback() - transaction.leave_transaction_management() - raise - transaction.leave_transaction_management() + for obj in serializers.deserialize(format, serialized_data): + obj.save() # Assert that the deserialized data is the same # as the original source @@ -406,10 +387,7 @@ def serializerTest(format, self): self.assertEquals(count, klass.objects.count()) def fieldsTest(format, self): - # Clear the database first - management.call_command('flush', verbosity=0, interactive=False) - - obj = ComplexModel(field1='first',field2='second',field3='third') + obj = ComplexModel(field1='first', field2='second', field3='third') obj.save_base(raw=True) # Serialize then deserialize the test database @@ -422,9 +400,6 @@ def fieldsTest(format, self): self.assertEqual(result.object.field3, 'third') def streamTest(format, self): - # Clear the database first - management.call_command('flush', verbosity=0, interactive=False) - obj = ComplexModel(field1='first',field2='second',field3='third') obj.save_base(raw=True) @@ -440,7 +415,7 @@ def streamTest(format, self): stream.close() for format in serializers.get_serializer_formats(): - setattr(SerializerTests, 'test_'+format+'_serializer', curry(serializerTest, format)) - setattr(SerializerTests, 'test_'+format+'_serializer_fields', curry(fieldsTest, format)) + setattr(SerializerTests, 'test_' + format + '_serializer', curry(serializerTest, format)) + setattr(SerializerTests, 'test_' + format + '_serializer_fields', curry(fieldsTest, format)) if format != 'python': - setattr(SerializerTests, 'test_'+format+'_serializer_stream', curry(streamTest, format)) + setattr(SerializerTests, 'test_' + format + '_serializer_stream', curry(streamTest, format)) diff --git a/tests/regressiontests/utils/timesince.py b/tests/regressiontests/utils/timesince.py index 04878b272a..5a54bf4c8c 100644 --- a/tests/regressiontests/utils/timesince.py +++ b/tests/regressiontests/utils/timesince.py @@ -88,11 +88,11 @@ u'0 minutes' u'0 minutes' # Timesince should work with both date objects (#9672) ->>> today = datetime.date.today() ->>> timeuntil(today+oneday, today) -u'1 day' ->>> timeuntil(today-oneday, today) -u'0 minutes' ->>> timeuntil(today+oneweek, today) -u'1 week' +>>> today = datetime.date.today() +>>> timeuntil(today+oneday, today) +u'1 day' +>>> timeuntil(today-oneday, today) +u'0 minutes' +>>> timeuntil(today+oneweek, today) +u'1 week' """ |
