From 79abb8147d97f7d39cbb022789597bfd6499dbf9 Mon Sep 17 00:00:00 2001 From: Simon Charette Date: Wed, 30 Mar 2016 15:44:35 -0400 Subject: [PATCH] Added regression tests for field metadata. --- tests/test_metadata.py | 314 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 310 insertions(+), 4 deletions(-) diff --git a/tests/test_metadata.py b/tests/test_metadata.py index 6819f1504..97e61cbf2 100644 --- a/tests/test_metadata.py +++ b/tests/test_metadata.py @@ -1,8 +1,13 @@ from __future__ import unicode_literals +import functools +import os + +from django import forms from django.core.validators import MaxValueValidator, MinValueValidator from django.db import models from django.test import TestCase +from django.utils.translation import ugettext, ugettext_lazy as _ from rest_framework import ( exceptions, metadata, serializers, status, versioning, views @@ -261,10 +266,311 @@ class TestMetadata: view = ExampleView.as_view(versioning_class=scheme) view(request=request) - def test_null_boolean_field_info_type(self): - options = metadata.SimpleMetadata() - field_info = options.get_field_info(serializers.NullBooleanField()) - assert field_info['type'] == 'boolean' + +class TestFieldMetadata(TestCase): + simple_metadata = metadata.SimpleMetadata() + + def get_field_metadata(self, field): + return self.simple_metadata.get_field_info(field) + + def get_serializer_metadata(self, serializer): + return self.simple_metadata.get_serializer_info(serializer) + + def assertMetadataEqual(self, field, expected_metadata): + if isinstance(field, serializers.BaseSerializer): + metadata = self.get_serializer_metadata(field) + else: + metadata = self.get_field_metadata(field) + self.assertEqual(metadata, expected_metadata) + + def test_field(self, field_factory=serializers.Field, expected_type='field', **expected_metadata): + field = field_factory() + self.assertMetadataEqual(field, dict({ + 'type': expected_type, + 'required': True, + 'read_only': False, + }, **expected_metadata)) + field = field_factory( + required=False, + label=_('label'), + help_text=_('help text'), + ) + self.assertMetadataEqual(field, dict({ + 'type': expected_type, + 'required': False, + 'read_only': False, + 'label': ugettext('label'), + 'help_text': ugettext('help text'), + }, **expected_metadata)) + # Empty string label and help_text should be ignored. + field = field_factory( + label='', + help_text='', + ) + self.assertMetadataEqual(field, dict({ + 'type': expected_type, + 'required': True, + 'read_only': False, + }, **expected_metadata)) + + def test_read_only_field(self, field_factory=serializers.ReadOnlyField, expected_type='field', + **expected_metadata): + field = field_factory(read_only=True) + self.assertMetadataEqual(field, dict({ + 'type': expected_type, + 'required': False, + 'read_only': True, + }, **expected_metadata)) + + def test_boolean_field(self): + self.test_field(serializers.BooleanField, 'boolean') + self.test_read_only_field(serializers.BooleanField, 'boolean') + + def test_null_boolean_field(self): + self.test_field(serializers.NullBooleanField, 'boolean') + self.test_read_only_field(serializers.NullBooleanField, 'boolean') + + def test_char_field(self, field_factory=serializers.CharField, expected_type='string'): + self.test_field(field_factory, expected_type) + self.test_read_only_field(field_factory, expected_type) + field = field_factory(min_length=0, max_length=0) + self.assertMetadataEqual(field, { + 'type': expected_type, + 'required': True, + 'read_only': False, + 'min_length': 0, + 'max_length': 0, + }) + + def test_email_field(self): + self.test_char_field(serializers.EmailField, 'email') + + def test_url_field(self): + self.test_char_field(serializers.URLField, 'url') + + def test_slug_field(self): + self.test_char_field(serializers.SlugField, 'slug') + + def test_regex_field(self): + self.test_char_field(functools.partial(serializers.RegexField, regex='regex'), 'regex') + + def test_ip_address_field(self): + self.test_char_field(serializers.IPAddressField) + + def test_uuid_field(self): + self.test_field(serializers.UUIDField) + self.test_read_only_field(serializers.UUIDField) + + def test_integer_field(self, field_factory=serializers.IntegerField, expected_type='integer'): + self.test_field(field_factory, expected_type) + self.test_read_only_field(field_factory, expected_type) + field = field_factory(min_value=0, max_value=0) + self.assertMetadataEqual(field, { + 'type': expected_type, + 'required': True, + 'read_only': False, + 'min_value': 0, + 'max_value': 0, + }) + + def test_float_field(self): + self.test_integer_field(serializers.FloatField, 'float') + + def test_decimal_field(self): + decimal_field_factory = functools.partial(serializers.DecimalField, max_digits=5, decimal_places=2) + self.test_integer_field(decimal_field_factory, 'decimal') + + def test_date_time_field(self): + self.test_field(serializers.DateTimeField, 'datetime') + self.test_read_only_field(serializers.DateTimeField, 'datetime') + + def test_date_field(self): + self.test_field(serializers.DateField, 'date') + self.test_read_only_field(serializers.DateField, 'date') + + def test_time_field(self): + self.test_field(serializers.TimeField, 'time') + self.test_read_only_field(serializers.TimeField, 'time') + + def test_duration_field(self): + self.test_field(serializers.DurationField) + self.test_read_only_field(serializers.DurationField) + + def test_choice_field(self, field_factory=serializers.ChoiceField, expected_type='choice'): + choice_field_factory = functools.partial(field_factory, choices=[]) + self.test_field(choice_field_factory, expected_type, choices=[]) + self.test_read_only_field(choice_field_factory, expected_type) + field = field_factory([('value', _('label'))]) + self.assertMetadataEqual(field, { + 'type': expected_type, + 'required': True, + 'read_only': False, + 'choices': [{'value': 'value', 'display_name': ugettext('label')}] + }) + + def test_multiple_choice_field(self): + self.test_choice_field(serializers.MultipleChoiceField, 'multiple choice') + + def test_file_path_field(self): + # We have to special case FilePathField as it deals differently with + # the `required` argument by changing the choices values to include + # an empty string choice instead. + path = os.path.dirname(__file__) + choices = [ + {'value': value, 'display_name': display_name} + for value, display_name in forms.FilePathField(path, required=False).choices + ] + file_path_field_factory = functools.partial(serializers.FilePathField, path=path) + field = file_path_field_factory() + self.assertMetadataEqual(field, { + 'type': 'choice', + 'required': True, + 'read_only': False, + 'choices': choices, + }) + field = file_path_field_factory( + required=False, + label=_('label'), + help_text=_('help text'), + ) + self.assertMetadataEqual(field, { + 'type': 'choice', + 'required': True, + 'read_only': False, + 'label': ugettext('label'), + 'help_text': ugettext('help text'), + 'choices': choices, + }) + # Empty string label and help_text should be ignored. + field = file_path_field_factory( + label='', + help_text='', + ) + self.assertMetadataEqual(field, { + 'type': 'choice', + 'required': True, + 'read_only': False, + 'choices': choices, + }) + self.test_read_only_field(file_path_field_factory, 'choice') + + def test_file_field(self, field_factory=serializers.FileField, expected_type='file upload'): + self.test_field(field_factory, expected_type) + self.test_read_only_field(field_factory, expected_type) + field = field_factory(max_length=0) + self.assertMetadataEqual(field, { + 'type': expected_type, + 'required': True, + 'read_only': False, + 'max_length': 0, + }) + + def test_image_field(self): + self.test_file_field(serializers.ImageField, expected_type='image upload') + + def test_list_field(self): + def list_field_factory(*args, **kwargs): + return serializers.ListField(child=serializers.Field(), *args, **kwargs) + child_metadata = self.get_field_metadata(serializers.Field()) + self.test_field(list_field_factory, 'list', child=child_metadata) + self.test_read_only_field(list_field_factory, 'list', child=child_metadata) + + def test_dict_field(self): + def dict_field_factory(*args, **kwargs): + return serializers.DictField(child=serializers.Field(), *args, **kwargs) + child_metadata = self.get_field_metadata(serializers.Field()) + self.test_field(dict_field_factory, 'nested object', child=child_metadata) + self.test_read_only_field(dict_field_factory, 'nested object', child=child_metadata) + + def test_json_field(self): + self.test_field(serializers.JSONField) + self.test_read_only_field(serializers.JSONField) + + def test_serializer_method_field(self): + self.test_read_only_field(functools.partial(serializers.SerializerMethodField, method_name='method')) + + def test_model_field(self): + model_field_factory = functools.partial(serializers.ModelField, model_field=models.Field()) + self.test_field(model_field_factory) + self.test_read_only_field(model_field_factory) + + def test_serializer(self): + class TestSerializer(serializers.Serializer): + field = serializers.Field() + + serializer = TestSerializer() + self.assertMetadataEqual(serializer, { + 'field': { + 'type': 'field', + 'required': True, + 'read_only': False, + 'label': 'Field', + } + }) + + list_serializer = TestSerializer(many=True) + self.assertMetadataEqual(list_serializer, { + 'field': { + 'type': 'field', + 'required': True, + 'read_only': False, + 'label': 'Field', + } + }) + + def test_nested_serializer(self): + class TestNestedSerializer(serializers.Serializer): + field = serializers.Field() + + class TestSerializer(serializers.Serializer): + serializer = TestNestedSerializer( + label=_('label'), help_text=_('help text'), required=True + ) + + serializer = TestSerializer() + self.assertMetadataEqual(serializer, { + 'serializer': { + 'type': 'nested object', + 'required': True, + 'read_only': False, + 'label': ugettext('label'), + 'help_text': ugettext('help text'), + 'children': { + 'field': { + 'type': 'field', + 'required': True, + 'read_only': False, + 'label': 'Field', + }, + }, + }, + }) + + class TestListSerializer(serializers.Serializer): + serializer = TestNestedSerializer(many=True) + + list_serializer = TestListSerializer() + self.assertMetadataEqual(list_serializer, { + 'serializer': { + 'type': 'field', + 'required': True, + 'read_only': False, + 'label': 'Serializer', + 'child': { + 'type': 'nested object', + 'required': True, + 'read_only': False, + 'children': { + 'field': { + 'type': 'field', + 'required': True, + 'read_only': False, + 'label': 'Field', + }, + }, + }, + }, + }) class TestModelSerializerMetadata(TestCase):