diff options
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/modeltests/fixtures/models.py | 227 | ||||
| -rw-r--r-- | tests/modeltests/fixtures/tests.py | 277 | ||||
| -rw-r--r-- | tests/modeltests/proxy_model_inheritance/tests.py | 2 | ||||
| -rw-r--r-- | tests/regressiontests/backends/models.py | 19 | ||||
| -rw-r--r-- | tests/regressiontests/backends/tests.py | 53 | ||||
| -rw-r--r-- | tests/regressiontests/csrf_tests/tests.py | 28 | ||||
| -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/utils/timesince.py | 14 |
10 files changed, 524 insertions, 411 deletions
diff --git a/tests/modeltests/fixtures/models.py b/tests/modeltests/fixtures/models.py index 46e07a5e6b..216a8e2502 100644 --- a/tests/modeltests/fixtures/models.py +++ b/tests/modeltests/fixtures/models.py @@ -90,230 +90,3 @@ class Book(models.Model): class Meta: ordering = ('name',) - -__test__ = {'API_TESTS': """ ->>> from django.core import management ->>> from django.db.models import get_app - -# Reset the database representation of this app. -# This will return the database to a clean initial state. ->>> management.call_command('flush', verbosity=0, interactive=False) - -# Syncdb introduces 1 initial data object from initial_data.json. ->>> Article.objects.all() -[<Article: Python program becomes self aware>] - -# Load fixture 1. Single JSON file, with two objects. ->>> management.call_command('loaddata', 'fixture1.json', verbosity=0) ->>> Article.objects.all() -[<Article: Time to reform copyright>, <Article: Poker has no place on ESPN>, <Article: Python program becomes self aware>] - -# Dump the current contents of the database as a JSON fixture ->>> management.call_command('dumpdata', 'fixtures', format='json') -[{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": "News Stories"}}, {"pk": 3, "model": "fixtures.article", "fields": {"headline": "Time to reform copyright", "pub_date": "2006-06-16 13:00:00"}}, {"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", "pub_date": "2006-06-16 12:00:00"}}, {"pk": 1, "model": "fixtures.article", "fields": {"headline": "Python program becomes self aware", "pub_date": "2006-06-16 11:00:00"}}] - -# Try just dumping the contents of fixtures.Category ->>> management.call_command('dumpdata', 'fixtures.Category', format='json') -[{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": "News Stories"}}] - -# ...and just fixtures.Article ->>> management.call_command('dumpdata', 'fixtures.Article', format='json') -[{"pk": 3, "model": "fixtures.article", "fields": {"headline": "Time to reform copyright", "pub_date": "2006-06-16 13:00:00"}}, {"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", "pub_date": "2006-06-16 12:00:00"}}, {"pk": 1, "model": "fixtures.article", "fields": {"headline": "Python program becomes self aware", "pub_date": "2006-06-16 11:00:00"}}] - -# ...and both ->>> management.call_command('dumpdata', 'fixtures.Category', 'fixtures.Article', format='json') -[{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": "News Stories"}}, {"pk": 3, "model": "fixtures.article", "fields": {"headline": "Time to reform copyright", "pub_date": "2006-06-16 13:00:00"}}, {"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", "pub_date": "2006-06-16 12:00:00"}}, {"pk": 1, "model": "fixtures.article", "fields": {"headline": "Python program becomes self aware", "pub_date": "2006-06-16 11:00:00"}}] - -# Specify a specific model twice ->>> management.call_command('dumpdata', 'fixtures.Article', 'fixtures.Article', format='json') -[{"pk": 3, "model": "fixtures.article", "fields": {"headline": "Time to reform copyright", "pub_date": "2006-06-16 13:00:00"}}, {"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", "pub_date": "2006-06-16 12:00:00"}}, {"pk": 1, "model": "fixtures.article", "fields": {"headline": "Python program becomes self aware", "pub_date": "2006-06-16 11:00:00"}}] - -# Specify a dump that specifies Article both explicitly and implicitly ->>> management.call_command('dumpdata', 'fixtures.Article', 'fixtures', format='json') -[{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": "News Stories"}}, {"pk": 3, "model": "fixtures.article", "fields": {"headline": "Time to reform copyright", "pub_date": "2006-06-16 13:00:00"}}, {"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", "pub_date": "2006-06-16 12:00:00"}}, {"pk": 1, "model": "fixtures.article", "fields": {"headline": "Python program becomes self aware", "pub_date": "2006-06-16 11:00:00"}}] - -# Same again, but specify in the reverse order ->>> management.call_command('dumpdata', 'fixtures', 'fixtures.Article', format='json') -[{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": "News Stories"}}, {"pk": 3, "model": "fixtures.article", "fields": {"headline": "Time to reform copyright", "pub_date": "2006-06-16 13:00:00"}}, {"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", "pub_date": "2006-06-16 12:00:00"}}, {"pk": 1, "model": "fixtures.article", "fields": {"headline": "Python program becomes self aware", "pub_date": "2006-06-16 11:00:00"}}] - -# Specify one model from one application, and an entire other application. ->>> management.call_command('dumpdata', 'fixtures.Category', 'sites', format='json') -[{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": "News Stories"}}, {"pk": 1, "model": "sites.site", "fields": {"domain": "example.com", "name": "example.com"}}] - -# Load fixture 2. JSON file imported by default. Overwrites some existing objects ->>> management.call_command('loaddata', 'fixture2.json', verbosity=0) ->>> Article.objects.all() -[<Article: Django conquers world!>, <Article: Copyright is fine the way it is>, <Article: Poker has no place on ESPN>, <Article: Python program becomes self aware>] - -# Load fixture 3, XML format. ->>> management.call_command('loaddata', 'fixture3.xml', verbosity=0) ->>> Article.objects.all() -[<Article: XML identified as leading cause of cancer>, <Article: Django conquers world!>, <Article: Copyright is fine the way it is>, <Article: Poker on TV is great!>, <Article: Python program becomes self aware>] - -# Load fixture 6, JSON file with dynamic ContentType fields. Testing ManyToOne. ->>> management.call_command('loaddata', 'fixture6.json', verbosity=0) ->>> Tag.objects.all() -[<Tag: <Article: Copyright is fine the way it is> tagged "copyright">, <Tag: <Article: Copyright is fine the way it is> tagged "law">] - -# Load fixture 7, XML file with dynamic ContentType fields. Testing ManyToOne. ->>> management.call_command('loaddata', 'fixture7.xml', verbosity=0) ->>> Tag.objects.all() -[<Tag: <Article: Copyright is fine the way it is> tagged "copyright">, <Tag: <Article: Copyright is fine the way it is> tagged "legal">, <Tag: <Article: Django conquers world!> tagged "django">, <Tag: <Article: Django conquers world!> tagged "world domination">] - -# Load fixture 8, JSON file with dynamic Permission fields. Testing ManyToMany. ->>> management.call_command('loaddata', 'fixture8.json', verbosity=0) ->>> Visa.objects.all() -[<Visa: Django Reinhardt Can add user, Can change user, Can delete user>, <Visa: Stephane Grappelli Can add user>, <Visa: Prince >] - -# Load fixture 9, XML file with dynamic Permission fields. Testing ManyToMany. ->>> management.call_command('loaddata', 'fixture9.xml', verbosity=0) ->>> Visa.objects.all() -[<Visa: Django Reinhardt Can add user, Can change user, Can delete user>, <Visa: Stephane Grappelli Can add user, Can delete user>, <Visa: Artist formerly known as "Prince" Can change user>] - ->>> Book.objects.all() -[<Book: Music for all ages by Artist formerly known as "Prince" and Django Reinhardt>] - -# Load a fixture that doesn't exist ->>> management.call_command('loaddata', 'unknown.json', verbosity=0) - -# object list is unaffected ->>> Article.objects.all() -[<Article: XML identified as leading cause of cancer>, <Article: Django conquers world!>, <Article: Copyright is fine the way it is>, <Article: Poker on TV is great!>, <Article: Python program becomes self aware>] - -# By default, you get raw keys on dumpdata ->>> management.call_command('dumpdata', 'fixtures.book', format='json') -[{"pk": 1, "model": "fixtures.book", "fields": {"name": "Music for all ages", "authors": [3, 1]}}] - -# But you can get natural keys if you ask for them and they are available ->>> management.call_command('dumpdata', 'fixtures.book', format='json', use_natural_keys=True) -[{"pk": 1, "model": "fixtures.book", "fields": {"name": "Music for all ages", "authors": [["Artist formerly known as \\"Prince\\""], ["Django Reinhardt"]]}}] - -# Dump the current contents of the database as a JSON fixture ->>> management.call_command('dumpdata', 'fixtures', format='json', use_natural_keys=True) -[{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": "News Stories"}}, {"pk": 5, "model": "fixtures.article", "fields": {"headline": "XML identified as leading cause of cancer", "pub_date": "2006-06-16 16:00:00"}}, {"pk": 4, "model": "fixtures.article", "fields": {"headline": "Django conquers world!", "pub_date": "2006-06-16 15:00:00"}}, {"pk": 3, "model": "fixtures.article", "fields": {"headline": "Copyright is fine the way it is", "pub_date": "2006-06-16 14:00:00"}}, {"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker on TV is great!", "pub_date": "2006-06-16 11:00:00"}}, {"pk": 1, "model": "fixtures.article", "fields": {"headline": "Python program becomes self aware", "pub_date": "2006-06-16 11:00:00"}}, {"pk": 1, "model": "fixtures.tag", "fields": {"tagged_type": ["fixtures", "article"], "name": "copyright", "tagged_id": 3}}, {"pk": 2, "model": "fixtures.tag", "fields": {"tagged_type": ["fixtures", "article"], "name": "legal", "tagged_id": 3}}, {"pk": 3, "model": "fixtures.tag", "fields": {"tagged_type": ["fixtures", "article"], "name": "django", "tagged_id": 4}}, {"pk": 4, "model": "fixtures.tag", "fields": {"tagged_type": ["fixtures", "article"], "name": "world domination", "tagged_id": 4}}, {"pk": 3, "model": "fixtures.person", "fields": {"name": "Artist formerly known as \\"Prince\\""}}, {"pk": 1, "model": "fixtures.person", "fields": {"name": "Django Reinhardt"}}, {"pk": 2, "model": "fixtures.person", "fields": {"name": "Stephane Grappelli"}}, {"pk": 1, "model": "fixtures.visa", "fields": {"person": ["Django Reinhardt"], "permissions": [["add_user", "auth", "user"], ["change_user", "auth", "user"], ["delete_user", "auth", "user"]]}}, {"pk": 2, "model": "fixtures.visa", "fields": {"person": ["Stephane Grappelli"], "permissions": [["add_user", "auth", "user"], ["delete_user", "auth", "user"]]}}, {"pk": 3, "model": "fixtures.visa", "fields": {"person": ["Artist formerly known as \\"Prince\\""], "permissions": [["change_user", "auth", "user"]]}}, {"pk": 1, "model": "fixtures.book", "fields": {"name": "Music for all ages", "authors": [["Artist formerly known as \\"Prince\\""], ["Django Reinhardt"]]}}] - -# Dump the current contents of the database as an XML fixture ->>> management.call_command('dumpdata', 'fixtures', format='xml', use_natural_keys=True) -<?xml version="1.0" encoding="utf-8"?> -<django-objects version="1.0"><object pk="1" model="fixtures.category"><field type="CharField" name="title">News Stories</field><field type="TextField" name="description">Latest news stories</field></object><object pk="5" model="fixtures.article"><field type="CharField" name="headline">XML identified as leading cause of cancer</field><field type="DateTimeField" name="pub_date">2006-06-16 16:00:00</field></object><object pk="4" model="fixtures.article"><field type="CharField" name="headline">Django conquers world!</field><field type="DateTimeField" name="pub_date">2006-06-16 15:00:00</field></object><object pk="3" model="fixtures.article"><field type="CharField" name="headline">Copyright is fine the way it is</field><field type="DateTimeField" name="pub_date">2006-06-16 14:00:00</field></object><object pk="2" model="fixtures.article"><field type="CharField" name="headline">Poker on TV is great!</field><field type="DateTimeField" name="pub_date">2006-06-16 11:00:00</field></object><object pk="1" model="fixtures.article"><field type="CharField" name="headline">Python program becomes self aware</field><field type="DateTimeField" name="pub_date">2006-06-16 11:00:00</field></object><object pk="1" model="fixtures.tag"><field type="CharField" name="name">copyright</field><field to="contenttypes.contenttype" name="tagged_type" rel="ManyToOneRel"><natural>fixtures</natural><natural>article</natural></field><field type="PositiveIntegerField" name="tagged_id">3</field></object><object pk="2" model="fixtures.tag"><field type="CharField" name="name">legal</field><field to="contenttypes.contenttype" name="tagged_type" rel="ManyToOneRel"><natural>fixtures</natural><natural>article</natural></field><field type="PositiveIntegerField" name="tagged_id">3</field></object><object pk="3" model="fixtures.tag"><field type="CharField" name="name">django</field><field to="contenttypes.contenttype" name="tagged_type" rel="ManyToOneRel"><natural>fixtures</natural><natural>article</natural></field><field type="PositiveIntegerField" name="tagged_id">4</field></object><object pk="4" model="fixtures.tag"><field type="CharField" name="name">world domination</field><field to="contenttypes.contenttype" name="tagged_type" rel="ManyToOneRel"><natural>fixtures</natural><natural>article</natural></field><field type="PositiveIntegerField" name="tagged_id">4</field></object><object pk="3" model="fixtures.person"><field type="CharField" name="name">Artist formerly known as "Prince"</field></object><object pk="1" model="fixtures.person"><field type="CharField" name="name">Django Reinhardt</field></object><object pk="2" model="fixtures.person"><field type="CharField" name="name">Stephane Grappelli</field></object><object pk="1" model="fixtures.visa"><field to="fixtures.person" name="person" rel="ManyToOneRel"><natural>Django Reinhardt</natural></field><field to="auth.permission" name="permissions" rel="ManyToManyRel"><object><natural>add_user</natural><natural>auth</natural><natural>user</natural></object><object><natural>change_user</natural><natural>auth</natural><natural>user</natural></object><object><natural>delete_user</natural><natural>auth</natural><natural>user</natural></object></field></object><object pk="2" model="fixtures.visa"><field to="fixtures.person" name="person" rel="ManyToOneRel"><natural>Stephane Grappelli</natural></field><field to="auth.permission" name="permissions" rel="ManyToManyRel"><object><natural>add_user</natural><natural>auth</natural><natural>user</natural></object><object><natural>delete_user</natural><natural>auth</natural><natural>user</natural></object></field></object><object pk="3" model="fixtures.visa"><field to="fixtures.person" name="person" rel="ManyToOneRel"><natural>Artist formerly known as "Prince"</natural></field><field to="auth.permission" name="permissions" rel="ManyToManyRel"><object><natural>change_user</natural><natural>auth</natural><natural>user</natural></object></field></object><object pk="1" model="fixtures.book"><field type="CharField" name="name">Music for all ages</field><field to="fixtures.person" name="authors" rel="ManyToManyRel"><object><natural>Artist formerly known as "Prince"</natural></object><object><natural>Django Reinhardt</natural></object></field></object></django-objects> - -"""} - -# Database flushing does not work on MySQL with the default storage engine -# because it requires transaction support. -if settings.DATABASES[DEFAULT_DB_ALIAS]['ENGINE'] != 'django.db.backends.mysql': - __test__['API_TESTS'] += \ -""" -# Reset the database representation of this app. This will delete all data. ->>> management.call_command('flush', verbosity=0, interactive=False) ->>> Article.objects.all() -[<Article: Python program becomes self aware>] - -# Load fixture 1 again, using format discovery ->>> management.call_command('loaddata', 'fixture1', verbosity=0) ->>> Article.objects.all() -[<Article: Time to reform copyright>, <Article: Poker has no place on ESPN>, <Article: Python program becomes self aware>] - -# Try to load fixture 2 using format discovery; this will fail -# because there are two fixture2's in the fixtures directory ->>> management.call_command('loaddata', 'fixture2', verbosity=0) # doctest: +ELLIPSIS -Multiple fixtures named 'fixture2' in '...fixtures'. Aborting. - -# object list is unaffected ->>> Article.objects.all() -[<Article: Time to reform copyright>, <Article: Poker has no place on ESPN>, <Article: Python program becomes self aware>] - -# Dump the current contents of the database as a JSON fixture ->>> management.call_command('dumpdata', 'fixtures', format='json') -[{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": "News Stories"}}, {"pk": 3, "model": "fixtures.article", "fields": {"headline": "Time to reform copyright", "pub_date": "2006-06-16 13:00:00"}}, {"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", "pub_date": "2006-06-16 12:00:00"}}, {"pk": 1, "model": "fixtures.article", "fields": {"headline": "Python program becomes self aware", "pub_date": "2006-06-16 11:00:00"}}] - -# Load fixture 4 (compressed), using format discovery ->>> management.call_command('loaddata', 'fixture4', verbosity=0) ->>> Article.objects.all() -[<Article: Django pets kitten>, <Article: Time to reform copyright>, <Article: Poker has no place on ESPN>, <Article: Python program becomes self aware>] - ->>> management.call_command('flush', verbosity=0, interactive=False) - -# Load fixture 4 (compressed), using format specification ->>> management.call_command('loaddata', 'fixture4.json', verbosity=0) ->>> Article.objects.all() -[<Article: Django pets kitten>, <Article: Python program becomes self aware>] - ->>> management.call_command('flush', verbosity=0, interactive=False) - -# Load fixture 5 (compressed), using format *and* compression specification ->>> management.call_command('loaddata', 'fixture5.json.zip', verbosity=0) ->>> Article.objects.all() -[<Article: WoW subscribers now outnumber readers>, <Article: Python program becomes self aware>] - ->>> management.call_command('flush', verbosity=0, interactive=False) - -# Load fixture 5 (compressed), only compression specification ->>> management.call_command('loaddata', 'fixture5.zip', verbosity=0) ->>> Article.objects.all() -[<Article: WoW subscribers now outnumber readers>, <Article: Python program becomes self aware>] - ->>> management.call_command('flush', verbosity=0, interactive=False) - -# Try to load fixture 5 using format and compression discovery; this will fail -# because there are two fixture5's in the fixtures directory ->>> management.call_command('loaddata', 'fixture5', verbosity=0) # doctest: +ELLIPSIS -Multiple fixtures named 'fixture5' in '...fixtures'. Aborting. - ->>> management.call_command('flush', verbosity=0, interactive=False) - -# Load db fixtures 1 and 2. These will load using the 'default' database identifier implicitly ->>> management.call_command('loaddata', 'db_fixture_1', verbosity=0) ->>> management.call_command('loaddata', 'db_fixture_2', verbosity=0) ->>> Article.objects.all() -[<Article: Who needs more than one database?>, <Article: Who needs to use compressed data?>, <Article: Python program becomes self aware>] - ->>> management.call_command('flush', verbosity=0, interactive=False) - -# Load db fixtures 1 and 2. These will load using the 'default' database identifier explicitly ->>> management.call_command('loaddata', 'db_fixture_1', verbosity=0, using='default') ->>> management.call_command('loaddata', 'db_fixture_2', verbosity=0, using='default') ->>> Article.objects.all() -[<Article: Who needs more than one database?>, <Article: Who needs to use compressed data?>, <Article: Python program becomes self aware>] - ->>> management.call_command('flush', verbosity=0, interactive=False) - -# Try to load db fixture 3. This won't load because the database identifier doesn't match ->>> management.call_command('loaddata', 'db_fixture_3', verbosity=0) ->>> Article.objects.all() -[<Article: Python program becomes self aware>] - ->>> management.call_command('loaddata', 'db_fixture_3', verbosity=0, using='default') ->>> Article.objects.all() -[<Article: Python program becomes self aware>] - ->>> management.call_command('flush', verbosity=0, interactive=False) - -# Load back in fixture 1, we need the articles from it ->>> management.call_command('loaddata', 'fixture1', verbosity=0) - -# Try to load fixture 6 using format discovery ->>> management.call_command('loaddata', 'fixture6', verbosity=0) ->>> Tag.objects.all() -[<Tag: <Article: Time to reform copyright> tagged "copyright">, <Tag: <Article: Time to reform copyright> tagged "law">] - -# Dump the current contents of the database as a JSON fixture ->>> management.call_command('dumpdata', 'fixtures', format='json', use_natural_keys=True) -[{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": "News Stories"}}, {"pk": 3, "model": "fixtures.article", "fields": {"headline": "Time to reform copyright", "pub_date": "2006-06-16 13:00:00"}}, {"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", "pub_date": "2006-06-16 12:00:00"}}, {"pk": 1, "model": "fixtures.article", "fields": {"headline": "Python program becomes self aware", "pub_date": "2006-06-16 11:00:00"}}, {"pk": 1, "model": "fixtures.tag", "fields": {"tagged_type": ["fixtures", "article"], "name": "copyright", "tagged_id": 3}}, {"pk": 2, "model": "fixtures.tag", "fields": {"tagged_type": ["fixtures", "article"], "name": "law", "tagged_id": 3}}, {"pk": 1, "model": "fixtures.person", "fields": {"name": "Django Reinhardt"}}, {"pk": 3, "model": "fixtures.person", "fields": {"name": "Prince"}}, {"pk": 2, "model": "fixtures.person", "fields": {"name": "Stephane Grappelli"}}] - -# Dump the current contents of the database as an XML fixture ->>> management.call_command('dumpdata', 'fixtures', format='xml', use_natural_keys=True) -<?xml version="1.0" encoding="utf-8"?> -<django-objects version="1.0"><object pk="1" model="fixtures.category"><field type="CharField" name="title">News Stories</field><field type="TextField" name="description">Latest news stories</field></object><object pk="3" model="fixtures.article"><field type="CharField" name="headline">Time to reform copyright</field><field type="DateTimeField" name="pub_date">2006-06-16 13:00:00</field></object><object pk="2" model="fixtures.article"><field type="CharField" name="headline">Poker has no place on ESPN</field><field type="DateTimeField" name="pub_date">2006-06-16 12:00:00</field></object><object pk="1" model="fixtures.article"><field type="CharField" name="headline">Python program becomes self aware</field><field type="DateTimeField" name="pub_date">2006-06-16 11:00:00</field></object><object pk="1" model="fixtures.tag"><field type="CharField" name="name">copyright</field><field to="contenttypes.contenttype" name="tagged_type" rel="ManyToOneRel"><natural>fixtures</natural><natural>article</natural></field><field type="PositiveIntegerField" name="tagged_id">3</field></object><object pk="2" model="fixtures.tag"><field type="CharField" name="name">law</field><field to="contenttypes.contenttype" name="tagged_type" rel="ManyToOneRel"><natural>fixtures</natural><natural>article</natural></field><field type="PositiveIntegerField" name="tagged_id">3</field></object><object pk="1" model="fixtures.person"><field type="CharField" name="name">Django Reinhardt</field></object><object pk="3" model="fixtures.person"><field type="CharField" name="name">Prince</field></object><object pk="2" model="fixtures.person"><field type="CharField" name="name">Stephane Grappelli</field></object></django-objects> - -""" - -from django.test import TestCase - -class SampleTestCase(TestCase): - fixtures = ['fixture1.json', 'fixture2.json'] - - def testClassFixtures(self): - "Check that test case has installed 4 fixture objects" - self.assertEqual(Article.objects.count(), 4) - self.assertEquals(str(Article.objects.all()), "[<Article: Django conquers world!>, <Article: Copyright is fine the way it is>, <Article: Poker has no place on ESPN>, <Article: Python program becomes self aware>]") diff --git a/tests/modeltests/fixtures/tests.py b/tests/modeltests/fixtures/tests.py new file mode 100644 index 0000000000..4facc6dee9 --- /dev/null +++ b/tests/modeltests/fixtures/tests.py @@ -0,0 +1,277 @@ +import StringIO +import sys + +from django.test import TestCase, TransactionTestCase +from django.conf import settings +from django.core import management +from django.db import DEFAULT_DB_ALIAS + +from models import Article, Blog, Book, Category, Person, Tag, Visa + +class TestCaseFixtureLoadingTests(TestCase): + fixtures = ['fixture1.json', 'fixture2.json'] + + def testClassFixtures(self): + "Check that test case has installed 4 fixture objects" + self.assertEqual(Article.objects.count(), 4) + self.assertQuerysetEqual(Article.objects.all(), [ + '<Article: Django conquers world!>', + '<Article: Copyright is fine the way it is>', + '<Article: Poker has no place on ESPN>', + '<Article: Python program becomes self aware>' + ]) + +class FixtureLoadingTests(TestCase): + + def _dumpdata_assert(self, args, output, format='json', natural_keys=False): + new_io = StringIO.StringIO() + management.call_command('dumpdata', *args, **{'format':format, 'stdout':new_io, 'use_natural_keys':natural_keys}) + command_output = new_io.getvalue().strip() + self.assertEqual(command_output, output) + + def test_initial_data(self): + # Syncdb introduces 1 initial data object from initial_data.json. + self.assertQuerysetEqual(Article.objects.all(), [ + '<Article: Python program becomes self aware>' + ]) + + def test_loading_and_dumping(self): + new_io = StringIO.StringIO() + + # Load fixture 1. Single JSON file, with two objects. + management.call_command('loaddata', 'fixture1.json', verbosity=0, commit=False) + self.assertQuerysetEqual(Article.objects.all(), [ + '<Article: Time to reform copyright>', + '<Article: Poker has no place on ESPN>', + '<Article: Python program becomes self aware>' + ]) + + # Dump the current contents of the database as a JSON fixture + self._dumpdata_assert(['fixtures'], '[{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": "News Stories"}}, {"pk": 3, "model": "fixtures.article", "fields": {"headline": "Time to reform copyright", "pub_date": "2006-06-16 13:00:00"}}, {"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", "pub_date": "2006-06-16 12:00:00"}}, {"pk": 1, "model": "fixtures.article", "fields": {"headline": "Python program becomes self aware", "pub_date": "2006-06-16 11:00:00"}}]') + + # Try just dumping the contents of fixtures.Category + self._dumpdata_assert(['fixtures.Category'], '[{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": "News Stories"}}]') + + # ...and just fixtures.Article + self._dumpdata_assert(['fixtures.Article'], '[{"pk": 3, "model": "fixtures.article", "fields": {"headline": "Time to reform copyright", "pub_date": "2006-06-16 13:00:00"}}, {"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", "pub_date": "2006-06-16 12:00:00"}}, {"pk": 1, "model": "fixtures.article", "fields": {"headline": "Python program becomes self aware", "pub_date": "2006-06-16 11:00:00"}}]') + + # ...and both + self._dumpdata_assert(['fixtures.Category', 'fixtures.Article'], '[{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": "News Stories"}}, {"pk": 3, "model": "fixtures.article", "fields": {"headline": "Time to reform copyright", "pub_date": "2006-06-16 13:00:00"}}, {"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", "pub_date": "2006-06-16 12:00:00"}}, {"pk": 1, "model": "fixtures.article", "fields": {"headline": "Python program becomes self aware", "pub_date": "2006-06-16 11:00:00"}}]') + + # Specify a specific model twice + self._dumpdata_assert(['fixtures.Article', 'fixtures.Article'], '[{"pk": 3, "model": "fixtures.article", "fields": {"headline": "Time to reform copyright", "pub_date": "2006-06-16 13:00:00"}}, {"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", "pub_date": "2006-06-16 12:00:00"}}, {"pk": 1, "model": "fixtures.article", "fields": {"headline": "Python program becomes self aware", "pub_date": "2006-06-16 11:00:00"}}]') + + # Specify a dump that specifies Article both explicitly and implicitly + self._dumpdata_assert(['fixtures.Article', 'fixtures'], '[{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": "News Stories"}}, {"pk": 3, "model": "fixtures.article", "fields": {"headline": "Time to reform copyright", "pub_date": "2006-06-16 13:00:00"}}, {"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", "pub_date": "2006-06-16 12:00:00"}}, {"pk": 1, "model": "fixtures.article", "fields": {"headline": "Python program becomes self aware", "pub_date": "2006-06-16 11:00:00"}}]') + + # Same again, but specify in the reverse order + self._dumpdata_assert(['fixtures'], '[{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": "News Stories"}}, {"pk": 3, "model": "fixtures.article", "fields": {"headline": "Time to reform copyright", "pub_date": "2006-06-16 13:00:00"}}, {"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", "pub_date": "2006-06-16 12:00:00"}}, {"pk": 1, "model": "fixtures.article", "fields": {"headline": "Python program becomes self aware", "pub_date": "2006-06-16 11:00:00"}}]') + + # Specify one model from one application, and an entire other application. + self._dumpdata_assert(['fixtures.Category', 'sites'], '[{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": "News Stories"}}, {"pk": 1, "model": "sites.site", "fields": {"domain": "example.com", "name": "example.com"}}]') + + # Load fixture 2. JSON file imported by default. Overwrites some existing objects + management.call_command('loaddata', 'fixture2.json', verbosity=0, commit=False) + self.assertQuerysetEqual(Article.objects.all(), [ + '<Article: Django conquers world!>', + '<Article: Copyright is fine the way it is>', + '<Article: Poker has no place on ESPN>', + '<Article: Python program becomes self aware>' + ]) + + # Load fixture 3, XML format. + management.call_command('loaddata', 'fixture3.xml', verbosity=0, commit=False) + self.assertQuerysetEqual(Article.objects.all(), [ + '<Article: XML identified as leading cause of cancer>', + '<Article: Django conquers world!>', + '<Article: Copyright is fine the way it is>', + '<Article: Poker on TV is great!>', + '<Article: Python program becomes self aware>' + ]) + + # Load fixture 6, JSON file with dynamic ContentType fields. Testing ManyToOne. + management.call_command('loaddata', 'fixture6.json', verbosity=0, commit=False) + self.assertQuerysetEqual(Tag.objects.all(), [ + '<Tag: <Article: Copyright is fine the way it is> tagged "copyright">', + '<Tag: <Article: Copyright is fine the way it is> tagged "law">' + ]) + + # Load fixture 7, XML file with dynamic ContentType fields. Testing ManyToOne. + management.call_command('loaddata', 'fixture7.xml', verbosity=0, commit=False) + self.assertQuerysetEqual(Tag.objects.all(), [ + '<Tag: <Article: Copyright is fine the way it is> tagged "copyright">', + '<Tag: <Article: Copyright is fine the way it is> tagged "legal">', + '<Tag: <Article: Django conquers world!> tagged "django">', + '<Tag: <Article: Django conquers world!> tagged "world domination">' + ]) + + # Load fixture 8, JSON file with dynamic Permission fields. Testing ManyToMany. + management.call_command('loaddata', 'fixture8.json', verbosity=0, commit=False) + self.assertQuerysetEqual(Visa.objects.all(), [ + '<Visa: Django Reinhardt Can add user, Can change user, Can delete user>', + '<Visa: Stephane Grappelli Can add user>', + '<Visa: Prince >' + ]) + + # Load fixture 9, XML file with dynamic Permission fields. Testing ManyToMany. + management.call_command('loaddata', 'fixture9.xml', verbosity=0, commit=False) + self.assertQuerysetEqual(Visa.objects.all(), [ + '<Visa: Django Reinhardt Can add user, Can change user, Can delete user>', + '<Visa: Stephane Grappelli Can add user, Can delete user>', + '<Visa: Artist formerly known as "Prince" Can change user>' + ]) + + self.assertQuerysetEqual(Book.objects.all(), [ + '<Book: Music for all ages by Artist formerly known as "Prince" and Django Reinhardt>' + ]) + + # Load a fixture that doesn't exist + management.call_command('loaddata', 'unknown.json', verbosity=0, commit=False) + + # object list is unaffected + self.assertQuerysetEqual(Article.objects.all(), [ + '<Article: XML identified as leading cause of cancer>', + '<Article: Django conquers world!>', + '<Article: Copyright is fine the way it is>', + '<Article: Poker on TV is great!>', + '<Article: Python program becomes self aware>' + ]) + + # By default, you get raw keys on dumpdata + self._dumpdata_assert(['fixtures.book'], '[{"pk": 1, "model": "fixtures.book", "fields": {"name": "Music for all ages", "authors": [3, 1]}}]') + + # But you can get natural keys if you ask for them and they are available + self._dumpdata_assert(['fixtures.book'], '[{"pk": 1, "model": "fixtures.book", "fields": {"name": "Music for all ages", "authors": [["Artist formerly known as \\"Prince\\""], ["Django Reinhardt"]]}}]', natural_keys=True) + + # Dump the current contents of the database as a JSON fixture + self._dumpdata_assert(['fixtures'], '[{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": "News Stories"}}, {"pk": 5, "model": "fixtures.article", "fields": {"headline": "XML identified as leading cause of cancer", "pub_date": "2006-06-16 16:00:00"}}, {"pk": 4, "model": "fixtures.article", "fields": {"headline": "Django conquers world!", "pub_date": "2006-06-16 15:00:00"}}, {"pk": 3, "model": "fixtures.article", "fields": {"headline": "Copyright is fine the way it is", "pub_date": "2006-06-16 14:00:00"}}, {"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker on TV is great!", "pub_date": "2006-06-16 11:00:00"}}, {"pk": 1, "model": "fixtures.article", "fields": {"headline": "Python program becomes self aware", "pub_date": "2006-06-16 11:00:00"}}, {"pk": 1, "model": "fixtures.tag", "fields": {"tagged_type": ["fixtures", "article"], "name": "copyright", "tagged_id": 3}}, {"pk": 2, "model": "fixtures.tag", "fields": {"tagged_type": ["fixtures", "article"], "name": "legal", "tagged_id": 3}}, {"pk": 3, "model": "fixtures.tag", "fields": {"tagged_type": ["fixtures", "article"], "name": "django", "tagged_id": 4}}, {"pk": 4, "model": "fixtures.tag", "fields": {"tagged_type": ["fixtures", "article"], "name": "world domination", "tagged_id": 4}}, {"pk": 3, "model": "fixtures.person", "fields": {"name": "Artist formerly known as \\"Prince\\""}}, {"pk": 1, "model": "fixtures.person", "fields": {"name": "Django Reinhardt"}}, {"pk": 2, "model": "fixtures.person", "fields": {"name": "Stephane Grappelli"}}, {"pk": 1, "model": "fixtures.visa", "fields": {"person": ["Django Reinhardt"], "permissions": [["add_user", "auth", "user"], ["change_user", "auth", "user"], ["delete_user", "auth", "user"]]}}, {"pk": 2, "model": "fixtures.visa", "fields": {"person": ["Stephane Grappelli"], "permissions": [["add_user", "auth", "user"], ["delete_user", "auth", "user"]]}}, {"pk": 3, "model": "fixtures.visa", "fields": {"person": ["Artist formerly known as \\"Prince\\""], "permissions": [["change_user", "auth", "user"]]}}, {"pk": 1, "model": "fixtures.book", "fields": {"name": "Music for all ages", "authors": [["Artist formerly known as \\"Prince\\""], ["Django Reinhardt"]]}}]', natural_keys=True) + + # Dump the current contents of the database as an XML fixture + self._dumpdata_assert(['fixtures'], """<?xml version="1.0" encoding="utf-8"?> +<django-objects version="1.0"><object pk="1" model="fixtures.category"><field type="CharField" name="title">News Stories</field><field type="TextField" name="description">Latest news stories</field></object><object pk="5" model="fixtures.article"><field type="CharField" name="headline">XML identified as leading cause of cancer</field><field type="DateTimeField" name="pub_date">2006-06-16 16:00:00</field></object><object pk="4" model="fixtures.article"><field type="CharField" name="headline">Django conquers world!</field><field type="DateTimeField" name="pub_date">2006-06-16 15:00:00</field></object><object pk="3" model="fixtures.article"><field type="CharField" name="headline">Copyright is fine the way it is</field><field type="DateTimeField" name="pub_date">2006-06-16 14:00:00</field></object><object pk="2" model="fixtures.article"><field type="CharField" name="headline">Poker on TV is great!</field><field type="DateTimeField" name="pub_date">2006-06-16 11:00:00</field></object><object pk="1" model="fixtures.article"><field type="CharField" name="headline">Python program becomes self aware</field><field type="DateTimeField" name="pub_date">2006-06-16 11:00:00</field></object><object pk="1" model="fixtures.tag"><field type="CharField" name="name">copyright</field><field to="contenttypes.contenttype" name="tagged_type" rel="ManyToOneRel"><natural>fixtures</natural><natural>article</natural></field><field type="PositiveIntegerField" name="tagged_id">3</field></object><object pk="2" model="fixtures.tag"><field type="CharField" name="name">legal</field><field to="contenttypes.contenttype" name="tagged_type" rel="ManyToOneRel"><natural>fixtures</natural><natural>article</natural></field><field type="PositiveIntegerField" name="tagged_id">3</field></object><object pk="3" model="fixtures.tag"><field type="CharField" name="name">django</field><field to="contenttypes.contenttype" name="tagged_type" rel="ManyToOneRel"><natural>fixtures</natural><natural>article</natural></field><field type="PositiveIntegerField" name="tagged_id">4</field></object><object pk="4" model="fixtures.tag"><field type="CharField" name="name">world domination</field><field to="contenttypes.contenttype" name="tagged_type" rel="ManyToOneRel"><natural>fixtures</natural><natural>article</natural></field><field type="PositiveIntegerField" name="tagged_id">4</field></object><object pk="3" model="fixtures.person"><field type="CharField" name="name">Artist formerly known as "Prince"</field></object><object pk="1" model="fixtures.person"><field type="CharField" name="name">Django Reinhardt</field></object><object pk="2" model="fixtures.person"><field type="CharField" name="name">Stephane Grappelli</field></object><object pk="1" model="fixtures.visa"><field to="fixtures.person" name="person" rel="ManyToOneRel"><natural>Django Reinhardt</natural></field><field to="auth.permission" name="permissions" rel="ManyToManyRel"><object><natural>add_user</natural><natural>auth</natural><natural>user</natural></object><object><natural>change_user</natural><natural>auth</natural><natural>user</natural></object><object><natural>delete_user</natural><natural>auth</natural><natural>user</natural></object></field></object><object pk="2" model="fixtures.visa"><field to="fixtures.person" name="person" rel="ManyToOneRel"><natural>Stephane Grappelli</natural></field><field to="auth.permission" name="permissions" rel="ManyToManyRel"><object><natural>add_user</natural><natural>auth</natural><natural>user</natural></object><object><natural>delete_user</natural><natural>auth</natural><natural>user</natural></object></field></object><object pk="3" model="fixtures.visa"><field to="fixtures.person" name="person" rel="ManyToOneRel"><natural>Artist formerly known as "Prince"</natural></field><field to="auth.permission" name="permissions" rel="ManyToManyRel"><object><natural>change_user</natural><natural>auth</natural><natural>user</natural></object></field></object><object pk="1" model="fixtures.book"><field type="CharField" name="name">Music for all ages</field><field to="fixtures.person" name="authors" rel="ManyToManyRel"><object><natural>Artist formerly known as "Prince"</natural></object><object><natural>Django Reinhardt</natural></object></field></object></django-objects>""", format='xml', natural_keys=True) + + def test_compress_format_loading(self): + # Load fixture 4 (compressed), using format specification + management.call_command('loaddata', 'fixture4.json', verbosity=0, commit=False) + self.assertQuerysetEqual(Article.objects.all(), [ + '<Article: Django pets kitten>', + '<Article: Python program becomes self aware>' + ]) + + def test_compressed_specified_loading(self): + # Load fixture 5 (compressed), using format *and* compression specification + management.call_command('loaddata', 'fixture5.json.zip', verbosity=0, commit=False) + self.assertQuerysetEqual(Article.objects.all(), [ + '<Article: WoW subscribers now outnumber readers>', + '<Article: Python program becomes self aware>' + ]) + + def test_compressed_loading(self): + # Load fixture 5 (compressed), only compression specification + management.call_command('loaddata', 'fixture5.zip', verbosity=0, commit=False) + self.assertQuerysetEqual(Article.objects.all(), [ + '<Article: WoW subscribers now outnumber readers>', + '<Article: Python program becomes self aware>' + ]) + + def test_ambiguous_compressed_fixture(self): + # The name "fixture5" is ambigous, so loading it will raise an error + new_io = StringIO.StringIO() + management.call_command('loaddata', 'fixture5', verbosity=0, stderr=new_io, commit=False) + output = new_io.getvalue().strip().split('\n') + self.assertEqual(len(output), 1) + self.assertTrue(output[0].startswith("Multiple fixtures named 'fixture5'")) + + def test_db_loading(self): + # Load db fixtures 1 and 2. These will load using the 'default' database identifier implicitly + management.call_command('loaddata', 'db_fixture_1', verbosity=0, commit=False) + management.call_command('loaddata', 'db_fixture_2', verbosity=0, commit=False) + self.assertQuerysetEqual(Article.objects.all(), [ + '<Article: Who needs more than one database?>', + '<Article: Who needs to use compressed data?>', + '<Article: Python program becomes self aware>' + ]) + + def test_loading_using(self): + # Load db fixtures 1 and 2. These will load using the 'default' database identifier explicitly + management.call_command('loaddata', 'db_fixture_1', verbosity=0, using='default', commit=False) + management.call_command('loaddata', 'db_fixture_2', verbosity=0, using='default', commit=False) + self.assertQuerysetEqual(Article.objects.all(), [ + '<Article: Who needs more than one database?>', + '<Article: Who needs to use compressed data?>', + '<Article: Python program becomes self aware>' + ]) + + def test_unmatched_identifier_loading(self): + # Try to load db fixture 3. This won't load because the database identifier doesn't match + management.call_command('loaddata', 'db_fixture_3', verbosity=0, commit=False) + self.assertQuerysetEqual(Article.objects.all(), [ + '<Article: Python program becomes self aware>' + ]) + + management.call_command('loaddata', 'db_fixture_3', verbosity=0, using='default', commit=False) + self.assertQuerysetEqual(Article.objects.all(), [ + '<Article: Python program becomes self aware>' + ]) + + def test_output_formats(self): + # Load back in fixture 1, we need the articles from it + management.call_command('loaddata', 'fixture1', verbosity=0, commit=False) + + # Try to load fixture 6 using format discovery + management.call_command('loaddata', 'fixture6', verbosity=0, commit=False) + self.assertQuerysetEqual(Tag.objects.all(), [ + '<Tag: <Article: Time to reform copyright> tagged "copyright">', + '<Tag: <Article: Time to reform copyright> tagged "law">' + ]) + + # Dump the current contents of the database as a JSON fixture + self._dumpdata_assert(['fixtures'], '[{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": "News Stories"}}, {"pk": 3, "model": "fixtures.article", "fields": {"headline": "Time to reform copyright", "pub_date": "2006-06-16 13:00:00"}}, {"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", "pub_date": "2006-06-16 12:00:00"}}, {"pk": 1, "model": "fixtures.article", "fields": {"headline": "Python program becomes self aware", "pub_date": "2006-06-16 11:00:00"}}, {"pk": 1, "model": "fixtures.tag", "fields": {"tagged_type": ["fixtures", "article"], "name": "copyright", "tagged_id": 3}}, {"pk": 2, "model": "fixtures.tag", "fields": {"tagged_type": ["fixtures", "article"], "name": "law", "tagged_id": 3}}, {"pk": 1, "model": "fixtures.person", "fields": {"name": "Django Reinhardt"}}, {"pk": 3, "model": "fixtures.person", "fields": {"name": "Prince"}}, {"pk": 2, "model": "fixtures.person", "fields": {"name": "Stephane Grappelli"}}]', natural_keys=True) + + # Dump the current contents of the database as an XML fixture + self._dumpdata_assert(['fixtures'], """<?xml version="1.0" encoding="utf-8"?> +<django-objects version="1.0"><object pk="1" model="fixtures.category"><field type="CharField" name="title">News Stories</field><field type="TextField" name="description">Latest news stories</field></object><object pk="3" model="fixtures.article"><field type="CharField" name="headline">Time to reform copyright</field><field type="DateTimeField" name="pub_date">2006-06-16 13:00:00</field></object><object pk="2" model="fixtures.article"><field type="CharField" name="headline">Poker has no place on ESPN</field><field type="DateTimeField" name="pub_date">2006-06-16 12:00:00</field></object><object pk="1" model="fixtures.article"><field type="CharField" name="headline">Python program becomes self aware</field><field type="DateTimeField" name="pub_date">2006-06-16 11:00:00</field></object><object pk="1" model="fixtures.tag"><field type="CharField" name="name">copyright</field><field to="contenttypes.contenttype" name="tagged_type" rel="ManyToOneRel"><natural>fixtures</natural><natural>article</natural></field><field type="PositiveIntegerField" name="tagged_id">3</field></object><object pk="2" model="fixtures.tag"><field type="CharField" name="name">law</field><field to="contenttypes.contenttype" name="tagged_type" rel="ManyToOneRel"><natural>fixtures</natural><natural>article</natural></field><field type="PositiveIntegerField" name="tagged_id">3</field></object><object pk="1" model="fixtures.person"><field type="CharField" name="name">Django Reinhardt</field></object><object pk="3" model="fixtures.person"><field type="CharField" name="name">Prince</field></object><object pk="2" model="fixtures.person"><field type="CharField" name="name">Stephane Grappelli</field></object></django-objects>""", format='xml', natural_keys=True) + +if settings.DATABASES[DEFAULT_DB_ALIAS]['ENGINE'] != 'django.db.backends.mysql': + class FixtureTransactionTests(TransactionTestCase): + def _dumpdata_assert(self, args, output, format='json'): + new_io = StringIO.StringIO() + management.call_command('dumpdata', *args, **{'format':format, 'stdout':new_io}) + command_output = new_io.getvalue().strip() + self.assertEqual(command_output, output) + + def test_format_discovery(self): + # Load fixture 1 again, using format discovery + management.call_command('loaddata', 'fixture1', verbosity=0, commit=False) + self.assertQuerysetEqual(Article.objects.all(), [ + '<Article: Time to reform copyright>', + '<Article: Poker has no place on ESPN>', + '<Article: Python program becomes self aware>' + ]) + + # Try to load fixture 2 using format discovery; this will fail + # because there are two fixture2's in the fixtures directory + new_io = StringIO.StringIO() + management.call_command('loaddata', 'fixture2', verbosity=0, stderr=new_io) + output = new_io.getvalue().strip().split('\n') + self.assertEqual(len(output), 1) + self.assertTrue(output[0].startswith("Multiple fixtures named 'fixture2'")) + + # object list is unaffected + self.assertQuerysetEqual(Article.objects.all(), [ + '<Article: Time to reform copyright>', + '<Article: Poker has no place on ESPN>', + '<Article: Python program becomes self aware>' + ]) + + # Dump the current contents of the database as a JSON fixture + self._dumpdata_assert(['fixtures'], '[{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": "News Stories"}}, {"pk": 3, "model": "fixtures.article", "fields": {"headline": "Time to reform copyright", "pub_date": "2006-06-16 13:00:00"}}, {"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", "pub_date": "2006-06-16 12:00:00"}}, {"pk": 1, "model": "fixtures.article", "fields": {"headline": "Python program becomes self aware", "pub_date": "2006-06-16 11:00:00"}}]') + + # Load fixture 4 (compressed), using format discovery + management.call_command('loaddata', 'fixture4', verbosity=0, commit=False) + self.assertQuerysetEqual(Article.objects.all(), [ + '<Article: Django pets kitten>', + '<Article: Time to reform copyright>', + '<Article: Poker has no place on ESPN>', + '<Article: Python program becomes self aware>' + ]) diff --git a/tests/modeltests/proxy_model_inheritance/tests.py b/tests/modeltests/proxy_model_inheritance/tests.py index a07958a13b..d10d6a4ac1 100644 --- a/tests/modeltests/proxy_model_inheritance/tests.py +++ b/tests/modeltests/proxy_model_inheritance/tests.py @@ -23,9 +23,9 @@ class ProxyModelInheritanceTests(TransactionTestCase): settings.INSTALLED_APPS = ('app1', 'app2') map(load_app, settings.INSTALLED_APPS) call_command('syncdb', verbosity=0) + global ProxyModel, NiceModel from app1.models import ProxyModel from app2.models import NiceModel - global ProxyModel, NiceModel def tearDown(self): settings.INSTALLED_APPS = self.old_installed_apps 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/csrf_tests/tests.py b/tests/regressiontests/csrf_tests/tests.py index 0a24522d9c..f383978266 100644 --- a/tests/regressiontests/csrf_tests/tests.py +++ b/tests/regressiontests/csrf_tests/tests.py @@ -3,7 +3,7 @@ from django.test import TestCase from django.http import HttpRequest, HttpResponse from django.middleware.csrf import CsrfMiddleware, CsrfViewMiddleware -from django.views.decorators.csrf import csrf_exempt +from django.views.decorators.csrf import csrf_exempt, csrf_view_exempt from django.core.context_processors import csrf from django.contrib.sessions.middleware import SessionMiddleware from django.utils.importlib import import_module @@ -123,6 +123,23 @@ class CsrfMiddlewareTest(TestCase): # Check the Vary header got patched correctly self.assert_('Cookie' in resp2.get('Vary','')) + def test_process_response_for_exempt_view(self): + """ + Check that a view decorated with 'csrf_view_exempt' is still + post-processed to add the CSRF token. + """ + req = self._get_GET_no_csrf_cookie_request() + CsrfMiddleware().process_view(req, csrf_view_exempt(post_form_view), (), {}) + + resp = post_form_response() + resp_content = resp.content # needed because process_response modifies resp + resp2 = CsrfMiddleware().process_response(req, resp) + + csrf_cookie = resp2.cookies.get(settings.CSRF_COOKIE_NAME, False) + self.assertNotEqual(csrf_cookie, False) + self.assertNotEqual(resp_content, resp2.content) + self._check_token_present(resp2, csrf_cookie.value) + def test_process_response_no_csrf_cookie_view_only_get_token_used(self): """ When no prior CSRF cookie exists, check that the cookie is created, even @@ -279,6 +296,15 @@ class CsrfMiddlewareTest(TestCase): resp = token_view(req) self._check_token_present(resp) + def test_get_token_for_exempt_view(self): + """ + Check that get_token still works for a view decorated with 'csrf_view_exempt'. + """ + req = self._get_GET_csrf_cookie_request() + CsrfViewMiddleware().process_view(req, csrf_view_exempt(token_view), (), {}) + resp = token_view(req) + self._check_token_present(resp) + def test_token_node_with_new_csrf_cookie(self): """ Check that CsrfTokenNode works when a CSRF cookie is created by 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/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' """ |
