diff options
Diffstat (limited to 'tests/test_validation.py')
| -rw-r--r-- | tests/test_validation.py | 183 | 
1 files changed, 183 insertions, 0 deletions
| diff --git a/tests/test_validation.py b/tests/test_validation.py new file mode 100644 index 00000000..4234efd3 --- /dev/null +++ b/tests/test_validation.py @@ -0,0 +1,183 @@ +from __future__ import unicode_literals +from django.core.validators import RegexValidator, MaxValueValidator +from django.db import models +from django.test import TestCase +from rest_framework import generics, serializers, status +from rest_framework.test import APIRequestFactory +import re + +factory = APIRequestFactory() + + +# Regression for #666 + +class ValidationModel(models.Model): +    blank_validated_field = models.CharField(max_length=255) + + +class ValidationModelSerializer(serializers.ModelSerializer): +    class Meta: +        model = ValidationModel +        fields = ('blank_validated_field',) +        read_only_fields = ('blank_validated_field',) + + +class UpdateValidationModel(generics.RetrieveUpdateDestroyAPIView): +    queryset = ValidationModel.objects.all() +    serializer_class = ValidationModelSerializer + + +# Regression for #653 + +class ShouldValidateModel(models.Model): +    should_validate_field = models.CharField(max_length=255) + + +class ShouldValidateModelSerializer(serializers.ModelSerializer): +    renamed = serializers.CharField(source='should_validate_field', required=False) + +    def validate_renamed(self, value): +        if len(value) < 3: +            raise serializers.ValidationError('Minimum 3 characters.') +        return value + +    class Meta: +        model = ShouldValidateModel +        fields = ('renamed',) + + +class TestPreSaveValidationExclusionsSerializer(TestCase): +    def test_renamed_fields_are_model_validated(self): +        """ +        Ensure fields with 'source' applied do get still get model validation. +        """ +        # We've set `required=False` on the serializer, but the model +        # does not have `blank=True`, so this serializer should not validate. +        serializer = ShouldValidateModelSerializer(data={'renamed': ''}) +        self.assertEqual(serializer.is_valid(), False) +        self.assertIn('renamed', serializer.errors) +        self.assertNotIn('should_validate_field', serializer.errors) + + +class TestCustomValidationMethods(TestCase): +    def test_custom_validation_method_is_executed(self): +        serializer = ShouldValidateModelSerializer(data={'renamed': 'fo'}) +        self.assertFalse(serializer.is_valid()) +        self.assertIn('renamed', serializer.errors) + +    def test_custom_validation_method_passing(self): +        serializer = ShouldValidateModelSerializer(data={'renamed': 'foo'}) +        self.assertTrue(serializer.is_valid()) + + +class ValidationSerializer(serializers.Serializer): +    foo = serializers.CharField() + +    def validate_foo(self, attrs, source): +        raise serializers.ValidationError("foo invalid") + +    def validate(self, attrs): +        raise serializers.ValidationError("serializer invalid") + + +class TestAvoidValidation(TestCase): +    """ +    If serializer was initialized with invalid data (None or non dict-like), it +    should avoid validation layer (validate_<field> and validate methods) +    """ +    def test_serializer_errors_has_only_invalid_data_error(self): +        serializer = ValidationSerializer(data='invalid data') +        self.assertFalse(serializer.is_valid()) +        self.assertDictEqual(serializer.errors, { +            'non_field_errors': [ +                'Invalid data. Expected a dictionary, but got %s.' % type('').__name__ +            ] +        }) + + +# regression tests for issue: 1493 + +class ValidationMaxValueValidatorModel(models.Model): +    number_value = models.PositiveIntegerField(validators=[MaxValueValidator(100)]) + + +class ValidationMaxValueValidatorModelSerializer(serializers.ModelSerializer): +    class Meta: +        model = ValidationMaxValueValidatorModel + + +class UpdateMaxValueValidationModel(generics.RetrieveUpdateDestroyAPIView): +    queryset = ValidationMaxValueValidatorModel.objects.all() +    serializer_class = ValidationMaxValueValidatorModelSerializer + + +class TestMaxValueValidatorValidation(TestCase): + +    def test_max_value_validation_serializer_success(self): +        serializer = ValidationMaxValueValidatorModelSerializer(data={'number_value': 99}) +        self.assertTrue(serializer.is_valid()) + +    def test_max_value_validation_serializer_fails(self): +        serializer = ValidationMaxValueValidatorModelSerializer(data={'number_value': 101}) +        self.assertFalse(serializer.is_valid()) +        self.assertDictEqual({'number_value': ['Ensure this value is less than or equal to 100.']}, serializer.errors) + +    def test_max_value_validation_success(self): +        obj = ValidationMaxValueValidatorModel.objects.create(number_value=100) +        request = factory.patch('/{0}'.format(obj.pk), {'number_value': 98}, format='json') +        view = UpdateMaxValueValidationModel().as_view() +        response = view(request, pk=obj.pk).render() +        self.assertEqual(response.status_code, status.HTTP_200_OK) + +    def test_max_value_validation_fail(self): +        obj = ValidationMaxValueValidatorModel.objects.create(number_value=100) +        request = factory.patch('/{0}'.format(obj.pk), {'number_value': 101}, format='json') +        view = UpdateMaxValueValidationModel().as_view() +        response = view(request, pk=obj.pk).render() +        self.assertEqual(response.content, b'{"number_value":["Ensure this value is less than or equal to 100."]}') +        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + +class TestChoiceFieldChoicesValidate(TestCase): +    CHOICES = [ +        (0, 'Small'), +        (1, 'Medium'), +        (2, 'Large'), +    ] + +    CHOICES_NESTED = [ +        ('Category', ( +            (1, 'First'), +            (2, 'Second'), +            (3, 'Third'), +        )), +        (4, 'Fourth'), +    ] + +    def test_choices(self): +        """ +        Make sure a value for choices works as expected. +        """ +        f = serializers.ChoiceField(choices=self.CHOICES) +        value = self.CHOICES[0][0] +        try: +            f.to_internal_value(value) +        except serializers.ValidationError: +            self.fail("Value %s does not validate" % str(value)) + + +class RegexSerializer(serializers.Serializer): +    pin = serializers.CharField( +        validators=[RegexValidator(regex=re.compile('^[0-9]{4,6}$'), +                                   message='A PIN is 4-6 digits')]) + +expected_repr = """ +RegexSerializer(): +    pin = CharField(validators=[<django.core.validators.RegexValidator object>]) +""".strip() + + +class TestRegexSerializer(TestCase): +    def test_regex_repr(self): +        serializer_repr = repr(RegexSerializer()) +        assert serializer_repr == expected_repr | 
