1# -*- coding: utf-8 -*-
2from __future__ import unicode_literals
3
4from parameterized import parameterized, param
5from operator import attrgetter
6import six
7import regex as re
8
9from dateparser.languages.loader import default_loader
10from tests import BaseTestCase
11
12
13class TestLoading(BaseTestCase):
14    def setUp(self):
15        super(TestLoading, self).setUp()
16        self.locale_generator = NotImplemented
17
18    @classmethod
19    def setUpClass(cls):
20        cls.data_loader = default_loader
21        cls.data_loader._loaded_locales = {}
22        cls.data_loader._loaded_languages = {}
23
24    @parameterized.expand([
25        param(given_languages=['es', 'fr', 'en'],
26              given_locales=None,
27              given_region=None,
28              loaded_languages=['en', 'es', 'fr'],
29              loaded_locales=['en', 'es', 'fr'],
30              expected_locales=['es', 'fr', 'en']),
31
32        param(given_languages=None,
33              given_locales=['fr-BF', 'ar-SO', 'asa'],
34              given_region=None,
35              loaded_languages=['en', 'es', 'fr', 'ar', 'asa'],
36              loaded_locales=['en', 'es', 'fr', 'fr-BF', 'ar-SO', 'asa'],
37              expected_locales=['fr-BF', 'ar-SO', 'asa']),
38
39        param(given_languages=None,
40              given_locales=['nl-CW', 'so-KE', 'sr-Latn-XK', 'zgh'],
41              given_region=None,
42              loaded_languages=['en', 'es', 'fr', 'ar', 'asa',
43                                'nl', 'so', 'sr-Latn', 'zgh'],
44              loaded_locales=['en', 'es', 'fr', 'fr-BF', 'ar-SO', 'asa',
45                              'nl-CW', 'so-KE', 'sr-Latn-XK', 'zgh'],
46              expected_locales=['nl-CW', 'so-KE', 'sr-Latn-XK', 'zgh']),
47
48        param(given_languages=['pt', 'zh-Hant', 'zh-Hans'],
49              given_locales=None,
50              given_region='MO',
51              loaded_languages=['en', 'es', 'fr', 'ar', 'asa', 'nl', 'so',
52                                'sr-Latn', 'zgh', 'pt', 'zh-Hant', 'zh-Hans'],
53              loaded_locales=['en', 'es', 'fr', 'fr-BF', 'ar-SO', 'asa',
54                              'nl-CW', 'so-KE', 'sr-Latn-XK', 'zgh',
55                              'pt-MO', 'zh-Hant-MO', 'zh-Hans-MO'],
56              expected_locales=['pt-MO', 'zh-Hant-MO', 'zh-Hans-MO']),
57
58        param(given_languages=['pt', 'he'],
59              given_locales=['ru-UA', 'ckb-IR', 'sq-XK'],
60              given_region='MO',
61              loaded_languages=['en', 'es', 'fr', 'ar', 'asa', 'nl', 'so',
62                                'sr-Latn', 'zgh', 'pt', 'zh-Hant', 'zh-Hans',
63                                'ru', 'ckb', 'sq'],
64              loaded_locales=['en', 'es', 'fr', 'fr-BF', 'ar-SO', 'asa', 'nl-CW',
65                              'so-KE', 'sr-Latn-XK', 'zgh', 'pt-MO', 'zh-Hant-MO',
66                              'zh-Hans-MO', 'ru-UA', 'ckb-IR', 'sq-XK'],
67              expected_locales=['ru-UA', 'ckb-IR', 'sq-XK']),
68
69        param(given_languages=['da', 'ja'],
70              given_locales=['shi-Latn', 'teo-KE', 'ewo', 'vun'],
71              given_region='AO',
72              loaded_languages=['en', 'es', 'fr', 'ar', 'asa', 'nl', 'so',
73                                'sr-Latn', 'zgh', 'pt', 'zh-Hant', 'zh-Hans',
74                                'ru', 'ckb', 'sq', 'shi-Latn', 'teo', 'ewo', 'vun'],
75              loaded_locales=['en', 'es', 'fr', 'fr-BF', 'ar-SO', 'asa', 'nl-CW',
76                              'so-KE', 'sr-Latn-XK', 'zgh', 'pt-MO', 'zh-Hant-MO',
77                              'zh-Hans-MO', 'ru-UA', 'ckb-IR', 'sq-XK', 'shi-Latn',
78                              'teo-KE', 'ewo', 'vun'],
79              expected_locales=['shi-Latn', 'teo-KE', 'ewo', 'vun']),
80    ])
81    def test_loading(self, given_languages, given_locales, given_region,
82                     loaded_languages, loaded_locales, expected_locales):
83        self.load_data(languages=given_languages, locales=given_locales, region=given_region)
84        self.then_locales_are_yielded_in_order(expected_locales)
85        self.then_loaded_languages_are(loaded_languages)
86        self.then_loaded_locales_are(loaded_locales)
87
88    def load_data(self, languages, locales, region):
89        self.locale_generator = self.data_loader.get_locales(
90            languages=languages, locales=locales, region=region, use_given_order=True)
91
92    def then_loaded_languages_are(self, loaded_languages):
93        six.assertCountEqual(self, loaded_languages, self.data_loader._loaded_languages.keys())
94
95    def then_loaded_locales_are(self, loaded_locales):
96        six.assertCountEqual(self, loaded_locales, self.data_loader._loaded_locales.keys())
97
98    def then_locales_are_yielded_in_order(self, expected_locales):
99        self.assertEqual(list(map(attrgetter('shortname'),
100                         list(self.locale_generator))), expected_locales)
101
102
103class TestLocaleDataLoader(BaseTestCase):
104    UNKNOWN_LANGUAGES_EXCEPTION_RE = re.compile("Unknown language\(s\): (.+)")
105    UNKNOWN_LOCALES_EXCEPTION_RE = re.compile("Unknown locale\(s\): (.+)")
106
107    def setUp(self):
108        super(TestLocaleDataLoader, self).setUp()
109        self.data_loader = default_loader
110        self.data_loader._loaded_languages = {}
111        self.data_loader._loaded_locales = {}
112
113    @parameterized.expand([
114        param(given_locales=['es-MX', 'ar-EG', 'fr-DJ']),
115        param(given_locales=['pt-MO', 'ru-KZ', 'es-CU']),
116        param(given_locales=['zh-Hans-HK', 'en-VG', 'my']),
117        param(given_locales=['tl', 'nl-SX', 'de-BE']),
118    ])
119    def test_loading_with_given_order(self, given_locales):
120        self.load_data(given_locales, use_given_order=True)
121        self.then_locales_are_yielded_in_order(given_locales)
122
123    @parameterized.expand([
124        param(given_locales=['os-RU', 'ln-CF', 'ee-TG'],
125              expected_locales=['ee-TG', 'ln-CF', 'os-RU']),
126        param(given_locales=['khq', 'ff-CM'],
127              expected_locales=['ff-CM', 'khq']),
128        param(given_locales=['en-CC', 'fr-BE', 'ar-KW'],
129              expected_locales=['en-CC', 'ar-KW', 'fr-BE']),
130    ])
131    def test_loading_without_given_order(self, given_locales, expected_locales):
132        self.load_data(given_locales, use_given_order=False)
133        self.then_locales_are_yielded_in_order(expected_locales)
134
135    @parameterized.expand([
136        param(given_locales=['sw-KE', 'ru-UA', 'he']),
137        param(given_locales=['de-IT', 'ta-MY', 'pa-Arab']),
138        param(given_locales=['bn-IN', 'pt-ST', 'ko-KP', 'ta']),
139        param(given_locales=['fr-NE', 'ar-SY']),
140    ])
141    def test_get_locale_map_with_given_order(self, given_locales):
142        self.given_locale_map(locales=given_locales, use_given_order=True)
143        self.then_locale_map_in_order(given_locales)
144
145    @parameterized.expand([
146        param(given_locales=['en-FJ', 'pt-CV', 'fr-RW'],
147              expected_locales=['en-FJ', 'fr-RW', 'pt-CV']),
148        param(given_locales=['pt-AO', 'hi', 'zh-Hans-SG', 'vi'],
149              expected_locales=['zh-Hans-SG', 'hi', 'pt-AO', 'vi']),
150        param(given_locales=['gsw-FR', 'es-BZ', 'ca-IT', 'qu-EC'],
151              expected_locales=['es-BZ', 'qu-EC', 'ca-IT', 'gsw-FR']),
152    ])
153    def test_get_locale_map_without_given_order(self, given_locales, expected_locales):
154        self.given_locale_map(locales=given_locales, use_given_order=False)
155        self.then_locale_map_in_order(expected_locales)
156
157    @parameterized.expand([
158        param(given_languages=['es', 'ar-001', 'xx'],
159              unknown_languages=['ar-001', 'xx']),
160        param(given_languages=['sr-Latn', 'sq', 'ii-Latn'],
161              unknown_languages=['ii-Latn']),
162        param(given_languages=['vol', 'bc'],
163              unknown_languages=['vol', 'bc']),
164    ])
165    def test_error_raised_for_unknown_languages(self, given_languages, unknown_languages):
166        self.given_locale_map(languages=given_languages)
167        self.then_error_for_unknown_languages_raised(unknown_languages)
168
169    @parameterized.expand([
170        param(given_locales=['es-AB', 'ar-001', 'fr-DJ'],
171              unknown_locales=['es-AB', 'ar-001']),
172        param(given_locales=['ru-MD', 'my-MY', 'zz'],
173              unknown_locales=['my-MY', 'zz']),
174        param(given_locales=['nl-SX', 'be-BE', 'ca-FR'],
175              unknown_locales=['be-BE']),
176    ])
177    def test_error_raised_for_unknown_locales(self, given_locales, unknown_locales):
178        self.given_locale_map(locales=given_locales)
179        self.then_error_for_unknown_locales_raised(unknown_locales)
180
181    @parameterized.expand([
182        param(given_locales=['en-TK', 'en-TO', 'zh']),
183        param(given_locales=['es-PY', 'es-IC', 'ja', 'es-DO']),
184        param(given_locales=['ca-TA', 'ca', 'fr']),
185    ])
186    def test_error_raised_for_conflicting_locales(self, given_locales):
187        self.given_locale_map(locales=given_locales)
188        self.then_error_was_raised(
189            ValueError, "Locales should not have same language and different region")
190
191    @parameterized.expand([
192        param(given_locales=['en-TK', 'en-TO', 'zh']),
193        param(given_locales=['es-PY', 'es-IC', 'ja', 'es-DO']),
194        param(given_locales=['af-NA', 'da', 'af']),
195    ])
196    def test_conflicting_locales_load_if_allow_conflicting_locales(self, given_locales):
197        self.load_data(given_locales, use_given_order=True, allow_conflicting_locales=True)
198        self.then_locales_are_yielded_in_order(given_locales)
199
200    def load_data(self, given_locales, use_given_order=False, allow_conflicting_locales=False):
201        self.locale_generator = self.data_loader.get_locales(
202            locales=given_locales, use_given_order=use_given_order,
203            allow_conflicting_locales=allow_conflicting_locales)
204
205    def given_locale_map(self, languages=None, locales=None, use_given_order=True):
206        try:
207            self.locale_map = self.data_loader.get_locale_map(
208                languages=languages, locales=locales, use_given_order=use_given_order)
209        except Exception as error:
210            self.error = error
211
212    def then_locales_are_yielded_in_order(self, expected_locales):
213        self.assertEqual(list(map(attrgetter('shortname'),
214                         list(self.locale_generator))), expected_locales)
215
216    def then_locale_map_in_order(self, expected_locales):
217        self.assertEqual(list(self.locale_map.keys()), expected_locales)
218
219    def then_error_for_unknown_languages_raised(self, unknown_languages):
220        self.assertIsInstance(self.error, ValueError)
221        match = self.UNKNOWN_LANGUAGES_EXCEPTION_RE.match(str(self.error))
222        self.assertTrue(match)
223        languages = match.group(1).split(", ")
224        six.assertCountEqual(self, languages, [repr(l) for l in unknown_languages])
225
226    def then_error_for_unknown_locales_raised(self, unknown_locales):
227        self.assertIsInstance(self.error, ValueError)
228        match = self.UNKNOWN_LOCALES_EXCEPTION_RE.match(str(self.error))
229        self.assertTrue(match)
230        locales = match.group(1).split(", ")
231        six.assertCountEqual(self, locales, [repr(l) for l in unknown_locales])
232