From ad060aa360fa2ed33bd83cbb419d7b996a428726 Mon Sep 17 00:00:00 2001 From: Gregor Müllegger Date: Sat, 15 Nov 2014 15:23:58 +0100 Subject: More helpful error message when default `.create` fails. Closes #2013. --- tests/test_model_serializer.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'tests') diff --git a/tests/test_model_serializer.py b/tests/test_model_serializer.py index 3aec0da0..90767dac 100644 --- a/tests/test_model_serializer.py +++ b/tests/test_model_serializer.py @@ -10,6 +10,7 @@ from django.core.validators import MaxValueValidator, MinValueValidator, MinLeng from django.db import models from django.test import TestCase from rest_framework import serializers +import pytest def dedent(blocktext): @@ -26,6 +27,10 @@ class CustomField(models.Field): pass +class OneFieldModel(models.Model): + char_field = models.CharField(max_length=100) + + class RegularFieldsModel(models.Model): """ A model class for testing regular flat fields. @@ -68,6 +73,29 @@ class FieldOptionsModel(models.Model): choices_field = models.CharField(max_length=100, choices=COLOR_CHOICES) +class TestModelSerializer(TestCase): + def test_create_method(self): + class TestSerializer(serializers.ModelSerializer): + non_model_field = serializers.CharField() + + class Meta: + model = OneFieldModel + fields = ('char_field', 'non_model_field') + + serializer = TestSerializer(data={ + 'char_field': 'foo', + 'non_model_field': 'bar', + }) + serializer.is_valid() + with pytest.raises(TypeError): + serializer.save() + + try: + serializer.save() + except TypeError as exc: + assert 'ModelSerializer' in str(exc) + + class TestRegularFieldMappings(TestCase): def test_regular_fields(self): """ -- cgit v1.2.3 From 2f03483f966c5402734b5db2f7006c788bbe04f7 Mon Sep 17 00:00:00 2001 From: Tymur Maryokhin Date: Sat, 29 Nov 2014 19:45:26 +0100 Subject: Removed unused models --- tests/models.py | 99 +-------------------------------------------------------- 1 file changed, 1 insertion(+), 98 deletions(-) (limited to 'tests') diff --git a/tests/models.py b/tests/models.py index 06ec5a22..a0e0b3cc 100644 --- a/tests/models.py +++ b/tests/models.py @@ -3,35 +3,16 @@ from django.db import models from django.utils.translation import ugettext_lazy as _ -def foobar(): - return 'foobar' - - -class CustomField(models.CharField): - - def __init__(self, *args, **kwargs): - kwargs['max_length'] = 12 - super(CustomField, self).__init__(*args, **kwargs) - - class RESTFrameworkModel(models.Model): """ Base for test models that sets app_label, so they play nicely. """ + class Meta: app_label = 'tests' abstract = True -class HasPositiveIntegerAsChoice(RESTFrameworkModel): - some_choices = ((1, 'A'), (2, 'B'), (3, 'C')) - some_integer = models.PositiveIntegerField(choices=some_choices) - - -class Anchor(RESTFrameworkModel): - text = models.CharField(max_length=100, default='anchor') - - class BasicModel(RESTFrameworkModel): text = models.CharField(max_length=100, verbose_name=_("Text comes here"), help_text=_("Text description.")) @@ -41,24 +22,6 @@ class SlugBasedModel(RESTFrameworkModel): slug = models.SlugField(max_length=32) -class DefaultValueModel(RESTFrameworkModel): - text = models.CharField(default='foobar', max_length=100) - extra = models.CharField(blank=True, null=True, max_length=100) - - -class CallableDefaultValueModel(RESTFrameworkModel): - text = models.CharField(default=foobar, max_length=100) - - -class ManyToManyModel(RESTFrameworkModel): - rel = models.ManyToManyField(Anchor, help_text='Some help text.') - - -class ReadOnlyManyToManyModel(RESTFrameworkModel): - text = models.CharField(max_length=100, default='anchor') - rel = models.ManyToManyField(Anchor) - - class BaseFilterableItem(RESTFrameworkModel): text = models.CharField(max_length=100) @@ -72,72 +35,12 @@ class FilterableItem(BaseFilterableItem): # Model for regression test for #285 - 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) - started = models.NullBooleanField(default=False) - done = models.BooleanField(default=False) - info = CustomField(default='---', max_length=12) - - -# Models for reverse relations -class Person(RESTFrameworkModel): - name = models.CharField(max_length=10) - age = models.IntegerField(null=True, blank=True) - - @property - def info(self): - return { - 'name': self.name, - 'age': self.age, - } - - -class BlogPost(RESTFrameworkModel): - title = models.CharField(max_length=100) - writer = models.ForeignKey(Person, null=True, blank=True) - - def get_first_comment(self): - return self.blogpostcomment_set.all()[0] - - -class BlogPostComment(RESTFrameworkModel): - text = models.TextField() - blog_post = models.ForeignKey(BlogPost) - - -class Album(RESTFrameworkModel): - title = models.CharField(max_length=100, unique=True) - ref = models.CharField(max_length=10, unique=True, null=True, blank=True) - - -class Photo(RESTFrameworkModel): - description = models.TextField() - album = models.ForeignKey(Album) - - -# Model for issue #324 -class BlankFieldModel(RESTFrameworkModel): - title = models.CharField(max_length=100, blank=True, null=False, - default="title") - - -# Model for issue #380 -class OptionalRelationModel(RESTFrameworkModel): - other = models.ForeignKey('OptionalRelationModel', blank=True, null=True) - - -# Model for RegexField -class Book(RESTFrameworkModel): - isbn = models.CharField(max_length=13) - - # Models for relations tests # ManyToMany class ManyToManyTarget(RESTFrameworkModel): -- cgit v1.2.3 From dd9d40d8c01f54f1542ba728d89b8b2da584dc1f Mon Sep 17 00:00:00 2001 From: Tymur Maryokhin Date: Sat, 29 Nov 2014 20:04:50 +0100 Subject: Moved non-conflicting models --- tests/models.py | 12 ------------ tests/test_generics.py | 34 +++++++++++++++++++++++++--------- 2 files changed, 25 insertions(+), 21 deletions(-) (limited to 'tests') diff --git a/tests/models.py b/tests/models.py index a0e0b3cc..456b0a0b 100644 --- a/tests/models.py +++ b/tests/models.py @@ -17,11 +17,6 @@ class BasicModel(RESTFrameworkModel): text = models.CharField(max_length=100, verbose_name=_("Text comes here"), help_text=_("Text description.")) -class SlugBasedModel(RESTFrameworkModel): - text = models.CharField(max_length=100) - slug = models.SlugField(max_length=32) - - class BaseFilterableItem(RESTFrameworkModel): text = models.CharField(max_length=100) @@ -34,13 +29,6 @@ class FilterableItem(BaseFilterableItem): date = models.DateField() -# Model for regression test for #285 -class Comment(RESTFrameworkModel): - email = models.EmailField() - content = models.CharField(max_length=200) - created = models.DateTimeField(auto_now_add=True) - - # Models for relations tests # ManyToMany class ManyToManyTarget(RESTFrameworkModel): diff --git a/tests/test_generics.py b/tests/test_generics.py index 2690fb47..b78584f0 100644 --- a/tests/test_generics.py +++ b/tests/test_generics.py @@ -6,12 +6,26 @@ from django.test import TestCase from django.utils import six from rest_framework import generics, renderers, serializers, status from rest_framework.test import APIRequestFactory -from tests.models import BasicModel, Comment, SlugBasedModel +from tests.models import BasicModel, RESTFrameworkModel from tests.models import ForeignKeySource, ForeignKeyTarget factory = APIRequestFactory() +# Models +class SlugBasedModel(RESTFrameworkModel): + text = models.CharField(max_length=100) + slug = models.SlugField(max_length=32) + + +# Model for regression test for #285 +class Comment(RESTFrameworkModel): + email = models.EmailField() + content = models.CharField(max_length=200) + created = models.DateTimeField(auto_now_add=True) + + +# Serializers class BasicSerializer(serializers.ModelSerializer): class Meta: model = BasicModel @@ -22,6 +36,15 @@ class ForeignKeySerializer(serializers.ModelSerializer): model = ForeignKeySource +class SlugSerializer(serializers.ModelSerializer): + slug = serializers.ReadOnlyField() + + class Meta: + model = SlugBasedModel + fields = ('text', 'slug') + + +# Views class RootView(generics.ListCreateAPIView): queryset = BasicModel.objects.all() serializer_class = BasicSerializer @@ -37,14 +60,6 @@ class FKInstanceView(generics.RetrieveUpdateDestroyAPIView): serializer_class = ForeignKeySerializer -class SlugSerializer(serializers.ModelSerializer): - slug = serializers.ReadOnlyField() - - class Meta: - model = SlugBasedModel - fields = ('text', 'slug') - - class SlugBasedInstanceView(InstanceView): """ A model with a slug-field. @@ -54,6 +69,7 @@ class SlugBasedInstanceView(InstanceView): lookup_field = 'slug' +# Tests class TestRootView(TestCase): def setUp(self): """ -- cgit v1.2.3 From e2ea98e8ab3192fa8d252d33cc03929fcf6ed02f Mon Sep 17 00:00:00 2001 From: Tymur Maryokhin Date: Sat, 29 Nov 2014 20:23:55 +0100 Subject: Fixed typos --- tests/test_generics.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'tests') diff --git a/tests/test_generics.py b/tests/test_generics.py index b78584f0..94023c30 100644 --- a/tests/test_generics.py +++ b/tests/test_generics.py @@ -143,13 +143,13 @@ class TestRootView(TestCase): self.assertEqual(created.text, 'foobar') -EXPECTED_QUERYS_FOR_PUT = 3 if django.VERSION < (1, 6) else 2 +EXPECTED_QUERIES_FOR_PUT = 3 if django.VERSION < (1, 6) else 2 class TestInstanceView(TestCase): def setUp(self): """ - Create 3 BasicModel intances. + Create 3 BasicModel instances. """ items = ['foo', 'bar', 'baz', 'filtered out'] for item in items: @@ -189,7 +189,7 @@ class TestInstanceView(TestCase): """ data = {'text': 'foobar'} request = factory.put('/1', data, format='json') - with self.assertNumQueries(EXPECTED_QUERYS_FOR_PUT): + with self.assertNumQueries(EXPECTED_QUERIES_FOR_PUT): response = self.view(request, pk='1').render() self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(dict(response.data), {'id': 1, 'text': 'foobar'}) @@ -203,7 +203,7 @@ class TestInstanceView(TestCase): data = {'text': 'foobar'} request = factory.patch('/1', data, format='json') - with self.assertNumQueries(EXPECTED_QUERYS_FOR_PUT): + with self.assertNumQueries(EXPECTED_QUERIES_FOR_PUT): response = self.view(request, pk=1).render() self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.data, {'id': 1, 'text': 'foobar'}) @@ -238,7 +238,7 @@ class TestInstanceView(TestCase): """ data = {'id': 999, 'text': 'foobar'} request = factory.put('/1', data, format='json') - with self.assertNumQueries(EXPECTED_QUERYS_FOR_PUT): + with self.assertNumQueries(EXPECTED_QUERIES_FOR_PUT): response = self.view(request, pk=1).render() self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.data, {'id': 1, 'text': 'foobar'}) @@ -304,9 +304,10 @@ class TestOverriddenGetObject(TestCase): Test cases for a RetrieveUpdateDestroyAPIView that does NOT use the queryset/model mechanism but instead overrides get_object() """ + def setUp(self): """ - Create 3 BasicModel intances. + Create 3 BasicModel instances. """ items = ['foo', 'bar', 'baz'] for item in items: @@ -379,11 +380,11 @@ class ClassB(models.Model): class ClassA(models.Model): name = models.CharField(max_length=255) - childs = models.ManyToManyField(ClassB, blank=True, null=True) + children = models.ManyToManyField(ClassB, blank=True, null=True) class ClassASerializer(serializers.ModelSerializer): - childs = serializers.PrimaryKeyRelatedField( + children = serializers.PrimaryKeyRelatedField( many=True, queryset=ClassB.objects.all() ) @@ -396,8 +397,8 @@ class ExampleView(generics.ListCreateAPIView): queryset = ClassA.objects.all() -class TestM2MBrowseableAPI(TestCase): - def test_m2m_in_browseable_api(self): +class TestM2MBrowsableAPI(TestCase): + def test_m2m_in_browsable_api(self): """ Test for particularly ugly regression with m2m in browsable API """ @@ -440,7 +441,6 @@ class DynamicSerializerView(generics.ListCreateAPIView): class TestFilterBackendAppliedToViews(TestCase): - def setUp(self): """ Create 3 BasicModel instances to filter on. -- cgit v1.2.3 From 53f52765fc90472a05cbeb34760b45f735a7332c Mon Sep 17 00:00:00 2001 From: BrickXu Date: Tue, 2 Dec 2014 12:55:34 +0800 Subject: Not allow to pass an empty actions to viewset.as_view(). Refs issue #2171 --- tests/test_viewsets.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 tests/test_viewsets.py (limited to 'tests') diff --git a/tests/test_viewsets.py b/tests/test_viewsets.py new file mode 100644 index 00000000..4d18a955 --- /dev/null +++ b/tests/test_viewsets.py @@ -0,0 +1,35 @@ +from django.test import TestCase +from rest_framework import status +from rest_framework.response import Response +from rest_framework.test import APIRequestFactory +from rest_framework.viewsets import GenericViewSet + + +factory = APIRequestFactory() + + +class BasicViewSet(GenericViewSet): + def list(self, request, *args, **kwargs): + return Response({'ACTION': 'LIST'}) + + +class InitializeViewSetsTestCase(TestCase): + def test_initialize_view_set_with_actions(self): + request = factory.get('/', '', content_type='application/json') + my_view = BasicViewSet.as_view(actions={ + 'get': 'list', + }) + + response = my_view(request) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response.data, {'ACTION': 'LIST'}) + + def test_initialize_view_set_with_empty_actions(self): + try: + BasicViewSet.as_view() + except TypeError as e: + self.assertEqual(str(e), "The `actions` argument must be provided " + "when calling `.as_view()` on a ViewSet. " + "For example `.as_view({'get': 'list'})`") + else: + self.fail("actions must not be empty.") -- cgit v1.2.3 From 76ac641fbd6c9d7dff5da3c551c3fd1ef7dedd2e Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Tue, 2 Dec 2014 13:04:49 +0000 Subject: Minor tweaks for helpful message on Model.objects.create() failure. --- tests/test_model_serializer.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'tests') diff --git a/tests/test_model_serializer.py b/tests/test_model_serializer.py index 90767dac..1bcd58e0 100644 --- a/tests/test_model_serializer.py +++ b/tests/test_model_serializer.py @@ -10,7 +10,6 @@ from django.core.validators import MaxValueValidator, MinValueValidator, MinLeng from django.db import models from django.test import TestCase from rest_framework import serializers -import pytest def dedent(blocktext): @@ -87,13 +86,10 @@ class TestModelSerializer(TestCase): 'non_model_field': 'bar', }) serializer.is_valid() - with pytest.raises(TypeError): + with self.assertRaises(TypeError) as excinfo: serializer.save() - - try: - serializer.save() - except TypeError as exc: - assert 'ModelSerializer' in str(exc) + msginitial = 'Got a `TypeError` when calling `OneFieldModel.objects.create()`.' + assert str(excinfo.exception).startswith(msginitial) class TestRegularFieldMappings(TestCase): -- cgit v1.2.3 From 0359e9250d34e18aef2db6216f24c130a4f51fce Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Tue, 2 Dec 2014 13:52:46 +0000 Subject: FileUploadParser. Raising StopFutureHandlers removes any handlers not yet run for the active set. Closes #2109. --- tests/test_parsers.py | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) (limited to 'tests') diff --git a/tests/test_parsers.py b/tests/test_parsers.py index 3f2672df..88eccef3 100644 --- a/tests/test_parsers.py +++ b/tests/test_parsers.py @@ -1,12 +1,13 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from rest_framework.compat import StringIO from django import forms from django.core.files.uploadhandler import MemoryFileUploadHandler from django.test import TestCase from django.utils import unittest from rest_framework.compat import etree +from rest_framework.compat import StringIO +from rest_framework.exceptions import ParseError from rest_framework.parsers import FormParser, FileUploadParser from rest_framework.parsers import XMLParser import datetime @@ -104,13 +105,40 @@ class TestFileUploadParser(TestCase): self.parser_context = {'request': request, 'kwargs': {}} def test_parse(self): - """ Make sure the `QueryDict` works OK """ + """ + Parse raw file upload. + """ parser = FileUploadParser() self.stream.seek(0) data_and_files = parser.parse(self.stream, None, self.parser_context) file_obj = data_and_files.files['file'] self.assertEqual(file_obj._size, 14) + def test_parse_missing_filename(self): + """ + Parse raw file upload when filename is missing. + """ + parser = FileUploadParser() + self.stream.seek(0) + self.parser_context['request'].META['HTTP_CONTENT_DISPOSITION'] = '' + with self.assertRaises(ParseError): + parser.parse(self.stream, None, self.parser_context) + + def test_parse_missing_filename_multiple_upload_handlers(self): + """ + Parse raw file upload with multiple handlers when filename is missing. + Regression test for #2109. + """ + parser = FileUploadParser() + self.stream.seek(0) + self.parser_context['request'].upload_handlers = ( + MemoryFileUploadHandler(), + MemoryFileUploadHandler() + ) + self.parser_context['request'].META['HTTP_CONTENT_DISPOSITION'] = '' + with self.assertRaises(ParseError): + parser.parse(self.stream, None, self.parser_context) + def test_get_filename(self): parser = FileUploadParser() filename = parser.get_filename(self.stream, None, self.parser_context) -- cgit v1.2.3 From 55528addf97c1d3ee24bb3332fb6dcb5496de158 Mon Sep 17 00:00:00 2001 From: Mark Hughes Date: Wed, 3 Dec 2014 12:30:15 +0000 Subject: Added test to show potential issue with UniqueValidator being added to the underlying Django model. --- tests/test_validators.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'tests') diff --git a/tests/test_validators.py b/tests/test_validators.py index 1df0641c..9226cc7a 100644 --- a/tests/test_validators.py +++ b/tests/test_validators.py @@ -20,6 +20,15 @@ class UniquenessSerializer(serializers.ModelSerializer): model = UniquenessModel +class AnotherUniquenessModel(models.Model): + code = models.IntegerField(unique=True) + + +class AnotherUniquenessSerializer(serializers.ModelSerializer): + class Meta: + model = AnotherUniquenessModel + + class TestUniquenessValidation(TestCase): def setUp(self): self.instance = UniquenessModel.objects.create(username='existing') @@ -51,6 +60,17 @@ class TestUniquenessValidation(TestCase): assert serializer.is_valid() assert serializer.validated_data == {'username': 'existing'} + def test_doesnt_pollute_model(self): + instance = AnotherUniquenessModel.objects.create(code='100') + serializer = AnotherUniquenessSerializer(instance) + self.assertEqual( + AnotherUniquenessModel._meta.get_field('code').validators, []) + + # Accessing data shouldn't effect validators on the model + serializer.data + self.assertEqual( + AnotherUniquenessModel._meta.get_field('code').validators, []) + # Tests for `UniqueTogetherValidator` # ----------------------------------- -- cgit v1.2.3 From 23fa6e54ce978055f7d4af5f5f99bc6f419f990b Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Wed, 3 Dec 2014 22:33:34 +0000 Subject: Escape \u2028 and \u2029 in JSON output. Closes #2169. --- tests/test_renderers.py | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'tests') diff --git a/tests/test_renderers.py b/tests/test_renderers.py index 416d7f22..61dd7c7a 100644 --- a/tests/test_renderers.py +++ b/tests/test_renderers.py @@ -384,6 +384,15 @@ class UnicodeJSONRendererTests(TestCase): content = renderer.render(obj, 'application/json') self.assertEqual(content, '{"countries":["United Kingdom","France","España"]}'.encode('utf-8')) + def test_u2028_u2029(self): + # The \u2028 and \u2029 characters should be escaped, + # even when the non-escaping unicode representation is used. + # Regression test for #2169 + obj = {'should_escape': '\u2028\u2029'} + renderer = JSONRenderer() + content = renderer.render(obj, 'application/json') + self.assertEqual(content, '{"should_escape":"\\u2028\\u2029"}'.encode('utf-8')) + class AsciiJSONRendererTests(TestCase): """ -- cgit v1.2.3 From 09e59f268619927dc22f15fed97c3ceac05ea306 Mon Sep 17 00:00:00 2001 From: Tymur Maryokhin Date: Thu, 4 Dec 2014 02:50:25 +0100 Subject: Removed custom python_2_unicode_compatible. Closes #2183 --- tests/test_description.py | 5 ++--- tests/test_relations_generic.py | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'tests') diff --git a/tests/test_description.py b/tests/test_description.py index 0675d209..6cd871ed 100644 --- a/tests/test_description.py +++ b/tests/test_description.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.test import TestCase +from django.utils.encoding import python_2_unicode_compatible from rest_framework.compat import apply_markdown, smart_text from rest_framework.views import APIView from .description import ViewWithNonASCIICharactersInDocstring @@ -107,6 +108,7 @@ class TestViewNamesAndDescriptions(TestCase): """ # use a mock object instead of gettext_lazy to ensure that we can't end # up with a test case string in our l10n catalog + @python_2_unicode_compatible class MockLazyStr(object): def __init__(self, string): self.s = string @@ -114,9 +116,6 @@ class TestViewNamesAndDescriptions(TestCase): def __str__(self): return self.s - def __unicode__(self): - return self.s - class MockView(APIView): __doc__ = MockLazyStr("a gettext string") diff --git a/tests/test_relations_generic.py b/tests/test_relations_generic.py index 380ad91d..b600b333 100644 --- a/tests/test_relations_generic.py +++ b/tests/test_relations_generic.py @@ -3,8 +3,8 @@ from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.generic import GenericRelation, GenericForeignKey from django.db import models from django.test import TestCase +from django.utils.encoding import python_2_unicode_compatible from rest_framework import serializers -from rest_framework.compat import python_2_unicode_compatible @python_2_unicode_compatible -- cgit v1.2.3 From d54c67d79d0f5661ef33d860efe80a4272e22b3e Mon Sep 17 00:00:00 2001 From: Tymur Maryokhin Date: Thu, 4 Dec 2014 03:11:42 +0100 Subject: Removed custom StringIO, force_text, smart_text compat --- tests/test_description.py | 4 ++-- tests/test_parsers.py | 2 +- tests/test_renderers.py | 4 +++- 3 files changed, 6 insertions(+), 4 deletions(-) (limited to 'tests') diff --git a/tests/test_description.py b/tests/test_description.py index 6cd871ed..78ce2350 100644 --- a/tests/test_description.py +++ b/tests/test_description.py @@ -2,8 +2,8 @@ from __future__ import unicode_literals from django.test import TestCase -from django.utils.encoding import python_2_unicode_compatible -from rest_framework.compat import apply_markdown, smart_text +from django.utils.encoding import python_2_unicode_compatible, smart_text +from rest_framework.compat import apply_markdown from rest_framework.views import APIView from .description import ViewWithNonASCIICharactersInDocstring from .description import UTF8_TEST_DOCSTRING diff --git a/tests/test_parsers.py b/tests/test_parsers.py index 88eccef3..d28d8bd4 100644 --- a/tests/test_parsers.py +++ b/tests/test_parsers.py @@ -5,8 +5,8 @@ from django import forms from django.core.files.uploadhandler import MemoryFileUploadHandler from django.test import TestCase from django.utils import unittest +from django.utils.six.moves import StringIO from rest_framework.compat import etree -from rest_framework.compat import StringIO from rest_framework.exceptions import ParseError from rest_framework.parsers import FormParser, FileUploadParser from rest_framework.parsers import XMLParser diff --git a/tests/test_renderers.py b/tests/test_renderers.py index 416d7f22..22eb5459 100644 --- a/tests/test_renderers.py +++ b/tests/test_renderers.py @@ -7,9 +7,11 @@ from django.core.cache import cache from django.db import models from django.test import TestCase from django.utils import six, unittest +from django.utils.six import BytesIO +from django.utils.six.moves import StringIO from django.utils.translation import ugettext_lazy as _ from rest_framework import status, permissions -from rest_framework.compat import yaml, etree, StringIO, BytesIO +from rest_framework.compat import yaml, etree from rest_framework.response import Response from rest_framework.views import APIView from rest_framework.renderers import BaseRenderer, JSONRenderer, YAMLRenderer, \ -- cgit v1.2.3 From d9930181ee157f51e2fcea33a3af5ea397647324 Mon Sep 17 00:00:00 2001 From: Tymur Maryokhin Date: Fri, 5 Dec 2014 00:29:28 +0100 Subject: Removed unused imports, pep8 fixes, typo fixes --- tests/test_multitable_inheritance.py | 2 +- tests/test_request.py | 2 +- tests/test_validators.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'tests') diff --git a/tests/test_multitable_inheritance.py b/tests/test_multitable_inheritance.py index ce1bf3ea..e1b40cc7 100644 --- a/tests/test_multitable_inheritance.py +++ b/tests/test_multitable_inheritance.py @@ -31,7 +31,7 @@ class AssociatedModelSerializer(serializers.ModelSerializer): # Tests -class IneritedModelSerializationTests(TestCase): +class InheritedModelSerializationTests(TestCase): def test_multitable_inherited_model_fields_as_expected(self): """ diff --git a/tests/test_request.py b/tests/test_request.py index 44afd243..7cf8c327 100644 --- a/tests/test_request.py +++ b/tests/test_request.py @@ -187,7 +187,7 @@ class MockView(APIView): if request.POST.get('example') is not None: return Response(status=status.HTTP_200_OK) - return Response(status=status.INTERNAL_SERVER_ERROR) + return Response(status=status.HTTP_500_INTERNAL_SERVER_ERROR) urlpatterns = patterns( '', diff --git a/tests/test_validators.py b/tests/test_validators.py index 1df0641c..5d92b284 100644 --- a/tests/test_validators.py +++ b/tests/test_validators.py @@ -148,7 +148,7 @@ class TestUniquenessTogetherValidation(TestCase): def test_ignore_excluded_fields(self): """ When model fields are not included in a serializer, then uniqueness - validtors should not be added for that field. + validators should not be added for that field. """ class ExcludedFieldSerializer(serializers.ModelSerializer): class Meta: -- cgit v1.2.3 From d68c61450440a522b08b64fdd21028cc739e6ead Mon Sep 17 00:00:00 2001 From: BrickXu Date: Fri, 5 Dec 2014 14:50:53 +0800 Subject: Add validation for fields & exclude type. --- tests/test_serializer_metaclass.py | 62 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 tests/test_serializer_metaclass.py (limited to 'tests') diff --git a/tests/test_serializer_metaclass.py b/tests/test_serializer_metaclass.py new file mode 100644 index 00000000..bd2fbed7 --- /dev/null +++ b/tests/test_serializer_metaclass.py @@ -0,0 +1,62 @@ +from django.test import TestCase +from rest_framework import serializers +from .models import BasicModel + + +class TestSerializerMetaClass(TestCase): + def setUp(self): + class FieldsSerializer(serializers.ModelSerializer): + text = serializers.CharField() + + class Meta: + model = BasicModel + fields = ('text') + + class ExcludeSerializer(serializers.ModelSerializer): + text = serializers.CharField() + + class Meta: + model = BasicModel + exclude = ('text') + + class FieldsAndExcludeSerializer(serializers.ModelSerializer): + text = serializers.CharField() + + class Meta: + model = BasicModel + fields = ('text',) + exclude = ('text',) + + self.fields_serializer = FieldsSerializer + self.exclude_serializer = ExcludeSerializer + self.faeSerializer = FieldsAndExcludeSerializer + + def test_meta_class_fields(self): + object = BasicModel(text="Hello World.") + serializer = self.fields_serializer(instance=object) + + with self.assertRaises(TypeError) as result: + serializer.data + + exception = result.exception + self.assertEqual(str(exception), "`fields` must be a list or tuple") + + def test_meta_class_exclude(self): + object = BasicModel(text="Hello World.") + serializer = self.exclude_serializer(instance=object) + + with self.assertRaises(TypeError) as result: + serializer.data + + exception = result.exception + self.assertEqual(str(exception), "`exclude` must be a list or tuple") + + def test_meta_class_fields_and_exclude(self): + object = BasicModel(text="Hello World.") + serializer = self.faeSerializer(instance=object) + + with self.assertRaises(AssertionError) as result: + serializer.data + + exception = result.exception + self.assertEqual(str(exception), "Cannot set both 'fields' and 'exclude'.") -- cgit v1.2.3 From 544967f36ed6e29819018428d48da00de74958b9 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Fri, 5 Dec 2014 14:15:58 +0000 Subject: Test tweaks --- tests/test_model_serializer.py | 50 ++++++++++++++++++++++++++++++ tests/test_serializer_metaclass.py | 62 -------------------------------------- 2 files changed, 50 insertions(+), 62 deletions(-) delete mode 100644 tests/test_serializer_metaclass.py (limited to 'tests') diff --git a/tests/test_model_serializer.py b/tests/test_model_serializer.py index 1bcd58e0..da79164a 100644 --- a/tests/test_model_serializer.py +++ b/tests/test_model_serializer.py @@ -559,3 +559,53 @@ class TestBulkCreate(TestCase): # Serializer returns correct data. assert serializer.data == data + + +class TestMetaClassModel(models.Model): + text = models.CharField(max_length=100) + + +class TestSerializerMetaClass(TestCase): + def test_meta_class_fields_option(self): + class ExampleSerializer(serializers.ModelSerializer): + class Meta: + model = TestMetaClassModel + fields = 'text' + + with self.assertRaises(TypeError) as result: + ExampleSerializer().fields + + exception = result.exception + assert str(exception).startswith( + "The `fields` option must be a list or tuple" + ) + + def test_meta_class_exclude_option(self): + class ExampleSerializer(serializers.ModelSerializer): + class Meta: + model = TestMetaClassModel + exclude = 'text' + + with self.assertRaises(TypeError) as result: + ExampleSerializer().fields + + exception = result.exception + assert str(exception).startswith( + "The `exclude` option must be a list or tuple" + ) + + def test_meta_class_fields_and_exclude_options(self): + class ExampleSerializer(serializers.ModelSerializer): + class Meta: + model = TestMetaClassModel + fields = ('text',) + exclude = ('text',) + + with self.assertRaises(AssertionError) as result: + ExampleSerializer().fields + + exception = result.exception + self.assertEqual( + str(exception), + "Cannot set both 'fields' and 'exclude'." + ) diff --git a/tests/test_serializer_metaclass.py b/tests/test_serializer_metaclass.py deleted file mode 100644 index bd2fbed7..00000000 --- a/tests/test_serializer_metaclass.py +++ /dev/null @@ -1,62 +0,0 @@ -from django.test import TestCase -from rest_framework import serializers -from .models import BasicModel - - -class TestSerializerMetaClass(TestCase): - def setUp(self): - class FieldsSerializer(serializers.ModelSerializer): - text = serializers.CharField() - - class Meta: - model = BasicModel - fields = ('text') - - class ExcludeSerializer(serializers.ModelSerializer): - text = serializers.CharField() - - class Meta: - model = BasicModel - exclude = ('text') - - class FieldsAndExcludeSerializer(serializers.ModelSerializer): - text = serializers.CharField() - - class Meta: - model = BasicModel - fields = ('text',) - exclude = ('text',) - - self.fields_serializer = FieldsSerializer - self.exclude_serializer = ExcludeSerializer - self.faeSerializer = FieldsAndExcludeSerializer - - def test_meta_class_fields(self): - object = BasicModel(text="Hello World.") - serializer = self.fields_serializer(instance=object) - - with self.assertRaises(TypeError) as result: - serializer.data - - exception = result.exception - self.assertEqual(str(exception), "`fields` must be a list or tuple") - - def test_meta_class_exclude(self): - object = BasicModel(text="Hello World.") - serializer = self.exclude_serializer(instance=object) - - with self.assertRaises(TypeError) as result: - serializer.data - - exception = result.exception - self.assertEqual(str(exception), "`exclude` must be a list or tuple") - - def test_meta_class_fields_and_exclude(self): - object = BasicModel(text="Hello World.") - serializer = self.faeSerializer(instance=object) - - with self.assertRaises(AssertionError) as result: - serializer.data - - exception = result.exception - self.assertEqual(str(exception), "Cannot set both 'fields' and 'exclude'.") -- cgit v1.2.3 From 0c0d65d23294d6976a3d7f9d47eb4b67440e908e Mon Sep 17 00:00:00 2001 From: Victor Cabral Date: Sun, 7 Dec 2014 15:05:17 -0500 Subject: Fixed unit test for auth login --- tests/test_authentication.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/test_authentication.py b/tests/test_authentication.py index 28c3a8b3..44837c4e 100644 --- a/tests/test_authentication.py +++ b/tests/test_authentication.py @@ -142,7 +142,7 @@ class SessionAuthTests(TestCase): cf. [#1810](https://github.com/tomchristie/django-rest-framework/pull/1810) """ response = self.csrf_client.get('/auth/login/') - self.assertContains(response, '') + self.assertContains(response, '') def test_post_form_session_auth_failing_csrf(self): """ -- cgit v1.2.3 From eee02a47d997bd4439fe5fbdc01979d8f372247a Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Mon, 8 Dec 2014 14:56:45 +0000 Subject: Added ListSerializer.validate(). Closes #2168. --- tests/test_serializer_lists.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'tests') diff --git a/tests/test_serializer_lists.py b/tests/test_serializer_lists.py index 640067e3..35b68ae7 100644 --- a/tests/test_serializer_lists.py +++ b/tests/test_serializer_lists.py @@ -272,3 +272,19 @@ class TestNestedListOfListsSerializer: serializer = self.Serializer(data=input_data) assert serializer.is_valid() assert serializer.validated_data == expected_output + + +class TestListSerializerClass: + """Tests for a custom list_serializer_class.""" + def test_list_serializer_class_validate(self): + class CustomListSerializer(serializers.ListSerializer): + def validate(self, attrs): + raise serializers.ValidationError('Non field error') + + class TestSerializer(serializers.Serializer): + class Meta: + list_serializer_class = CustomListSerializer + + serializer = TestSerializer(data=[], many=True) + assert not serializer.is_valid() + assert serializer.errors == {'non_field_errors': ['Non field error']} -- cgit v1.2.3 From afe7ed9333e37384f8ddc57e891da9632c8714c3 Mon Sep 17 00:00:00 2001 From: José Padilla Date: Tue, 9 Dec 2014 09:25:06 -0400 Subject: Add allow_blank for ChoiceField #2184 This makes a ChoiceField optional in HTML if model field has `blank=True` set.--- tests/test_fields.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'tests') diff --git a/tests/test_fields.py b/tests/test_fields.py index 13525632..3f4e65f2 100644 --- a/tests/test_fields.py +++ b/tests/test_fields.py @@ -804,6 +804,21 @@ class TestChoiceField(FieldValues): ] ) + def test_allow_blank(self): + """ + If `allow_blank=True` then '' is a valid input. + """ + field = serializers.ChoiceField( + allow_blank=True, + choices=[ + ('poor', 'Poor quality'), + ('medium', 'Medium quality'), + ('good', 'Good quality'), + ] + ) + output = field.run_validation('') + assert output is '' + class TestChoiceFieldWithType(FieldValues): """ -- cgit v1.2.3 From 720a37d3dedc501968bebaca3a339c72392b9c81 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Tue, 9 Dec 2014 17:28:56 +0000 Subject: Hyperlinked PK optimization. Closes #1872. --- tests/test_relations_hyperlink.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'tests') diff --git a/tests/test_relations_hyperlink.py b/tests/test_relations_hyperlink.py index b938e385..e741e99b 100644 --- a/tests/test_relations_hyperlink.py +++ b/tests/test_relations_hyperlink.py @@ -89,7 +89,8 @@ class HyperlinkedManyToManyTests(TestCase): {'url': 'http://testserver/manytomanysource/2/', 'name': 'source-2', 'targets': ['http://testserver/manytomanytarget/1/', 'http://testserver/manytomanytarget/2/']}, {'url': 'http://testserver/manytomanysource/3/', 'name': 'source-3', 'targets': ['http://testserver/manytomanytarget/1/', 'http://testserver/manytomanytarget/2/', 'http://testserver/manytomanytarget/3/']} ] - self.assertEqual(serializer.data, expected) + with self.assertNumQueries(4): + self.assertEqual(serializer.data, expected) def test_reverse_many_to_many_retrieve(self): queryset = ManyToManyTarget.objects.all() @@ -99,7 +100,8 @@ class HyperlinkedManyToManyTests(TestCase): {'url': 'http://testserver/manytomanytarget/2/', 'name': 'target-2', 'sources': ['http://testserver/manytomanysource/2/', 'http://testserver/manytomanysource/3/']}, {'url': 'http://testserver/manytomanytarget/3/', 'name': 'target-3', 'sources': ['http://testserver/manytomanysource/3/']} ] - self.assertEqual(serializer.data, expected) + with self.assertNumQueries(4): + self.assertEqual(serializer.data, expected) def test_many_to_many_update(self): data = {'url': 'http://testserver/manytomanysource/1/', 'name': 'source-1', 'targets': ['http://testserver/manytomanytarget/1/', 'http://testserver/manytomanytarget/2/', 'http://testserver/manytomanytarget/3/']} @@ -197,7 +199,8 @@ class HyperlinkedForeignKeyTests(TestCase): {'url': 'http://testserver/foreignkeysource/2/', 'name': 'source-2', 'target': 'http://testserver/foreignkeytarget/1/'}, {'url': 'http://testserver/foreignkeysource/3/', 'name': 'source-3', 'target': 'http://testserver/foreignkeytarget/1/'} ] - self.assertEqual(serializer.data, expected) + with self.assertNumQueries(1): + self.assertEqual(serializer.data, expected) def test_reverse_foreign_key_retrieve(self): queryset = ForeignKeyTarget.objects.all() @@ -206,7 +209,8 @@ class HyperlinkedForeignKeyTests(TestCase): {'url': 'http://testserver/foreignkeytarget/1/', 'name': 'target-1', 'sources': ['http://testserver/foreignkeysource/1/', 'http://testserver/foreignkeysource/2/', 'http://testserver/foreignkeysource/3/']}, {'url': 'http://testserver/foreignkeytarget/2/', 'name': 'target-2', 'sources': []}, ] - self.assertEqual(serializer.data, expected) + with self.assertNumQueries(3): + self.assertEqual(serializer.data, expected) def test_foreign_key_update(self): data = {'url': 'http://testserver/foreignkeysource/1/', 'name': 'source-1', 'target': 'http://testserver/foreignkeytarget/2/'} -- cgit v1.2.3 From ca7b1f6d5189398be8a0d24b1e01577281b1b187 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Wed, 10 Dec 2014 21:09:45 +0000 Subject: Optimizations play nicely with select_related, prefetch_related --- tests/test_relations_hyperlink.py | 6 ++++++ tests/test_relations_pk.py | 12 ++++++++++++ tests/test_relations_slug.py | 15 ++++++++++++++- 3 files changed, 32 insertions(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/test_relations_hyperlink.py b/tests/test_relations_hyperlink.py index e741e99b..f1b882ed 100644 --- a/tests/test_relations_hyperlink.py +++ b/tests/test_relations_hyperlink.py @@ -92,6 +92,12 @@ class HyperlinkedManyToManyTests(TestCase): with self.assertNumQueries(4): self.assertEqual(serializer.data, expected) + def test_many_to_many_retrieve_prefetch_related(self): + queryset = ManyToManySource.objects.all().prefetch_related('targets') + serializer = ManyToManySourceSerializer(queryset, many=True, context={'request': request}) + with self.assertNumQueries(2): + serializer.data + def test_reverse_many_to_many_retrieve(self): queryset = ManyToManyTarget.objects.all() serializer = ManyToManyTargetSerializer(queryset, many=True, context={'request': request}) diff --git a/tests/test_relations_pk.py b/tests/test_relations_pk.py index e95a877e..f872a8dc 100644 --- a/tests/test_relations_pk.py +++ b/tests/test_relations_pk.py @@ -71,6 +71,12 @@ class PKManyToManyTests(TestCase): with self.assertNumQueries(4): self.assertEqual(serializer.data, expected) + def test_many_to_many_retrieve_prefetch_related(self): + queryset = ManyToManySource.objects.all().prefetch_related('targets') + serializer = ManyToManySourceSerializer(queryset, many=True) + with self.assertNumQueries(2): + serializer.data + def test_reverse_many_to_many_retrieve(self): queryset = ManyToManyTarget.objects.all() serializer = ManyToManyTargetSerializer(queryset, many=True) @@ -188,6 +194,12 @@ class PKForeignKeyTests(TestCase): with self.assertNumQueries(3): self.assertEqual(serializer.data, expected) + def test_reverse_foreign_key_retrieve_prefetch_related(self): + queryset = ForeignKeyTarget.objects.all().prefetch_related('sources') + serializer = ForeignKeyTargetSerializer(queryset, many=True) + with self.assertNumQueries(2): + serializer.data + def test_foreign_key_update(self): data = {'id': 1, 'name': 'source-1', 'target': 2} instance = ForeignKeySource.objects.get(pk=1) diff --git a/tests/test_relations_slug.py b/tests/test_relations_slug.py index 7bac9046..cd2cb1ed 100644 --- a/tests/test_relations_slug.py +++ b/tests/test_relations_slug.py @@ -54,7 +54,14 @@ class SlugForeignKeyTests(TestCase): {'id': 2, 'name': 'source-2', 'target': 'target-1'}, {'id': 3, 'name': 'source-3', 'target': 'target-1'} ] - self.assertEqual(serializer.data, expected) + with self.assertNumQueries(4): + self.assertEqual(serializer.data, expected) + + def test_foreign_key_retrieve_select_related(self): + queryset = ForeignKeySource.objects.all().select_related('target') + serializer = ForeignKeySourceSerializer(queryset, many=True) + with self.assertNumQueries(1): + serializer.data def test_reverse_foreign_key_retrieve(self): queryset = ForeignKeyTarget.objects.all() @@ -65,6 +72,12 @@ class SlugForeignKeyTests(TestCase): ] self.assertEqual(serializer.data, expected) + def test_reverse_foreign_key_retrieve_prefetch_related(self): + queryset = ForeignKeyTarget.objects.all().prefetch_related('sources') + serializer = ForeignKeyTargetSerializer(queryset, many=True) + with self.assertNumQueries(2): + serializer.data + def test_foreign_key_update(self): data = {'id': 1, 'name': 'source-1', 'target': 'target-2'} instance = ForeignKeySource.objects.get(pk=1) -- cgit v1.2.3 From 78312d44d1e1a7f43daacd1614be2008eb77a0de Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Fri, 12 Dec 2014 13:13:08 +0000 Subject: Client.logout() also clears any force_authenticate --- tests/test_testing.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/test_testing.py b/tests/test_testing.py index 9fd5966e..f5d2cbcd 100644 --- a/tests/test_testing.py +++ b/tests/test_testing.py @@ -109,7 +109,7 @@ class TestAPITestClient(TestCase): def test_can_logout(self): """ - `logout()` reset stored credentials + `logout()` resets stored credentials """ self.client.credentials(HTTP_AUTHORIZATION='example') response = self.client.get('/view/') @@ -118,6 +118,18 @@ class TestAPITestClient(TestCase): response = self.client.get('/view/') self.assertEqual(response.data['auth'], b'') + def test_logout_resets_force_authenticate(self): + """ + `logout()` resets any `force_authenticate` + """ + user = User.objects.create_user('example', 'example@example.com', 'password') + self.client.force_authenticate(user) + response = self.client.get('/view/') + self.assertEqual(response.data['user'], 'example') + self.client.logout() + response = self.client.get('/view/') + self.assertEqual(response.data['user'], b'') + def test_follow_redirect(self): """ Follow redirect by setting follow argument. -- cgit v1.2.3 From e3b16c8bc631d5be599776c483ee0488cef9c288 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Fri, 12 Dec 2014 13:16:18 +0000 Subject: Python 3 test fix --- tests/test_testing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/test_testing.py b/tests/test_testing.py index f5d2cbcd..6fce8464 100644 --- a/tests/test_testing.py +++ b/tests/test_testing.py @@ -128,7 +128,7 @@ class TestAPITestClient(TestCase): self.assertEqual(response.data['user'], 'example') self.client.logout() response = self.client.get('/view/') - self.assertEqual(response.data['user'], b'') + self.assertEqual(response.data['user'], '') def test_follow_redirect(self): """ -- cgit v1.2.3 From 8825b258caa0c51d6dcdb3529dc433c75a76339d Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Fri, 12 Dec 2014 13:22:24 +0000 Subject: Clean up import ordering --- tests/test_testing.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'tests') diff --git a/tests/test_testing.py b/tests/test_testing.py index 6fce8464..87d2b61f 100644 --- a/tests/test_testing.py +++ b/tests/test_testing.py @@ -1,15 +1,13 @@ -# -- coding: utf-8 -- - +# encoding: utf-8 from __future__ import unicode_literals from django.conf.urls import patterns, url -from io import BytesIO - from django.contrib.auth.models import User from django.shortcuts import redirect from django.test import TestCase from rest_framework.decorators import api_view from rest_framework.response import Response from rest_framework.test import APIClient, APIRequestFactory, force_authenticate +from io import BytesIO @api_view(['GET', 'POST']) -- cgit v1.2.3