aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/test_fields.py69
-rw-r--r--tests/test_filters.py17
-rw-r--r--tests/test_htmlrenderer.py6
-rw-r--r--tests/test_model_serializer.py52
-rw-r--r--tests/test_multitable_inheritance.py4
-rw-r--r--tests/test_parsers.py4
-rw-r--r--tests/test_relations.py33
-rw-r--r--tests/test_renderers.py85
-rw-r--r--tests/test_routers.py7
-rw-r--r--tests/test_serializer.py17
-rw-r--r--tests/utils.py25
11 files changed, 200 insertions, 119 deletions
diff --git a/tests/test_fields.py b/tests/test_fields.py
index 775d4618..6744cf64 100644
--- a/tests/test_fields.py
+++ b/tests/test_fields.py
@@ -4,6 +4,7 @@ from rest_framework import serializers
import datetime
import django
import pytest
+import uuid
# Tests for field keyword arguments and core functionality.
@@ -467,6 +468,23 @@ class TestURLField(FieldValues):
field = serializers.URLField()
+class TestUUIDField(FieldValues):
+ """
+ Valid and invalid values for `UUIDField`.
+ """
+ valid_inputs = {
+ '825d7aeb-05a9-45b5-a5b7-05df87923cda': uuid.UUID('825d7aeb-05a9-45b5-a5b7-05df87923cda'),
+ '825d7aeb05a945b5a5b705df87923cda': uuid.UUID('825d7aeb-05a9-45b5-a5b7-05df87923cda')
+ }
+ invalid_inputs = {
+ '825d7aeb-05a9-45b5-a5b7': ['"825d7aeb-05a9-45b5-a5b7" is not a valid UUID.']
+ }
+ outputs = {
+ uuid.UUID('825d7aeb-05a9-45b5-a5b7-05df87923cda'): '825d7aeb-05a9-45b5-a5b7-05df87923cda'
+ }
+ field = serializers.UUIDField()
+
+
# Number types...
class TestIntegerField(FieldValues):
@@ -1029,7 +1047,7 @@ class TestValidImageField(FieldValues):
class TestListField(FieldValues):
"""
- Values for `ListField`.
+ Values for `ListField` with IntegerField as child.
"""
valid_inputs = [
([1, 2, 3], [1, 2, 3]),
@@ -1046,6 +1064,55 @@ class TestListField(FieldValues):
field = serializers.ListField(child=serializers.IntegerField())
+class TestUnvalidatedListField(FieldValues):
+ """
+ Values for `ListField` with no `child` argument.
+ """
+ valid_inputs = [
+ ([1, '2', True, [4, 5, 6]], [1, '2', True, [4, 5, 6]]),
+ ]
+ invalid_inputs = [
+ ('not a list', ['Expected a list of items but got type `str`']),
+ ]
+ outputs = [
+ ([1, '2', True, [4, 5, 6]], [1, '2', True, [4, 5, 6]]),
+ ]
+ field = serializers.ListField()
+
+
+class TestDictField(FieldValues):
+ """
+ Values for `ListField` with CharField as child.
+ """
+ valid_inputs = [
+ ({'a': 1, 'b': '2', 3: 3}, {'a': '1', 'b': '2', '3': '3'}),
+ ]
+ invalid_inputs = [
+ ({'a': 1, 'b': None}, ['This field may not be null.']),
+ ('not a dict', ['Expected a dictionary of items but got type `str`']),
+ ]
+ outputs = [
+ ({'a': 1, 'b': '2', 3: 3}, {'a': '1', 'b': '2', '3': '3'}),
+ ]
+ field = serializers.DictField(child=serializers.CharField())
+
+
+class TestUnvalidatedDictField(FieldValues):
+ """
+ Values for `ListField` with no `child` argument.
+ """
+ valid_inputs = [
+ ({'a': 1, 'b': [4, 5, 6], 1: 123}, {'a': 1, 'b': [4, 5, 6], '1': 123}),
+ ]
+ invalid_inputs = [
+ ('not a dict', ['Expected a dictionary of items but got type `str`']),
+ ]
+ outputs = [
+ ({'a': 1, 'b': [4, 5, 6]}, {'a': 1, 'b': [4, 5, 6]}),
+ ]
+ field = serializers.DictField()
+
+
# Tests for FieldField.
# ---------------------
diff --git a/tests/test_filters.py b/tests/test_filters.py
index dc84dcbd..355f02ce 100644
--- a/tests/test_filters.py
+++ b/tests/test_filters.py
@@ -5,13 +5,15 @@ from django.db import models
from django.conf.urls import patterns, url
from django.core.urlresolvers import reverse
from django.test import TestCase
+from django.test.utils import override_settings
from django.utils import unittest
from django.utils.dateparse import parse_date
+from django.utils.six.moves import reload_module
from rest_framework import generics, serializers, status, filters
from rest_framework.compat import django_filters
from rest_framework.test import APIRequestFactory
from .models import BaseFilterableItem, FilterableItem, BasicModel
-from .utils import temporary_setting
+
factory = APIRequestFactory()
@@ -404,7 +406,9 @@ class SearchFilterTests(TestCase):
)
def test_search_with_nonstandard_search_param(self):
- with temporary_setting('SEARCH_PARAM', 'query', module=filters):
+ with override_settings(REST_FRAMEWORK={'SEARCH_PARAM': 'query'}):
+ reload_module(filters)
+
class SearchListView(generics.ListAPIView):
queryset = SearchFilterModel.objects.all()
serializer_class = SearchFilterSerializer
@@ -422,6 +426,8 @@ class SearchFilterTests(TestCase):
]
)
+ reload_module(filters)
+
class OrderingFilterModel(models.Model):
title = models.CharField(max_length=20)
@@ -467,6 +473,7 @@ class DjangoFilterOrderingTests(TestCase):
for d in data:
DjangoFilterOrderingModel.objects.create(**d)
+ @unittest.skipUnless(django_filters, 'django-filter not installed')
def test_default_ordering(self):
class DjangoFilterOrderingView(generics.ListAPIView):
serializer_class = DjangoFilterOrderingSerializer
@@ -641,7 +648,9 @@ class OrderingFilterTests(TestCase):
)
def test_ordering_with_nonstandard_ordering_param(self):
- with temporary_setting('ORDERING_PARAM', 'order', filters):
+ with override_settings(REST_FRAMEWORK={'ORDERING_PARAM': 'order'}):
+ reload_module(filters)
+
class OrderingListView(generics.ListAPIView):
queryset = OrderingFilterModel.objects.all()
serializer_class = OrderingFilterSerializer
@@ -661,6 +670,8 @@ class OrderingFilterTests(TestCase):
]
)
+ reload_module(filters)
+
class SensitiveOrderingFilterModel(models.Model):
username = models.CharField(max_length=20)
diff --git a/tests/test_htmlrenderer.py b/tests/test_htmlrenderer.py
index 2edc6b4b..a33b832f 100644
--- a/tests/test_htmlrenderer.py
+++ b/tests/test_htmlrenderer.py
@@ -56,7 +56,13 @@ class TemplateHTMLRendererTests(TestCase):
return Template("example: {{ object }}")
raise TemplateDoesNotExist(template_name)
+ def select_template(template_name_list, dirs=None, using=None):
+ if template_name_list == ['example.html']:
+ return Template("example: {{ object }}")
+ raise TemplateDoesNotExist(template_name_list[0])
+
django.template.loader.get_template = get_template
+ django.template.loader.select_template = select_template
def tearDown(self):
"""
diff --git a/tests/test_model_serializer.py b/tests/test_model_serializer.py
index ee556dbc..247b309a 100644
--- a/tests/test_model_serializer.py
+++ b/tests/test_model_serializer.py
@@ -5,11 +5,14 @@ shortcuts for automatically creating serializers based on a given model class.
These tests deal with ensuring that we correctly map the model fields onto
an appropriate set of serializer fields for each case.
"""
+from __future__ import unicode_literals
from django.core.exceptions import ImproperlyConfigured
from django.core.validators import MaxValueValidator, MinValueValidator, MinLengthValidator
from django.db import models
from django.test import TestCase
+from django.utils import six
from rest_framework import serializers
+from rest_framework.compat import unicode_repr
def dedent(blocktext):
@@ -124,7 +127,7 @@ class TestRegularFieldMappings(TestCase):
url_field = URLField(max_length=100)
custom_field = ModelField(model_field=<tests.test_model_serializer.CustomField: custom_field>)
""")
- self.assertEqual(repr(TestSerializer()), expected)
+ self.assertEqual(unicode_repr(TestSerializer()), expected)
def test_field_options(self):
class TestSerializer(serializers.ModelSerializer):
@@ -142,7 +145,14 @@ class TestRegularFieldMappings(TestCase):
descriptive_field = IntegerField(help_text='Some help text', label='A label')
choices_field = ChoiceField(choices=[('red', 'Red'), ('blue', 'Blue'), ('green', 'Green')])
""")
- self.assertEqual(repr(TestSerializer()), expected)
+ if six.PY2:
+ # This particular case is too awkward to resolve fully across
+ # both py2 and py3.
+ expected = expected.replace(
+ "('red', 'Red'), ('blue', 'Blue'), ('green', 'Green')",
+ "(u'red', u'Red'), (u'blue', u'Blue'), (u'green', u'Green')"
+ )
+ self.assertEqual(unicode_repr(TestSerializer()), expected)
def test_method_field(self):
"""
@@ -221,7 +231,7 @@ class TestRegularFieldMappings(TestCase):
model = RegularFieldsModel
fields = ('auto_field',)
- with self.assertRaises(ImproperlyConfigured) as excinfo:
+ with self.assertRaises(AssertionError) as excinfo:
TestSerializer().fields
expected = (
'Field `missing` has been declared on serializer '
@@ -229,6 +239,26 @@ class TestRegularFieldMappings(TestCase):
)
assert str(excinfo.exception) == expected
+ def test_missing_superclass_field(self):
+ """
+ Fields that have been declared on a parent of the serializer class may
+ be excluded from the `Meta.fields` option.
+ """
+ class TestSerializer(serializers.ModelSerializer):
+ missing = serializers.ReadOnlyField()
+
+ class Meta:
+ model = RegularFieldsModel
+
+ class ChildSerializer(TestSerializer):
+ missing = serializers.ReadOnlyField()
+
+ class Meta:
+ model = RegularFieldsModel
+ fields = ('auto_field',)
+
+ ChildSerializer().fields
+
# Tests for relational field mappings.
# ------------------------------------
@@ -276,7 +306,7 @@ class TestRelationalFieldMappings(TestCase):
many_to_many = PrimaryKeyRelatedField(many=True, queryset=ManyToManyTargetModel.objects.all())
through = PrimaryKeyRelatedField(many=True, read_only=True)
""")
- self.assertEqual(repr(TestSerializer()), expected)
+ self.assertEqual(unicode_repr(TestSerializer()), expected)
def test_nested_relations(self):
class TestSerializer(serializers.ModelSerializer):
@@ -300,7 +330,7 @@ class TestRelationalFieldMappings(TestCase):
id = IntegerField(label='ID', read_only=True)
name = CharField(max_length=100)
""")
- self.assertEqual(repr(TestSerializer()), expected)
+ self.assertEqual(unicode_repr(TestSerializer()), expected)
def test_hyperlinked_relations(self):
class TestSerializer(serializers.HyperlinkedModelSerializer):
@@ -315,7 +345,7 @@ class TestRelationalFieldMappings(TestCase):
many_to_many = HyperlinkedRelatedField(many=True, queryset=ManyToManyTargetModel.objects.all(), view_name='manytomanytargetmodel-detail')
through = HyperlinkedRelatedField(many=True, read_only=True, view_name='throughtargetmodel-detail')
""")
- self.assertEqual(repr(TestSerializer()), expected)
+ self.assertEqual(unicode_repr(TestSerializer()), expected)
def test_nested_hyperlinked_relations(self):
class TestSerializer(serializers.HyperlinkedModelSerializer):
@@ -339,7 +369,7 @@ class TestRelationalFieldMappings(TestCase):
url = HyperlinkedIdentityField(view_name='throughtargetmodel-detail')
name = CharField(max_length=100)
""")
- self.assertEqual(repr(TestSerializer()), expected)
+ self.assertEqual(unicode_repr(TestSerializer()), expected)
def test_pk_reverse_foreign_key(self):
class TestSerializer(serializers.ModelSerializer):
@@ -353,7 +383,7 @@ class TestRelationalFieldMappings(TestCase):
name = CharField(max_length=100)
reverse_foreign_key = PrimaryKeyRelatedField(many=True, queryset=RelationalModel.objects.all())
""")
- self.assertEqual(repr(TestSerializer()), expected)
+ self.assertEqual(unicode_repr(TestSerializer()), expected)
def test_pk_reverse_one_to_one(self):
class TestSerializer(serializers.ModelSerializer):
@@ -367,7 +397,7 @@ class TestRelationalFieldMappings(TestCase):
name = CharField(max_length=100)
reverse_one_to_one = PrimaryKeyRelatedField(queryset=RelationalModel.objects.all())
""")
- self.assertEqual(repr(TestSerializer()), expected)
+ self.assertEqual(unicode_repr(TestSerializer()), expected)
def test_pk_reverse_many_to_many(self):
class TestSerializer(serializers.ModelSerializer):
@@ -381,7 +411,7 @@ class TestRelationalFieldMappings(TestCase):
name = CharField(max_length=100)
reverse_many_to_many = PrimaryKeyRelatedField(many=True, queryset=RelationalModel.objects.all())
""")
- self.assertEqual(repr(TestSerializer()), expected)
+ self.assertEqual(unicode_repr(TestSerializer()), expected)
def test_pk_reverse_through(self):
class TestSerializer(serializers.ModelSerializer):
@@ -395,7 +425,7 @@ class TestRelationalFieldMappings(TestCase):
name = CharField(max_length=100)
reverse_through = PrimaryKeyRelatedField(many=True, read_only=True)
""")
- self.assertEqual(repr(TestSerializer()), expected)
+ self.assertEqual(unicode_repr(TestSerializer()), expected)
class TestIntegration(TestCase):
diff --git a/tests/test_multitable_inheritance.py b/tests/test_multitable_inheritance.py
index e1b40cc7..15627e1d 100644
--- a/tests/test_multitable_inheritance.py
+++ b/tests/test_multitable_inheritance.py
@@ -48,8 +48,8 @@ class InheritedModelSerializationTests(TestCase):
Assert that a model with a onetoone field that is the primary key is
not treated like a derived model
"""
- parent = ParentModel(name1='parent name')
- associate = AssociatedModel(name='hello', ref=parent)
+ parent = ParentModel.objects.create(name1='parent name')
+ associate = AssociatedModel.objects.create(name='hello', ref=parent)
serializer = AssociatedModelSerializer(associate)
self.assertEqual(set(serializer.data.keys()),
set(['name', 'ref']))
diff --git a/tests/test_parsers.py b/tests/test_parsers.py
index d28d8bd4..1d2054ac 100644
--- a/tests/test_parsers.py
+++ b/tests/test_parsers.py
@@ -161,7 +161,9 @@ class TestFileUploadParser(TestCase):
self.__replace_content_disposition('inline; filename=fallback.txt; filename*=utf-8--ÀĥƦ.txt')
filename = parser.get_filename(self.stream, None, self.parser_context)
- self.assertEqual(filename, 'fallback.txt')
+ # Malformed. Either None or 'fallback.txt' will be acceptable.
+ # See also https://code.djangoproject.com/ticket/24209
+ self.assertIn(filename, ('fallback.txt', None))
def __replace_content_disposition(self, disposition):
self.parser_context['request'].META['HTTP_CONTENT_DISPOSITION'] = disposition
diff --git a/tests/test_relations.py b/tests/test_relations.py
index 62353dc2..d478d855 100644
--- a/tests/test_relations.py
+++ b/tests/test_relations.py
@@ -1,6 +1,8 @@
from .utils import mock_reverse, fail_reverse, BadType, MockObject, MockQueryset
from django.core.exceptions import ImproperlyConfigured
+from django.utils.datastructures import MultiValueDict
from rest_framework import serializers
+from rest_framework.fields import empty
from rest_framework.test import APISimpleTestCase
import pytest
@@ -134,3 +136,34 @@ class TestSlugRelatedField(APISimpleTestCase):
def test_representation(self):
representation = self.field.to_representation(self.instance)
assert representation == self.instance.name
+
+
+class TestManyRelatedField(APISimpleTestCase):
+ def setUp(self):
+ self.instance = MockObject(pk=1, name='foo')
+ self.field = serializers.StringRelatedField(many=True)
+ self.field.field_name = 'foo'
+
+ def test_get_value_regular_dictionary_full(self):
+ assert 'bar' == self.field.get_value({'foo': 'bar'})
+ assert empty == self.field.get_value({'baz': 'bar'})
+
+ def test_get_value_regular_dictionary_partial(self):
+ setattr(self.field.root, 'partial', True)
+ assert 'bar' == self.field.get_value({'foo': 'bar'})
+ assert empty == self.field.get_value({'baz': 'bar'})
+
+ def test_get_value_multi_dictionary_full(self):
+ mvd = MultiValueDict({'foo': ['bar1', 'bar2']})
+ assert ['bar1', 'bar2'] == self.field.get_value(mvd)
+
+ mvd = MultiValueDict({'baz': ['bar1', 'bar2']})
+ assert [] == self.field.get_value(mvd)
+
+ def test_get_value_multi_dictionary_partial(self):
+ setattr(self.field.root, 'partial', True)
+ mvd = MultiValueDict({'foo': ['bar1', 'bar2']})
+ assert ['bar1', 'bar2'] == self.field.get_value(mvd)
+
+ mvd = MultiValueDict({'baz': ['bar1', 'bar2']})
+ assert empty == self.field.get_value(mvd)
diff --git a/tests/test_renderers.py b/tests/test_renderers.py
index 00a24fb1..54eea8ce 100644
--- a/tests/test_renderers.py
+++ b/tests/test_renderers.py
@@ -22,7 +22,6 @@ from rest_framework.test import APIRequestFactory
from collections import MutableMapping
import datetime
import json
-import pickle
import re
@@ -618,84 +617,24 @@ class CacheRenderTest(TestCase):
urls = 'tests.test_renderers'
- cache_key = 'just_a_cache_key'
-
- @classmethod
- def _get_pickling_errors(cls, obj, seen=None):
- """ Return any errors that would be raised if `obj' is pickled
- Courtesy of koffie @ http://stackoverflow.com/a/7218986/109897
- """
- if seen is None:
- seen = []
- try:
- state = obj.__getstate__()
- except AttributeError:
- return
- if state is None:
- return
- if isinstance(state, tuple):
- if not isinstance(state[0], dict):
- state = state[1]
- else:
- state = state[0].update(state[1])
- result = {}
- for i in state:
- try:
- pickle.dumps(state[i], protocol=2)
- except pickle.PicklingError:
- if not state[i] in seen:
- seen.append(state[i])
- result[i] = cls._get_pickling_errors(state[i], seen)
- return result
-
- def http_resp(self, http_method, url):
- """
- Simple wrapper for Client http requests
- Removes the `client' and `request' attributes from as they are
- added by django.test.client.Client and not part of caching
- responses outside of tests.
- """
- method = getattr(self.client, http_method)
- resp = method(url)
- resp._closable_objects = []
- del resp.client, resp.request
- try:
- del resp.wsgi_request
- except AttributeError:
- pass
- return resp
-
- def test_obj_pickling(self):
- """
- Test that responses are properly pickled
- """
- resp = self.http_resp('get', '/cache')
-
- # Make sure that no pickling errors occurred
- self.assertEqual(self._get_pickling_errors(resp), {})
-
- # Unfortunately LocMem backend doesn't raise PickleErrors but returns
- # None instead.
- cache.set(self.cache_key, resp)
- self.assertTrue(cache.get(self.cache_key) is not None)
-
def test_head_caching(self):
"""
Test caching of HEAD requests
"""
- resp = self.http_resp('head', '/cache')
- cache.set(self.cache_key, resp)
-
- cached_resp = cache.get(self.cache_key)
- self.assertIsInstance(cached_resp, Response)
+ response = self.client.head('/cache')
+ cache.set('key', response)
+ cached_response = cache.get('key')
+ assert isinstance(cached_response, Response)
+ assert cached_response.content == response.content
+ assert cached_response.status_code == response.status_code
def test_get_caching(self):
"""
Test caching of GET requests
"""
- resp = self.http_resp('get', '/cache')
- cache.set(self.cache_key, resp)
-
- cached_resp = cache.get(self.cache_key)
- self.assertIsInstance(cached_resp, Response)
- self.assertEqual(cached_resp.content, resp.content)
+ response = self.client.get('/cache')
+ cache.set('key', response)
+ cached_response = cache.get('key')
+ assert isinstance(cached_response, Response)
+ assert cached_response.content == response.content
+ assert cached_response.status_code == response.status_code
diff --git a/tests/test_routers.py b/tests/test_routers.py
index 86113f5d..948c69bb 100644
--- a/tests/test_routers.py
+++ b/tests/test_routers.py
@@ -180,7 +180,7 @@ class TestLookupValueRegex(TestCase):
class TestTrailingSlashIncluded(TestCase):
def setUp(self):
class NoteViewSet(viewsets.ModelViewSet):
- model = RouterTestModel
+ queryset = RouterTestModel.objects.all()
self.router = SimpleRouter()
self.router.register(r'notes', NoteViewSet)
@@ -195,7 +195,7 @@ class TestTrailingSlashIncluded(TestCase):
class TestTrailingSlashRemoved(TestCase):
def setUp(self):
class NoteViewSet(viewsets.ModelViewSet):
- model = RouterTestModel
+ queryset = RouterTestModel.objects.all()
self.router = SimpleRouter(trailing_slash=False)
self.router.register(r'notes', NoteViewSet)
@@ -210,7 +210,8 @@ class TestTrailingSlashRemoved(TestCase):
class TestNameableRoot(TestCase):
def setUp(self):
class NoteViewSet(viewsets.ModelViewSet):
- model = RouterTestModel
+ queryset = RouterTestModel.objects.all()
+
self.router = DefaultRouter()
self.router.root_view_name = 'nameable-root'
self.router.register(r'notes', NoteViewSet)
diff --git a/tests/test_serializer.py b/tests/test_serializer.py
index 68bbbe98..b7a0484b 100644
--- a/tests/test_serializer.py
+++ b/tests/test_serializer.py
@@ -3,6 +3,7 @@ from __future__ import unicode_literals
from .utils import MockObject
from rest_framework import serializers
from rest_framework.compat import unicode_repr
+import pickle
import pytest
@@ -278,3 +279,19 @@ class TestNotRequiredOutput:
serializer = ExampleSerializer(instance)
with pytest.raises(AttributeError):
serializer.data
+
+
+class TestCacheSerializerData:
+ def test_cache_serializer_data(self):
+ """
+ Caching serializer data with pickle will drop the serializer info,
+ but does preserve the data itself.
+ """
+ class ExampleSerializer(serializers.Serializer):
+ field1 = serializers.CharField()
+ field2 = serializers.CharField()
+
+ serializer = ExampleSerializer({'field1': 'a', 'field2': 'b'})
+ pickled = pickle.dumps(serializer.data)
+ data = pickle.loads(pickled)
+ assert data == {'field1': 'a', 'field2': 'b'}
diff --git a/tests/utils.py b/tests/utils.py
index 5e902ba9..5b2d7586 100644
--- a/tests/utils.py
+++ b/tests/utils.py
@@ -1,30 +1,5 @@
-from contextlib import contextmanager
from django.core.exceptions import ObjectDoesNotExist
from django.core.urlresolvers import NoReverseMatch
-from django.utils import six
-from rest_framework.settings import api_settings
-
-
-@contextmanager
-def temporary_setting(setting, value, module=None):
- """
- Temporarily change value of setting for test.
-
- Optionally reload given module, useful when module uses value of setting on
- import.
- """
- original_value = getattr(api_settings, setting)
- setattr(api_settings, setting, value)
-
- if module is not None:
- six.moves.reload_module(module)
-
- yield
-
- setattr(api_settings, setting, original_value)
-
- if module is not None:
- six.moves.reload_module(module)
class MockObject(object):