1from __future__ import unicode_literals
2
3from django.test import TestCase, override_settings
4
5from django_countries import countries
6from django_countries.fields import Country
7from django_countries.tests.models import Person, MultiCountry
8from django_countries.tests.custom_countries import FantasyCountries
9from django_countries.serializers import CountryFieldMixin
10
11from rest_framework.test import APIRequestFactory
12from rest_framework import serializers, views
13
14
15def countries_display(countries):
16    """
17    Convert Countries into a DRF-OPTIONS formatted dict.
18    """
19    return [{'display_name': v, 'value': k} for (k, v) in countries]
20
21
22class PersonSerializer(CountryFieldMixin, serializers.ModelSerializer):
23
24    class Meta:
25        model = Person
26        fields = (
27            'name', 'country', 'other_country', 'favourite_country',
28            'fantasy_country')
29        extra_kwargs = {
30            'other_country': {'country_dict': True},
31        }
32
33
34class MultiCountrySerializer(CountryFieldMixin, serializers.ModelSerializer):
35
36    class Meta:
37        model = MultiCountry
38        fields = ('countries',)
39
40
41class TestDRF(TestCase):
42
43    def test_serialize(self):
44        person = Person(name='Chris Beaven', country='NZ')
45        serializer = PersonSerializer(person)
46        self.assertEqual(
47            serializer.data,
48            {
49                'name': 'Chris Beaven',
50                'country': 'NZ',
51                'other_country': '',
52                'favourite_country': 'NZ',
53                'fantasy_country': '',
54            })
55
56    def test_serialize_country_dict(self):
57        person = Person(name='Chris Beaven', other_country='AU')
58        serializer = PersonSerializer(person)
59        self.assertEqual(
60            serializer.data,
61            {
62                'name': 'Chris Beaven',
63                'country': '',
64                'other_country': {'code': 'AU', 'name': 'Australia'},
65                'favourite_country': 'NZ',
66                'fantasy_country': '',
67            })
68
69    def test_deserialize(self):
70        serializer = PersonSerializer(data={
71            'name': 'Tester',
72            'country': 'US',
73            'fantasy_country': 'NV',
74        })
75        self.assertTrue(serializer.is_valid())
76        self.assertEqual(serializer.validated_data['country'], 'US')
77
78    def test_deserialize_country_dict(self):
79        serializer = PersonSerializer(data={
80            'name': 'Tester',
81            'country': {'code': 'GB', 'name': 'Anything'},
82            'fantasy_country': 'NV'
83        })
84        self.assertTrue(serializer.is_valid())
85        self.assertEqual(serializer.validated_data['country'], 'GB')
86
87    def test_deserialize_by_name(self):
88        serializer = PersonSerializer(data={
89            'name': 'Chris',
90            'country': 'New Zealand',
91            'fantasy_country': 'Neverland',
92        })
93        self.assertTrue(serializer.is_valid())
94        self.assertEqual(serializer.validated_data['country'], 'NZ')
95        self.assertEqual(serializer.validated_data['fantasy_country'], 'NV')
96
97    def test_deserialize_invalid(self):
98        serializer = PersonSerializer(data={
99            'name': 'Chris',
100            'country': 'No Such Zealand',
101            'fantasy_country': 'Neverland',
102        })
103        self.assertFalse(serializer.is_valid())
104        self.assertTrue(
105            serializer.errors['country'],
106            ['"No Such Zealand" is not a valid choice.'])
107
108    def test_multi_serialize(self):
109        mc = MultiCountry(countries='NZ,AU')
110        serializer = MultiCountrySerializer(mc)
111        self.assertEqual(
112            serializer.data,
113            {
114                'countries': ['NZ', 'AU']
115            })
116
117    def test_multi_serialize_empty(self):
118        mc = MultiCountry(countries='')
119        serializer = MultiCountrySerializer(mc)
120        self.assertEqual(
121            serializer.data,
122            {
123                'countries': []
124            })
125
126    def test_multi_deserialize(self):
127        serializer = MultiCountrySerializer(data={
128            'countries': ['NZ', 'AU']
129        })
130        self.assertTrue(serializer.is_valid())
131        self.assertEqual(serializer.validated_data['countries'], ['NZ', 'AU'])
132
133    def test_multi_deserialize_by_name(self):
134        serializer = MultiCountrySerializer(data={
135            'countries': ['New Zealand', 'Australia']
136        })
137        self.assertTrue(serializer.is_valid())
138        self.assertEqual(serializer.validated_data['countries'], ['NZ', 'AU'])
139
140    def test_multi_deserialize_invalid(self):
141        serializer = MultiCountrySerializer(data={
142            'countries': ['NZ', 'BAD', 'AU']
143        })
144        self.assertFalse(serializer.is_valid())
145        self.assertEqual(
146            serializer.errors['countries'],
147            ['"BAD" is not a valid choice.'])
148
149    def test_multi_deserialize_save(self):
150        serializer = MultiCountrySerializer(data={
151            'countries': ['NZ', 'AU']
152        })
153        self.assertTrue(serializer.is_valid())
154        saved = serializer.save()
155        loaded = MultiCountry.objects.get(pk=saved.pk)
156        self.assertEqual(loaded.countries, [Country('NZ'), Country('AU')])
157
158
159class TestDRFMetadata(TestCase):
160    """
161    Tests against the DRF OPTIONS API metadata endpoint.
162    """
163
164    def test_actions(self):
165
166        class ExampleView(views.APIView):
167            """Example view."""
168            def post(self, request):
169                pass  # pragma: nocover
170
171            def get_serializer(self):
172                return PersonSerializer()
173
174        def _choices(response, key):
175            """Helper method for unpacking response JSON."""
176            return response.data['actions']['POST'][key]['choices']
177
178        view = ExampleView.as_view()
179
180        factory = APIRequestFactory()
181        request = factory.options('/')
182        response = view(request=request)
183        country_choices = _choices(response, 'country')
184        fantasy_choices_en = _choices(response, 'fantasy_country')
185        self.assertEqual(response.status_code, 200)
186        self.assertEqual(country_choices, countries_display(countries))
187        self.assertEqual(
188            fantasy_choices_en, countries_display(FantasyCountries()))
189
190        with override_settings(LANGUAGE_CODE='fr'):
191            response = view(request=request)
192            fantasy_choices_fr = _choices(response, 'fantasy_country')
193            self.assertNotEqual(fantasy_choices_en, fantasy_choices_fr)
194