aboutsummaryrefslogtreecommitdiffstats
path: root/rest_framework/tests
diff options
context:
space:
mode:
authorBen Konrath2012-11-01 14:06:56 +0100
committerBen Konrath2012-11-01 14:06:56 +0100
commit9c82f9717e58f1bb250d5fd4b27619dbcbbd1f21 (patch)
treee976854e6871a8b826e91d8eb16d9a139b90664f /rest_framework/tests
parentc24997df3b943e5d7a3b2e101508e4b79ee82dc4 (diff)
parent204db7bdaa59cd17f762d6cf0e6a8623c2cc9939 (diff)
downloaddjango-rest-framework-9c82f9717e58f1bb250d5fd4b27619dbcbbd1f21.tar.bz2
Merge branch 'master' into restframework2-filter
Diffstat (limited to 'rest_framework/tests')
-rw-r--r--rest_framework/tests/__init__.py13
-rw-r--r--rest_framework/tests/generics.py51
-rw-r--r--rest_framework/tests/htmlrenderer.py6
-rw-r--r--rest_framework/tests/hyperlinkedserializers.py44
-rw-r--r--rest_framework/tests/models.py37
-rw-r--r--rest_framework/tests/negotiation.py10
-rw-r--r--rest_framework/tests/request.py15
-rw-r--r--rest_framework/tests/serializer.py240
-rw-r--r--rest_framework/tests/tests.py13
-rw-r--r--rest_framework/tests/validators.py10
10 files changed, 403 insertions, 36 deletions
diff --git a/rest_framework/tests/__init__.py b/rest_framework/tests/__init__.py
index adeaf6da..e69de29b 100644
--- a/rest_framework/tests/__init__.py
+++ b/rest_framework/tests/__init__.py
@@ -1,13 +0,0 @@
-"""
-Force import of all modules in this package in order to get the standard test
-runner to pick up the tests. Yowzers.
-"""
-import os
-
-modules = [filename.rsplit('.', 1)[0]
- for filename in os.listdir(os.path.dirname(__file__))
- if filename.endswith('.py') and not filename.startswith('_')]
-__test__ = dict()
-
-for module in modules:
- exec("from rest_framework.tests.%s import *" % module)
diff --git a/rest_framework/tests/generics.py b/rest_framework/tests/generics.py
index f4263478..a8279ef2 100644
--- a/rest_framework/tests/generics.py
+++ b/rest_framework/tests/generics.py
@@ -2,7 +2,7 @@ from django.test import TestCase
from django.test.client import RequestFactory
from django.utils import simplejson as json
from rest_framework import generics, serializers, status
-from rest_framework.tests.models import BasicModel, Comment
+from rest_framework.tests.models import BasicModel, Comment, SlugBasedModel
factory = RequestFactory()
@@ -22,6 +22,22 @@ class InstanceView(generics.RetrieveUpdateDestroyAPIView):
model = BasicModel
+class SlugSerializer(serializers.ModelSerializer):
+ slug = serializers.Field() # read only
+
+ class Meta:
+ model = SlugBasedModel
+ exclude = ('id',)
+
+
+class SlugBasedInstanceView(InstanceView):
+ """
+ A model with a slug-field.
+ """
+ model = SlugBasedModel
+ serializer_class = SlugSerializer
+
+
class TestRootView(TestCase):
def setUp(self):
"""
@@ -129,6 +145,7 @@ class TestInstanceView(TestCase):
for obj in self.objects.all()
]
self.view = InstanceView.as_view()
+ self.slug_based_view = SlugBasedInstanceView.as_view()
def test_get_instance_view(self):
"""
@@ -198,7 +215,7 @@ class TestInstanceView(TestCase):
def test_put_cannot_set_id(self):
"""
- POST requests to create a new object should not be able to set the id.
+ PUT requests to create a new object should not be able to set the id.
"""
content = {'id': 999, 'text': 'foobar'}
request = factory.put('/1', json.dumps(content),
@@ -219,11 +236,39 @@ class TestInstanceView(TestCase):
request = factory.put('/1', json.dumps(content),
content_type='application/json')
response = self.view(request, pk=1).render()
- self.assertEquals(response.status_code, status.HTTP_200_OK)
+ self.assertEquals(response.status_code, status.HTTP_201_CREATED)
self.assertEquals(response.data, {'id': 1, 'text': 'foobar'})
updated = self.objects.get(id=1)
self.assertEquals(updated.text, 'foobar')
+ def test_put_as_create_on_id_based_url(self):
+ """
+ PUT requests to RetrieveUpdateDestroyAPIView should create an object
+ at the requested url if it doesn't exist.
+ """
+ content = {'text': 'foobar'}
+ # pk fields can not be created on demand, only the database can set th pk for a new object
+ request = factory.put('/5', json.dumps(content),
+ content_type='application/json')
+ response = self.view(request, pk=5).render()
+ self.assertEquals(response.status_code, status.HTTP_201_CREATED)
+ new_obj = self.objects.get(pk=5)
+ self.assertEquals(new_obj.text, 'foobar')
+
+ def test_put_as_create_on_slug_based_url(self):
+ """
+ PUT requests to RetrieveUpdateDestroyAPIView should create an object
+ at the requested url if possible, else return HTTP_403_FORBIDDEN error-response.
+ """
+ content = {'text': 'foobar'}
+ request = factory.put('/test_slug', json.dumps(content),
+ content_type='application/json')
+ response = self.slug_based_view(request, slug='test_slug').render()
+ self.assertEquals(response.status_code, status.HTTP_201_CREATED)
+ self.assertEquals(response.data, {'slug': 'test_slug', 'text': 'foobar'})
+ new_obj = SlugBasedModel.objects.get(slug='test_slug')
+ self.assertEquals(new_obj.text, 'foobar')
+
# Regression test for #285
diff --git a/rest_framework/tests/htmlrenderer.py b/rest_framework/tests/htmlrenderer.py
index da2f83c3..10d7e31d 100644
--- a/rest_framework/tests/htmlrenderer.py
+++ b/rest_framework/tests/htmlrenderer.py
@@ -3,12 +3,12 @@ from django.test import TestCase
from django.template import TemplateDoesNotExist, Template
import django.template.loader
from rest_framework.decorators import api_view, renderer_classes
-from rest_framework.renderers import HTMLRenderer
+from rest_framework.renderers import TemplateHTMLRenderer
from rest_framework.response import Response
@api_view(('GET',))
-@renderer_classes((HTMLRenderer,))
+@renderer_classes((TemplateHTMLRenderer,))
def example(request):
"""
A view that can returns an HTML representation.
@@ -22,7 +22,7 @@ urlpatterns = patterns('',
)
-class HTMLRendererTests(TestCase):
+class TemplateHTMLRendererTests(TestCase):
urls = 'rest_framework.tests.htmlrenderer'
def setUp(self):
diff --git a/rest_framework/tests/hyperlinkedserializers.py b/rest_framework/tests/hyperlinkedserializers.py
index 5532a8ee..92c3691e 100644
--- a/rest_framework/tests/hyperlinkedserializers.py
+++ b/rest_framework/tests/hyperlinkedserializers.py
@@ -2,11 +2,19 @@ from django.conf.urls.defaults import patterns, url
from django.test import TestCase
from django.test.client import RequestFactory
from rest_framework import generics, status, serializers
-from rest_framework.tests.models import Anchor, BasicModel, ManyToManyModel
+from rest_framework.tests.models import Anchor, BasicModel, ManyToManyModel, BlogPost, BlogPostComment
factory = RequestFactory()
+class BlogPostCommentSerializer(serializers.Serializer):
+ text = serializers.CharField()
+ blog_post_url = serializers.HyperlinkedRelatedField(source='blog_post', view_name='blogpost-detail', queryset=BlogPost.objects.all())
+
+ def restore_object(self, attrs, instance=None):
+ return BlogPostComment(**attrs)
+
+
class BasicList(generics.ListCreateAPIView):
model = BasicModel
model_serializer_class = serializers.HyperlinkedModelSerializer
@@ -32,12 +40,22 @@ class ManyToManyDetail(generics.RetrieveAPIView):
model_serializer_class = serializers.HyperlinkedModelSerializer
+class BlogPostCommentListCreate(generics.ListCreateAPIView):
+ model = BlogPostComment
+ model_serializer_class = BlogPostCommentSerializer
+
+
+class BlogPostDetail(generics.RetrieveAPIView):
+ model = BlogPost
+
urlpatterns = patterns('',
url(r'^basic/$', BasicList.as_view(), name='basicmodel-list'),
url(r'^basic/(?P<pk>\d+)/$', BasicDetail.as_view(), name='basicmodel-detail'),
url(r'^anchor/(?P<pk>\d+)/$', AnchorDetail.as_view(), name='anchor-detail'),
url(r'^manytomany/$', ManyToManyList.as_view(), name='manytomanymodel-list'),
url(r'^manytomany/(?P<pk>\d+)/$', ManyToManyDetail.as_view(), name='manytomanymodel-detail'),
+ url(r'^posts/(?P<pk>\d+)/$', BlogPostDetail.as_view(), name='blogpost-detail'),
+ url(r'^comments/$', BlogPostCommentListCreate.as_view(), name='blogpostcomment-list')
)
@@ -124,3 +142,27 @@ class TestManyToManyHyperlinkedView(TestCase):
response = self.detail_view(request, pk=1).render()
self.assertEquals(response.status_code, status.HTTP_200_OK)
self.assertEquals(response.data, self.data[0])
+
+
+class TestCreateWithForeignKeys(TestCase):
+ urls = 'rest_framework.tests.hyperlinkedserializers'
+
+ def setUp(self):
+ """
+ Create a blog post
+ """
+ self.post = BlogPost.objects.create(title="Test post")
+ self.create_view = BlogPostCommentListCreate.as_view()
+
+ def test_create_comment(self):
+
+ data = {
+ 'text': 'A test comment',
+ 'blog_post_url': 'http://testserver/posts/1/'
+ }
+
+ request = factory.post('/comments/', data=data)
+ response = self.create_view(request).render()
+ self.assertEqual(response.status_code, 201)
+ self.assertEqual(self.post.blogpostcomment_set.count(), 1)
+ self.assertEqual(self.post.blogpostcomment_set.all()[0].text, 'A test comment')
diff --git a/rest_framework/tests/models.py b/rest_framework/tests/models.py
index 780c9dba..9efedbc4 100644
--- a/rest_framework/tests/models.py
+++ b/rest_framework/tests/models.py
@@ -40,7 +40,7 @@ class RESTFrameworkModel(models.Model):
Base for test models that sets app_label, so they play nicely.
"""
class Meta:
- app_label = 'rest_framework'
+ app_label = 'tests'
abstract = True
@@ -52,6 +52,11 @@ class BasicModel(RESTFrameworkModel):
text = models.CharField(max_length=100)
+class SlugBasedModel(RESTFrameworkModel):
+ text = models.CharField(max_length=100)
+ slug = models.SlugField(max_length=32)
+
+
class DefaultValueModel(RESTFrameworkModel):
text = models.CharField(default='foobar', max_length=100)
@@ -63,6 +68,11 @@ class CallableDefaultValueModel(RESTFrameworkModel):
class ManyToManyModel(RESTFrameworkModel):
rel = models.ManyToManyField(Anchor)
+
+class ReadOnlyManyToManyModel(RESTFrameworkModel):
+ text = models.CharField(max_length=100, default='anchor')
+ rel = models.ManyToManyField(Anchor)
+
# Models to test generic relations
@@ -98,3 +108,28 @@ class Comment(RESTFrameworkModel):
email = models.EmailField()
content = models.CharField(max_length=200)
created = models.DateTimeField(auto_now_add=True)
+
+
+class ActionItem(RESTFrameworkModel):
+ title = models.CharField(max_length=200)
+ done = models.BooleanField(default=False)
+
+
+# Models for reverse relations
+class BlogPost(RESTFrameworkModel):
+ title = models.CharField(max_length=100)
+
+
+class BlogPostComment(RESTFrameworkModel):
+ text = models.TextField()
+ blog_post = models.ForeignKey(BlogPost)
+
+
+class Person(RESTFrameworkModel):
+ name = models.CharField(max_length=10)
+ age = models.IntegerField(null=True, blank=True)
+
+
+# Model for issue #324
+class BlankFieldModel(RESTFrameworkModel):
+ title = models.CharField(max_length=100, blank=True)
diff --git a/rest_framework/tests/negotiation.py b/rest_framework/tests/negotiation.py
index d8265b43..e06354ea 100644
--- a/rest_framework/tests/negotiation.py
+++ b/rest_framework/tests/negotiation.py
@@ -18,20 +18,20 @@ class TestAcceptedMediaType(TestCase):
self.renderers = [MockJSONRenderer(), MockHTMLRenderer()]
self.negotiator = DefaultContentNegotiation()
- def negotiate(self, request):
- return self.negotiator.negotiate(request, self.renderers)
+ def select_renderer(self, request):
+ return self.negotiator.select_renderer(request, self.renderers)
def test_client_without_accept_use_renderer(self):
request = factory.get('/')
- accepted_renderer, accepted_media_type = self.negotiate(request)
+ accepted_renderer, accepted_media_type = self.select_renderer(request)
self.assertEquals(accepted_media_type, 'application/json')
def test_client_underspecifies_accept_use_renderer(self):
request = factory.get('/', HTTP_ACCEPT='*/*')
- accepted_renderer, accepted_media_type = self.negotiate(request)
+ accepted_renderer, accepted_media_type = self.select_renderer(request)
self.assertEquals(accepted_media_type, 'application/json')
def test_client_overspecifies_accept_use_client(self):
request = factory.get('/', HTTP_ACCEPT='application/json; indent=8')
- accepted_renderer, accepted_media_type = self.negotiate(request)
+ accepted_renderer, accepted_media_type = self.select_renderer(request)
self.assertEquals(accepted_media_type, 'application/json; indent=8')
diff --git a/rest_framework/tests/request.py b/rest_framework/tests/request.py
index 7b24b036..ff48f3fa 100644
--- a/rest_framework/tests/request.py
+++ b/rest_framework/tests/request.py
@@ -10,9 +10,9 @@ from rest_framework import status
from rest_framework.authentication import SessionAuthentication
from django.test.client import RequestFactory
from rest_framework.parsers import (
+ BaseParser,
FormParser,
MultiPartParser,
- PlainTextParser,
JSONParser
)
from rest_framework.request import Request
@@ -24,6 +24,19 @@ from rest_framework.views import APIView
factory = RequestFactory()
+class PlainTextParser(BaseParser):
+ media_type = 'text/plain'
+
+ def parse(self, stream, media_type=None, parser_context=None):
+ """
+ Returns a 2-tuple of `(data, files)`.
+
+ `data` will simply be a string representing the body of the request.
+ `files` will always be `None`.
+ """
+ return stream.read()
+
+
class TestMethodOverloading(TestCase):
def test_method(self):
"""
diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py
index 256987ad..d4b43862 100644
--- a/rest_framework/tests/serializer.py
+++ b/rest_framework/tests/serializer.py
@@ -4,6 +4,11 @@ from rest_framework import serializers
from rest_framework.tests.models import *
+class SubComment(object):
+ def __init__(self, sub_comment):
+ self.sub_comment = sub_comment
+
+
class Comment(object):
def __init__(self, email, content, created):
self.email = email
@@ -14,11 +19,16 @@ class Comment(object):
return all([getattr(self, attr) == getattr(other, attr)
for attr in ('email', 'content', 'created')])
+ def get_sub_comment(self):
+ sub_comment = SubComment('And Merry Christmas!')
+ return sub_comment
+
class CommentSerializer(serializers.Serializer):
email = serializers.EmailField()
content = serializers.CharField(max_length=1000)
created = serializers.DateTimeField()
+ sub_comment = serializers.Field(source='get_sub_comment.sub_comment')
def restore_object(self, data, instance=None):
if instance is None:
@@ -28,6 +38,16 @@ class CommentSerializer(serializers.Serializer):
return instance
+class ActionItemSerializer(serializers.ModelSerializer):
+ class Meta:
+ model = ActionItem
+
+
+class PersonSerializer(serializers.ModelSerializer):
+ class Meta:
+ model = Person
+
+
class BasicTests(TestCase):
def setUp(self):
self.comment = Comment(
@@ -38,7 +58,14 @@ class BasicTests(TestCase):
self.data = {
'email': 'tom@example.com',
'content': 'Happy new year!',
- 'created': datetime.datetime(2012, 1, 1)
+ 'created': datetime.datetime(2012, 1, 1),
+ 'sub_comment': 'This wont change'
+ }
+ self.expected = {
+ 'email': 'tom@example.com',
+ 'content': 'Happy new year!',
+ 'created': datetime.datetime(2012, 1, 1),
+ 'sub_comment': 'And Merry Christmas!'
}
def test_empty(self):
@@ -46,14 +73,14 @@ class BasicTests(TestCase):
expected = {
'email': '',
'content': '',
- 'created': None
+ 'created': None,
+ 'sub_comment': ''
}
self.assertEquals(serializer.data, expected)
def test_retrieve(self):
serializer = CommentSerializer(instance=self.comment)
- expected = self.data
- self.assertEquals(serializer.data, expected)
+ self.assertEquals(serializer.data, self.expected)
def test_create(self):
serializer = CommentSerializer(self.data)
@@ -61,6 +88,7 @@ class BasicTests(TestCase):
self.assertEquals(serializer.is_valid(), True)
self.assertEquals(serializer.object, expected)
self.assertFalse(serializer.object is expected)
+ self.assertEquals(serializer.data['sub_comment'], 'And Merry Christmas!')
def test_update(self):
serializer = CommentSerializer(self.data, instance=self.comment)
@@ -68,6 +96,7 @@ class BasicTests(TestCase):
self.assertEquals(serializer.is_valid(), True)
self.assertEquals(serializer.object, expected)
self.assertTrue(serializer.object is expected)
+ self.assertEquals(serializer.data['sub_comment'], 'And Merry Christmas!')
class ValidationTests(TestCase):
@@ -82,6 +111,8 @@ class ValidationTests(TestCase):
'content': 'x' * 1001,
'created': datetime.datetime(2012, 1, 1)
}
+ self.actionitem = ActionItem('Some to do item',
+ )
def test_create(self):
serializer = CommentSerializer(self.data)
@@ -102,6 +133,74 @@ class ValidationTests(TestCase):
self.assertEquals(serializer.is_valid(), False)
self.assertEquals(serializer.errors, {'email': [u'This field is required.']})
+ def test_missing_bool_with_default(self):
+ """Make sure that a boolean value with a 'False' value is not
+ mistaken for not having a default."""
+ data = {
+ 'title': 'Some action item',
+ #No 'done' value.
+ }
+ serializer = ActionItemSerializer(data, instance=self.actionitem)
+ self.assertEquals(serializer.is_valid(), True)
+ self.assertEquals(serializer.errors, {})
+
+ def test_field_validation(self):
+
+ class CommentSerializerWithFieldValidator(CommentSerializer):
+
+ def validate_content(self, attrs, source):
+ value = attrs[source]
+ if "test" not in value:
+ raise serializers.ValidationError("Test not in value")
+ return attrs
+
+ data = {
+ 'email': 'tom@example.com',
+ 'content': 'A test comment',
+ 'created': datetime.datetime(2012, 1, 1)
+ }
+
+ serializer = CommentSerializerWithFieldValidator(data)
+ self.assertTrue(serializer.is_valid())
+
+ data['content'] = 'This should not validate'
+
+ serializer = CommentSerializerWithFieldValidator(data)
+ self.assertFalse(serializer.is_valid())
+ self.assertEquals(serializer.errors, {'content': [u'Test not in value']})
+
+ def test_cross_field_validation(self):
+
+ class CommentSerializerWithCrossFieldValidator(CommentSerializer):
+
+ def validate(self, attrs):
+ if attrs["email"] not in attrs["content"]:
+ raise serializers.ValidationError("Email address not in content")
+ return attrs
+
+ data = {
+ 'email': 'tom@example.com',
+ 'content': 'A comment from tom@example.com',
+ 'created': datetime.datetime(2012, 1, 1)
+ }
+
+ serializer = CommentSerializerWithCrossFieldValidator(data)
+ self.assertTrue(serializer.is_valid())
+
+ data['content'] = 'A comment from foo@bar.com'
+
+ serializer = CommentSerializerWithCrossFieldValidator(data)
+ self.assertFalse(serializer.is_valid())
+ self.assertEquals(serializer.errors, {'non_field_errors': [u'Email address not in content']})
+
+ def test_null_is_true_fields(self):
+ """
+ Omitting a value for null-field should validate.
+ """
+ serializer = PersonSerializer({'name': 'marko'})
+ self.assertEquals(serializer.is_valid(), True)
+ self.assertEquals(serializer.errors, {})
+
class MetadataTests(TestCase):
def test_empty(self):
@@ -212,6 +311,61 @@ class ManyToManyTests(TestCase):
self.assertEquals(list(instance.rel.all()), [])
+class ReadOnlyManyToManyTests(TestCase):
+ def setUp(self):
+ class ReadOnlyManyToManySerializer(serializers.ModelSerializer):
+ rel = serializers.ManyRelatedField(read_only=True)
+
+ class Meta:
+ model = ReadOnlyManyToManyModel
+
+ self.serializer_class = ReadOnlyManyToManySerializer
+
+ # An anchor instance to use for the relationship
+ self.anchor = Anchor()
+ self.anchor.save()
+
+ # A model instance with a many to many relationship to the anchor
+ self.instance = ReadOnlyManyToManyModel()
+ self.instance.save()
+ self.instance.rel.add(self.anchor)
+
+ # A serialized representation of the model instance
+ self.data = {'rel': [self.anchor.id], 'id': 1, 'text': 'anchor'}
+
+ def test_update(self):
+ """
+ Attempt to update an instance of a model with a ManyToMany
+ relationship. Not updated due to read_only=True
+ """
+ new_anchor = Anchor()
+ new_anchor.save()
+ data = {'rel': [self.anchor.id, new_anchor.id]}
+ serializer = self.serializer_class(data, instance=self.instance)
+ self.assertEquals(serializer.is_valid(), True)
+ instance = serializer.save()
+ self.assertEquals(len(ReadOnlyManyToManyModel.objects.all()), 1)
+ self.assertEquals(instance.pk, 1)
+ # rel is still as original (1 entry)
+ self.assertEquals(list(instance.rel.all()), [self.anchor])
+
+ def test_update_without_relationship(self):
+ """
+ Attempt to update an instance of a model where many to ManyToMany
+ relationship is not supplied. Not updated due to read_only=True
+ """
+ new_anchor = Anchor()
+ new_anchor.save()
+ data = {}
+ serializer = self.serializer_class(data, instance=self.instance)
+ self.assertEquals(serializer.is_valid(), True)
+ instance = serializer.save()
+ self.assertEquals(len(ReadOnlyManyToManyModel.objects.all()), 1)
+ self.assertEquals(instance.pk, 1)
+ # rel is still as original (1 entry)
+ self.assertEquals(list(instance.rel.all()), [self.anchor])
+
+
class DefaultValueTests(TestCase):
def setUp(self):
class DefaultValueSerializer(serializers.ModelSerializer):
@@ -266,3 +420,81 @@ class CallableDefaultValueTests(TestCase):
self.assertEquals(len(self.objects.all()), 1)
self.assertEquals(instance.pk, 1)
self.assertEquals(instance.text, 'overridden')
+
+
+class ManyRelatedTests(TestCase):
+ def setUp(self):
+
+ class BlogPostCommentSerializer(serializers.Serializer):
+ text = serializers.CharField()
+
+ class BlogPostSerializer(serializers.Serializer):
+ title = serializers.CharField()
+ comments = BlogPostCommentSerializer(source='blogpostcomment_set')
+
+ self.serializer_class = BlogPostSerializer
+
+ def test_reverse_relations(self):
+ post = BlogPost.objects.create(title="Test blog post")
+ post.blogpostcomment_set.create(text="I hate this blog post")
+ post.blogpostcomment_set.create(text="I love this blog post")
+
+ serializer = self.serializer_class(instance=post)
+ expected = {
+ 'title': 'Test blog post',
+ 'comments': [
+ {'text': 'I hate this blog post'},
+ {'text': 'I love this blog post'}
+ ]
+ }
+
+ self.assertEqual(serializer.data, expected)
+
+
+# Test for issue #324
+class BlankFieldTests(TestCase):
+ def setUp(self):
+
+ class BlankFieldModelSerializer(serializers.ModelSerializer):
+ class Meta:
+ model = BlankFieldModel
+
+ class BlankFieldSerializer(serializers.Serializer):
+ title = serializers.CharField(blank=True)
+
+ class NotBlankFieldModelSerializer(serializers.ModelSerializer):
+ class Meta:
+ model = BasicModel
+
+ class NotBlankFieldSerializer(serializers.Serializer):
+ title = serializers.CharField()
+
+ self.model_serializer_class = BlankFieldModelSerializer
+ self.serializer_class = BlankFieldSerializer
+ self.not_blank_model_serializer_class = NotBlankFieldModelSerializer
+ self.not_blank_serializer_class = NotBlankFieldSerializer
+ self.data = {'title': ''}
+
+ def test_create_blank_field(self):
+ serializer = self.serializer_class(self.data)
+ self.assertEquals(serializer.is_valid(), True)
+
+ def test_create_model_blank_field(self):
+ serializer = self.model_serializer_class(self.data)
+ self.assertEquals(serializer.is_valid(), True)
+
+ def test_create_not_blank_field(self):
+ """
+ Test to ensure blank data in a field not marked as blank=True
+ is considered invalid in a non-model serializer
+ """
+ serializer = self.not_blank_serializer_class(self.data)
+ self.assertEquals(serializer.is_valid(), False)
+
+ def test_create_model_not_blank_field(self):
+ """
+ Test to ensure blank data in a field not marked as blank=True
+ is considered invalid in a model serializer
+ """
+ serializer = self.not_blank_model_serializer_class(self.data)
+ self.assertEquals(serializer.is_valid(), False)
diff --git a/rest_framework/tests/tests.py b/rest_framework/tests/tests.py
new file mode 100644
index 00000000..adeaf6da
--- /dev/null
+++ b/rest_framework/tests/tests.py
@@ -0,0 +1,13 @@
+"""
+Force import of all modules in this package in order to get the standard test
+runner to pick up the tests. Yowzers.
+"""
+import os
+
+modules = [filename.rsplit('.', 1)[0]
+ for filename in os.listdir(os.path.dirname(__file__))
+ if filename.endswith('.py') and not filename.startswith('_')]
+__test__ = dict()
+
+for module in modules:
+ exec("from rest_framework.tests.%s import *" % module)
diff --git a/rest_framework/tests/validators.py b/rest_framework/tests/validators.py
index b390c42f..c032985e 100644
--- a/rest_framework/tests/validators.py
+++ b/rest_framework/tests/validators.py
@@ -285,7 +285,7 @@
# uiop = models.CharField(max_length=256, blank=True)
# @property
-# def readonly(self):
+# def read_only(self):
# return 'read only'
# class MockResource(ModelResource):
@@ -298,7 +298,7 @@
# def test_property_fields_are_allowed_on_model_forms(self):
# """Validation on ModelForms may include property fields that exist on the Model to be included in the input."""
-# content = {'qwerty': 'example', 'uiop': 'example', 'readonly': 'read only'}
+# content = {'qwerty': 'example', 'uiop': 'example', 'read_only': 'read only'}
# self.assertEqual(self.validator.validate_request(content, None), content)
# def test_property_fields_are_not_required_on_model_forms(self):
@@ -310,19 +310,19 @@
# """If some (otherwise valid) content includes fields that are not in the form then validation should fail.
# It might be okay on normal form submission, but for Web APIs we oughta get strict, as it'll help show up
# broken clients more easily (eg submitting content with a misnamed field)"""
-# content = {'qwerty': 'example', 'uiop': 'example', 'readonly': 'read only', 'extra': 'extra'}
+# content = {'qwerty': 'example', 'uiop': 'example', 'read_only': 'read only', 'extra': 'extra'}
# self.assertRaises(ImmediateResponse, self.validator.validate_request, content, None)
# def test_validate_requires_fields_on_model_forms(self):
# """If some (otherwise valid) content includes fields that are not in the form then validation should fail.
# It might be okay on normal form submission, but for Web APIs we oughta get strict, as it'll help show up
# broken clients more easily (eg submitting content with a misnamed field)"""
-# content = {'readonly': 'read only'}
+# content = {'read_only': 'read only'}
# self.assertRaises(ImmediateResponse, self.validator.validate_request, content, None)
# def test_validate_does_not_require_blankable_fields_on_model_forms(self):
# """Test standard ModelForm validation behaviour - fields with blank=True are not required."""
-# content = {'qwerty': 'example', 'readonly': 'read only'}
+# content = {'qwerty': 'example', 'read_only': 'read only'}
# self.validator.validate_request(content, None)
# def test_model_form_validator_uses_model_forms(self):