diff options
| author | Russell Keith-Magee <russell@keith-magee.com> | 2014-01-20 10:45:21 +0800 |
|---|---|---|
| committer | Russell Keith-Magee <russell@keith-magee.com> | 2014-01-20 10:45:21 +0800 |
| commit | d818e0c9b2b88276cc499974f9eee893170bf0a8 (patch) | |
| tree | 13ef631f7ba50bf81fa36f484abf925ba8172651 /tests/contenttypes_tests/tests.py | |
| parent | 6e7bd0b63bd01949ac4fd647f2597639bed0c3a2 (diff) | |
Fixed #16905 -- Added extensible checks (nee validation) framework
This is the result of Christopher Medrela's 2013 Summer of Code project.
Thanks also to Preston Holmes, Tim Graham, Anssi Kääriäinen, Florian
Apolloner, and Alex Gaynor for review notes along the way.
Also: Fixes #8579, fixes #3055, fixes #19844.
Diffstat (limited to 'tests/contenttypes_tests/tests.py')
| -rw-r--r-- | tests/contenttypes_tests/tests.py | 303 |
1 files changed, 301 insertions, 2 deletions
diff --git a/tests/contenttypes_tests/tests.py b/tests/contenttypes_tests/tests.py index 1f0af709cb..624e60d7a5 100644 --- a/tests/contenttypes_tests/tests.py +++ b/tests/contenttypes_tests/tests.py @@ -1,9 +1,14 @@ -from __future__ import unicode_literals +# -*- coding: utf-8 -*- +from __future__ import absolute_import, unicode_literals -from django.apps.registry import Apps +from django.apps.registry import Apps, apps +from django.contrib.contenttypes import generic from django.contrib.contenttypes.models import ContentType +from django.core import checks from django.db import models from django.test import TestCase +from django.test.utils import override_settings +from django.utils.encoding import force_str from .models import Author, Article @@ -67,3 +72,297 @@ class ContentTypesViewsTests(TestCase): self.assertEqual(ct.app_label, 'my_great_app') self.assertEqual(ct.model, 'modelcreatedonthefly') self.assertEqual(ct.name, 'a model created on the fly') + + +class IsolatedModelsTestCase(TestCase): + def setUp(self): + # The unmanaged models need to be removed after the test in order to + # prevent bad interactions with the flush operation in other tests. + self._old_models = apps.app_configs['contenttypes_tests'].models.copy() + + def tearDown(self): + apps.app_configs['contenttypes_tests'].models = self._old_models + apps.all_models['contenttypes_tests'] = self._old_models + apps.clear_cache() + + +class GenericForeignKeyTests(IsolatedModelsTestCase): + + def test_str(self): + class Model(models.Model): + field = generic.GenericForeignKey() + expected = "contenttypes_tests.Model.field" + actual = force_str(Model.field) + self.assertEqual(expected, actual) + + def test_missing_content_type_field(self): + class TaggedItem(models.Model): + # no content_type field + object_id = models.PositiveIntegerField() + content_object = generic.GenericForeignKey() + + errors = TaggedItem.content_object.check() + expected = [ + checks.Error( + 'The field refers to TaggedItem.content_type field which is missing.', + hint=None, + obj=TaggedItem.content_object, + id='contenttypes.E005', + ) + ] + self.assertEqual(errors, expected) + + def test_invalid_content_type_field(self): + class Model(models.Model): + content_type = models.IntegerField() # should be ForeignKey + object_id = models.PositiveIntegerField() + content_object = generic.GenericForeignKey( + 'content_type', 'object_id') + + errors = Model.content_object.check() + expected = [ + checks.Error( + ('"content_type" field is used by a GenericForeignKey ' + 'as content type field and therefore it must be ' + 'a ForeignKey.'), + hint=None, + obj=Model.content_object, + id='contenttypes.E006', + ) + ] + self.assertEqual(errors, expected) + + def test_content_type_field_pointing_to_wrong_model(self): + class Model(models.Model): + content_type = models.ForeignKey('self') # should point to ContentType + object_id = models.PositiveIntegerField() + content_object = generic.GenericForeignKey( + 'content_type', 'object_id') + + errors = Model.content_object.check() + expected = [ + checks.Error( + ('"content_type" field is used by a GenericForeignKey ' + 'as content type field and therefore it must be ' + 'a ForeignKey to ContentType.'), + hint=None, + obj=Model.content_object, + id='contenttypes.E007', + ) + ] + self.assertEqual(errors, expected) + + def test_missing_object_id_field(self): + class TaggedItem(models.Model): + content_type = models.ForeignKey(ContentType) + # missing object_id field + content_object = generic.GenericForeignKey() + + errors = TaggedItem.content_object.check() + expected = [ + checks.Error( + 'The field refers to "object_id" field which is missing.', + hint=None, + obj=TaggedItem.content_object, + id='contenttypes.E001', + ) + ] + self.assertEqual(errors, expected) + + def test_field_name_ending_with_underscore(self): + class Model(models.Model): + content_type = models.ForeignKey(ContentType) + object_id = models.PositiveIntegerField() + content_object_ = generic.GenericForeignKey( + 'content_type', 'object_id') + + errors = Model.content_object_.check() + expected = [ + checks.Error( + 'Field names must not end with underscores.', + hint=None, + obj=Model.content_object_, + id='contenttypes.E002', + ) + ] + self.assertEqual(errors, expected) + + def test_generic_foreign_key_checks_are_performed(self): + class MyGenericForeignKey(generic.GenericForeignKey): + def check(self, **kwargs): + return ['performed!'] + + class Model(models.Model): + content_object = MyGenericForeignKey() + + errors = checks.run_checks() + self.assertEqual(errors, ['performed!']) + + +class GenericRelationshipTests(IsolatedModelsTestCase): + + def test_valid_generic_relationship(self): + class TaggedItem(models.Model): + content_type = models.ForeignKey(ContentType) + object_id = models.PositiveIntegerField() + content_object = generic.GenericForeignKey() + + class Bookmark(models.Model): + tags = generic.GenericRelation('TaggedItem') + + errors = Bookmark.tags.field.check() + self.assertEqual(errors, []) + + def test_valid_generic_relationship_with_explicit_fields(self): + class TaggedItem(models.Model): + custom_content_type = models.ForeignKey(ContentType) + custom_object_id = models.PositiveIntegerField() + content_object = generic.GenericForeignKey( + 'custom_content_type', 'custom_object_id') + + class Bookmark(models.Model): + tags = generic.GenericRelation('TaggedItem', + content_type_field='custom_content_type', + object_id_field='custom_object_id') + + errors = Bookmark.tags.field.check() + self.assertEqual(errors, []) + + def test_pointing_to_missing_model(self): + class Model(models.Model): + rel = generic.GenericRelation('MissingModel') + + errors = Model.rel.field.check() + expected = [ + checks.Error( + ('The field has a relation with model MissingModel, ' + 'which has either not been installed or is abstract.'), + hint=('Ensure that you did not misspell the model name and ' + 'the model is not abstract. Does your INSTALLED_APPS ' + 'setting contain the app where MissingModel is defined?'), + obj=Model.rel.field, + id='E030', + ) + ] + self.assertEqual(errors, expected) + + def test_valid_self_referential_generic_relationship(self): + class Model(models.Model): + rel = generic.GenericRelation('Model') + content_type = models.ForeignKey(ContentType) + object_id = models.PositiveIntegerField() + content_object = generic.GenericForeignKey( + 'content_type', 'object_id') + + errors = Model.rel.field.check() + self.assertEqual(errors, []) + + def test_missing_content_type_field(self): + class TaggedItem(models.Model): + # no content_type field + object_id = models.PositiveIntegerField() + content_object = generic.GenericForeignKey() + + class Bookmark(models.Model): + tags = generic.GenericRelation('TaggedItem') + + errors = Bookmark.tags.field.check() + expected = [ + checks.Error( + 'The field refers to TaggedItem.content_type field which is missing.', + hint=None, + obj=Bookmark.tags.field, + id='contenttypes.E005', + ) + ] + self.assertEqual(errors, expected) + + def test_missing_object_id_field(self): + class TaggedItem(models.Model): + content_type = models.ForeignKey(ContentType) + # missing object_id field + content_object = generic.GenericForeignKey() + + class Bookmark(models.Model): + tags = generic.GenericRelation('TaggedItem') + + errors = Bookmark.tags.field.check() + expected = [ + checks.Error( + 'The field refers to TaggedItem.object_id field which is missing.', + hint=None, + obj=Bookmark.tags.field, + id='contenttypes.E003', + ) + ] + self.assertEqual(errors, expected) + + def test_missing_generic_foreign_key(self): + class TaggedItem(models.Model): + content_type = models.ForeignKey(ContentType) + object_id = models.PositiveIntegerField() + + class Bookmark(models.Model): + tags = generic.GenericRelation('TaggedItem') + + errors = Bookmark.tags.field.check() + expected = [ + checks.Warning( + ('The field defines a generic relation with the model ' + 'contenttypes_tests.TaggedItem, but the model lacks ' + 'GenericForeignKey.'), + hint=None, + obj=Bookmark.tags.field, + id='contenttypes.E004', + ) + ] + self.assertEqual(errors, expected) + + @override_settings(TEST_SWAPPED_MODEL='contenttypes_tests.Replacement') + def test_pointing_to_swapped_model(self): + class Replacement(models.Model): + pass + + class SwappedModel(models.Model): + content_type = models.ForeignKey(ContentType) + object_id = models.PositiveIntegerField() + content_object = generic.GenericForeignKey() + + class Meta: + swappable = 'TEST_SWAPPED_MODEL' + + class Model(models.Model): + rel = generic.GenericRelation('SwappedModel') + + errors = Model.rel.field.check() + expected = [ + checks.Error( + ('The field defines a relation with the model ' + 'contenttypes_tests.SwappedModel, ' + 'which has been swapped out.'), + hint='Update the relation to point at settings.TEST_SWAPPED_MODEL', + obj=Model.rel.field, + id='E029', + ) + ] + self.assertEqual(errors, expected) + + def test_field_name_ending_with_underscore(self): + class TaggedItem(models.Model): + content_type = models.ForeignKey(ContentType) + object_id = models.PositiveIntegerField() + content_object = generic.GenericForeignKey() + + class InvalidBookmark(models.Model): + tags_ = generic.GenericRelation('TaggedItem') + + errors = InvalidBookmark.tags_.field.check() + expected = [ + checks.Error( + 'Field names must not end with underscores.', + hint=None, + obj=InvalidBookmark.tags_.field, + id='E001', + ) + ] + self.assertEqual(errors, expected) |
