import datetime, pickle from django.test import TestCase from rest_framework import serializers from rest_framework.tests.models import (ActionItem, Anchor, BasicModel, BlankFieldModel, BlogPost, Book, CallableDefaultValueModel, DefaultValueModel, ManyToManyModel, Person, ReadOnlyManyToManyModel) 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 self.content = content self.created = created or datetime.datetime.now() def __eq__(self, other): 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: return Comment(**data) for key, val in data.items(): setattr(instance, key, val) return instance class BookSerializer(serializers.ModelSerializer): isbn = serializers.RegexField(regex=r'^[0-9]{13}$', error_messages={'invalid': 'isbn has to be exact 13 numbers'}) class Meta: model = Book class ActionItemSerializer(serializers.ModelSerializer): class Meta: model = ActionItem class PersonSerializer(serializers.ModelSerializer): info = serializers.Field(source='info') class Meta: model = Person fields = ('name', 'age', 'info') read_only_fields = ('age',) class BasicTests(TestCase): def setUp(self): self.comment = Comment( 'tom@example.com', 'Happy new year!', datetime.datetime(2012, 1, 1) ) self.data = { 'email': 'tom@example.com', 'content': 'Happy new year!', '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!' } self.person_data = {'name': 'dwight', 'age': 35} self.person = Person(**self.person_data) self.person.save() def test_empty(self): serializer = CommentSerializer() expected = { 'email': '', 'content': '', 'created': None, 'sub_comment': '' } self.assertEquals(serializer.data, expected) def test_retrieve(self): serializer = CommentSerializer(self.comment) self.assertEquals(serializer.data, self.expected) def test_create(self): serializer = CommentSerializer(data=self.data) expected = self.comment 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.comment, data=self.data) expected = self.comment 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!') def test_partial_update(self): msg = 'Merry New Year!' partial_data = {'content': msg} serializer = CommentSerializer(self.comment, data=partial_data) self.assertEquals(serializer.is_valid(), False) serializer = CommentSerializer(self.comment, data=partial_data, partial=True) expected = self.comment self.assertEqual(serializer.is_valid(), True) self.assertEquals(serializer.object, expected) self.assertTrue(serializer.object is expected) self.assertEquals(serializer.data['content'], msg) def test_model_fields_as_expected(self): """ Make sure that the fields returned are the same as defined in the Meta data """ serializer = PersonSerializer(self.person) self.assertEquals(set(serializer.data.keys()), set(['name', 'age', 'info'])) def test_field_with_dictionary(self): """ Make sure that dictionaries from fields are left intact """ serializer = PersonSerializer(self.person) expected = self.person_data self.assertEquals(serializer.data['info'], expected) def test_read_only_fields(self): """ Attempting to update fields set as read_only should have no effect. """ serializer = PersonSerializer(self.person, data={'name': 'dwight', 'age': 99}) self.assertEquals(serializer.is_valid(), True) instance = serializer.save() self.assertEquals(serializer.errors, {}) # Assert age is unchanged (35) self.assertEquals(instance.age, self.person_data['age']) class ValidationTests(TestCase): def setUp(self): self.comment = Comment( 'tom@example.com', 'Happy new year!', datetime.datetime(2012, 1, 1) ) self.data = { 'email': 'tom@example.com', 'content': 'x' * 1001, 'created': datetime.datetime(2012, 1, 1) } self.actionitem = ActionItem('Some to do item', ) def test_create(self): serializer = CommentSerializer(data=self.data) self.assertEquals(serializer.is_valid(), False) self.assertEquals(serializer.errors, {'content': [u'Ensure this value has at most 1000 characters (it has 1001).']}) def test_update(self): serializer = CommentSerializer(self.comment, data=self.data) self.assertEquals(serializer.is_valid(), False) self.assertEquals(serializer.errors, {'content': [u'Ensure this value has at most 1000 characters (it has 1001).']}) def test_update_missing_field(self): data = { 'content': 'xxx', 'created': datetime.datetime(2012, 1, 1) } serializer = CommentSerializer(self.comment, data=data)
"""
Tests for content parsing, and form-overloaded content parsing.
"""
from django.test import TestCase
from djangorestframework.compat import RequestFactory
from djangorestframework.mixins import RequestMixin
from djangorestframework.parsers import FormParser, MultiPartParser, PlainTextParser

class TestContentParsing(TestCase):
    def setUp(self):
        self.req = RequestFactory()

    def ensure_determines_no_content_GET(self, view):
        """Ensure view.DATA returns None for GET request with no content."""
        view.request = self.req.get('/')
        self.assertEqual(view.DATA, None)

    def ensure_determines_no_content_HEAD(self, view):
        """Ensure view.DATA returns None for HEAD request."""
        view.request = self.req.head('/')
        self.assertEqual(view.DATA, None)

    def ensure_determines_form_content_POST(self, view):
        """Ensure view.DATA returns content for POST request with form content."""
        form_data = {'qwerty': 'uiop'}
        view.parsers = (FormParser, MultiPartParser)
        view.request = self.req.post('/', data=form_data)
        self.assertEqual(view.DATA.items(), form_data.items())

    def ensure_determines_non_form_content_POST(self, view):
        """Ensure view.RAW_CONTENT returns content for POST request with non-form content."""
        content = 'qwerty'
        content_type = 'text/plain'
        view.parsers = (PlainTextParser,)
        view.request = self.req.post('/', content, content_type=content_type)
        self.assertEqual(view.DATA, content)

    def ensure_determines_form_content_PUT(self, view):
        """Ensure view.RAW_CONTENT returns content for PUT request with form content."""
        form_data = {'qwerty': 'uiop'}
        view.parsers = (FormParser, MultiPartParser)
        view.request = self.req.put('/', data=form_data)
        self.assertEqual(view.DATA.items(), form_data.items())

    def ensure_determines_non_form_content_PUT(self, view):
        """Ensure view.RAW_CONTENT returns content for PUT request with non-form content."""
        content = 'qwerty'
        content_type = 'text/plain'
        view.parsers = (PlainTextParser,)
        view.request = self.req.post('/', content, content_type=content_type)
        self.assertEqual(view.DATA, content)

    def test_standard_behaviour_determines_no_content_GET(self):
        """Ensure view.DATA returns None for GET request with no content."""
        self.ensure_determines_no_content_GET(RequestMixin())

    def test_standard_behaviour_determines_no_content_HEAD(self):
        """Ensure view.DATA returns None for HEAD request."""
        self.ensure_determines_no_content_HEAD(RequestMixin())

    def test_standard_behaviour_determines_form_content_POST(self):
        """Ensure view.DATA returns content for POST request with form content."""
        self.ensure_determines_form_content_POST(RequestMixin())

    def test_standard_behaviour_determines_non_form_content_POST(self):
        """Ensure view.DATA returns content for POST request with non-form content."""
        self.ensure_determines_non_form_content_POST(RequestMixin())

    def test_standard_behaviour_determines_form_content_PUT(self):
        """Ensure view.DATA returns content for PUT request with form content."""
        self.ensure_determines_form_content_PUT(RequestMixin())

    def test_standard_behaviour_determines_non_form_content_PUT(self):
        """Ensure view.DATA returns content for PUT request with non-form content."""
        self.ensure_determines_non_form_content_PUT(RequestMixin())

    def test_overloaded_behaviour_allows_content_tunnelling(self):
        """Ensure request.DATA returns content for overloaded POST request"""
        content = 'qwerty'
        content_type = 'text/plain'
        view = RequestMixin()
        form_data = {view._CONTENT_PARAM: content,
                     view._CONTENTTYPE_PARAM: content_type}
        view.request = self.req.post('/', form_data)
        view.parsers = (PlainTextParser,)
        self.assertEqual(view.DATA, content)
comments = BlogPostCommentSerializer(source='blogpostcomment_set') serializer = BlogPostSerializer(instance=post) expected = { 'title': u'Test blog post', 'comments': [{ 'text': u'I love this blog post', 'post_owner': { "name": u"django", "age": None } }] } self.assertEqual(serializer.data, expected) class SerializerMethodFieldTests(TestCase): def setUp(self): class BoopSerializer(serializers.Serializer): beep = serializers.SerializerMethodField('get_beep') boop = serializers.Field() boop_count = serializers.SerializerMethodField('get_boop_count') def get_beep(self, obj): return 'hello!' def get_boop_count(self, obj): return len(obj.boop) self.serializer_class = BoopSerializer def test_serializer_method_field(self): class MyModel(object): boop = ['a', 'b', 'c'] source_data = MyModel() serializer = self.serializer_class(source_data) expected = { 'beep': u'hello!', 'boop': [u'a', u'b', u'c'], 'boop_count': 3, } 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(data=self.data) self.assertEquals(serializer.is_valid(), True) def test_create_model_blank_field(self): serializer = self.model_serializer_class(data=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(data=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(data=self.data) self.assertEquals(serializer.is_valid(), False) #test for issue #460 class SerializerPickleTests(TestCase): """ Test pickleability of the output of Serializers """ def test_pickle_simple_model_serializer_data(self): """ Test simple serializer """ pickle.dumps(PersonSerializer(Person(name="Methusela", age=969)).data) def test_pickle_inner_serializer(self): """ Test pickling a serializer whose resulting .data (a SortedDictWithMetadata) will have unpickleable meta data--in order to make sure metadata doesn't get pulled into the pickle. See DictWithMetadata.__getstate__ """ class InnerPersonSerializer(serializers.ModelSerializer): class Meta: model = Person fields = ('name', 'age') pickle.dumps(InnerPersonSerializer(Person(name="Noah", age=950)).data)