diff options
| author | Ben Konrath | 2012-11-01 14:06:56 +0100 | 
|---|---|---|
| committer | Ben Konrath | 2012-11-01 14:06:56 +0100 | 
| commit | 9c82f9717e58f1bb250d5fd4b27619dbcbbd1f21 (patch) | |
| tree | e976854e6871a8b826e91d8eb16d9a139b90664f /rest_framework/tests | |
| parent | c24997df3b943e5d7a3b2e101508e4b79ee82dc4 (diff) | |
| parent | 204db7bdaa59cd17f762d6cf0e6a8623c2cc9939 (diff) | |
| download | django-rest-framework-9c82f9717e58f1bb250d5fd4b27619dbcbbd1f21.tar.bz2 | |
Merge branch 'master' into restframework2-filter
Diffstat (limited to 'rest_framework/tests')
| -rw-r--r-- | rest_framework/tests/__init__.py | 13 | ||||
| -rw-r--r-- | rest_framework/tests/generics.py | 51 | ||||
| -rw-r--r-- | rest_framework/tests/htmlrenderer.py | 6 | ||||
| -rw-r--r-- | rest_framework/tests/hyperlinkedserializers.py | 44 | ||||
| -rw-r--r-- | rest_framework/tests/models.py | 37 | ||||
| -rw-r--r-- | rest_framework/tests/negotiation.py | 10 | ||||
| -rw-r--r-- | rest_framework/tests/request.py | 15 | ||||
| -rw-r--r-- | rest_framework/tests/serializer.py | 240 | ||||
| -rw-r--r-- | rest_framework/tests/tests.py | 13 | ||||
| -rw-r--r-- | rest_framework/tests/validators.py | 10 | 
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):  | 
