aboutsummaryrefslogtreecommitdiffstats
path: root/tests/test_validation.py
blob: c4506e7e90a77a08ab90809da095b54747622135 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
from __future__ import unicode_literals
from django.core.validators import MaxValueValidator
from django.core.exceptions import ValidationError
from django.db import models
from django.test import TestCase
from rest_framework import generics, serializers, status
from rest_framework.test import APIRequestFactory

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']})


# 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_native(value)
        except ValidationError:
            self.fail("Value %s does not validate" % str(value))

    # def test_nested_choices(self):
    #     """
    #     Make sure a nested value for choices works as expected.
    #     """
    #     f = serializers.ChoiceField(choices=self.CHOICES_NESTED)
    #     value = self.CHOICES_NESTED[0][1][0][0]
    #     try:
    #         f.to_native(value)
    #     except ValidationError:
    #         self.fail("Value %s does not validate" % str(value))