blob: a88d34b2c5f924da1bbb55fdb7cb59d685778dce [file] [log] [blame]
Benjamin Petersonbec087f2009-03-26 21:10:30 +00001from test.test_support import run_unittest, verbose
Stefan Krah01a3ee82011-08-02 01:17:48 +02002from platform import linux_distribution
Antoine Pitrouba54eda2008-07-25 20:40:19 +00003import unittest
Martin v. Löwis88ad12a2001-04-13 08:09:50 +00004import locale
Guido van Rossumfc349862001-04-15 13:15:56 +00005import sys
Antoine Pitrouba54eda2008-07-25 20:40:19 +00006import codecs
Martin v. Löwis88ad12a2001-04-13 08:09:50 +00007
Martin v. Löwis88ad12a2001-04-13 08:09:50 +00008
Antoine Pitrou524f4132008-07-26 10:29:43 +00009enUS_locale = None
10
11def get_enUS_locale():
12 global enUS_locale
13 if sys.platform == 'darwin':
Ronald Oussoren37805e52010-04-18 13:47:49 +000014 import os
15 tlocs = ("en_US.UTF-8", "en_US.ISO8859-1", "en_US")
16 if int(os.uname()[2].split('.')[0]) < 10:
17 # The locale test work fine on OSX 10.6, I (ronaldoussoren)
18 # haven't had time yet to verify if tests work on OSX 10.5
19 # (10.4 is known to be bad)
20 raise unittest.SkipTest("Locale support on MacOSX is minimal")
Antoine Pitrou524f4132008-07-26 10:29:43 +000021 if sys.platform.startswith("win"):
22 tlocs = ("En", "English")
23 else:
24 tlocs = ("en_US.UTF-8", "en_US.US-ASCII", "en_US")
25 oldlocale = locale.setlocale(locale.LC_NUMERIC)
26 for tloc in tlocs:
27 try:
28 locale.setlocale(locale.LC_NUMERIC, tloc)
29 except locale.Error:
30 continue
31 break
32 else:
Benjamin Petersonbec087f2009-03-26 21:10:30 +000033 raise unittest.SkipTest(
Antoine Pitrou524f4132008-07-26 10:29:43 +000034 "Test locale not supported (tried %s)" % (', '.join(tlocs)))
35 enUS_locale = tloc
36 locale.setlocale(locale.LC_NUMERIC, oldlocale)
37
38
Antoine Pitrouba54eda2008-07-25 20:40:19 +000039class BaseLocalizedTest(unittest.TestCase):
40 #
41 # Base class for tests using a real locale
42 #
Guido van Rossumfc349862001-04-15 13:15:56 +000043
Antoine Pitrouba54eda2008-07-25 20:40:19 +000044 def setUp(self):
Antoine Pitrouba54eda2008-07-25 20:40:19 +000045 self.oldlocale = locale.setlocale(self.locale_type)
Antoine Pitrou524f4132008-07-26 10:29:43 +000046 locale.setlocale(self.locale_type, enUS_locale)
Martin v. Löwis88ad12a2001-04-13 08:09:50 +000047 if verbose:
Antoine Pitrou524f4132008-07-26 10:29:43 +000048 print "testing with \"%s\"..." % enUS_locale,
Martin v. Löwis88ad12a2001-04-13 08:09:50 +000049
Antoine Pitrouba54eda2008-07-25 20:40:19 +000050 def tearDown(self):
51 locale.setlocale(self.locale_type, self.oldlocale)
Hye-Shik Changb5047fd2004-08-04 06:33:51 +000052
53
Antoine Pitrouba54eda2008-07-25 20:40:19 +000054class BaseCookedTest(unittest.TestCase):
55 #
56 # Base class for tests using cooked localeconv() values
57 #
Hye-Shik Changb5047fd2004-08-04 06:33:51 +000058
Antoine Pitrouba54eda2008-07-25 20:40:19 +000059 def setUp(self):
60 locale._override_localeconv = self.cooked_values
Georg Brandl278fc502008-07-19 12:46:12 +000061
Antoine Pitrouba54eda2008-07-25 20:40:19 +000062 def tearDown(self):
63 locale._override_localeconv = {}
64
65
66class CCookedTest(BaseCookedTest):
67 # A cooked "C" locale
68
69 cooked_values = {
70 'currency_symbol': '',
71 'decimal_point': '.',
72 'frac_digits': 127,
73 'grouping': [],
74 'int_curr_symbol': '',
75 'int_frac_digits': 127,
76 'mon_decimal_point': '',
77 'mon_grouping': [],
78 'mon_thousands_sep': '',
79 'n_cs_precedes': 127,
80 'n_sep_by_space': 127,
81 'n_sign_posn': 127,
82 'negative_sign': '',
83 'p_cs_precedes': 127,
84 'p_sep_by_space': 127,
85 'p_sign_posn': 127,
86 'positive_sign': '',
87 'thousands_sep': ''
88 }
89
90class EnUSCookedTest(BaseCookedTest):
91 # A cooked "en_US" locale
92
93 cooked_values = {
94 'currency_symbol': '$',
95 'decimal_point': '.',
96 'frac_digits': 2,
97 'grouping': [3, 3, 0],
98 'int_curr_symbol': 'USD ',
99 'int_frac_digits': 2,
100 'mon_decimal_point': '.',
101 'mon_grouping': [3, 3, 0],
102 'mon_thousands_sep': ',',
103 'n_cs_precedes': 1,
104 'n_sep_by_space': 0,
105 'n_sign_posn': 1,
106 'negative_sign': '-',
107 'p_cs_precedes': 1,
108 'p_sep_by_space': 0,
109 'p_sign_posn': 1,
110 'positive_sign': '',
111 'thousands_sep': ','
112 }
113
114
Antoine Pitroufeeafff2009-03-14 00:07:21 +0000115class FrFRCookedTest(BaseCookedTest):
116 # A cooked "fr_FR" locale with a space character as decimal separator
117 # and a non-ASCII currency symbol.
118
119 cooked_values = {
120 'currency_symbol': '\xe2\x82\xac',
121 'decimal_point': ',',
122 'frac_digits': 2,
123 'grouping': [3, 3, 0],
124 'int_curr_symbol': 'EUR ',
125 'int_frac_digits': 2,
126 'mon_decimal_point': ',',
127 'mon_grouping': [3, 3, 0],
128 'mon_thousands_sep': ' ',
129 'n_cs_precedes': 0,
130 'n_sep_by_space': 1,
131 'n_sign_posn': 1,
132 'negative_sign': '-',
133 'p_cs_precedes': 0,
134 'p_sep_by_space': 1,
135 'p_sign_posn': 1,
136 'positive_sign': '',
137 'thousands_sep': ' '
138 }
139
140
Antoine Pitrouba54eda2008-07-25 20:40:19 +0000141class BaseFormattingTest(object):
142 #
143 # Utility functions for formatting tests
144 #
145
146 def _test_formatfunc(self, format, value, out, func, **format_opts):
147 self.assertEqual(
148 func(format, value, **format_opts), out)
149
150 def _test_format(self, format, value, out, **format_opts):
151 self._test_formatfunc(format, value, out,
152 func=locale.format, **format_opts)
153
154 def _test_format_string(self, format, value, out, **format_opts):
155 self._test_formatfunc(format, value, out,
156 func=locale.format_string, **format_opts)
157
158 def _test_currency(self, value, out, **format_opts):
159 self.assertEqual(locale.currency(value, **format_opts), out)
160
161
162class EnUSNumberFormatting(BaseFormattingTest):
Antoine Pitrou36897e12008-07-26 13:49:13 +0000163 # XXX there is a grouping + padding bug when the thousands separator
164 # is empty but the grouping array contains values (e.g. Solaris 10)
Antoine Pitrouba54eda2008-07-25 20:40:19 +0000165
166 def setUp(self):
Antoine Pitrouba54eda2008-07-25 20:40:19 +0000167 self.sep = locale.localeconv()['thousands_sep']
168
169 def test_grouping(self):
170 self._test_format("%f", 1024, grouping=1, out='1%s024.000000' % self.sep)
171 self._test_format("%f", 102, grouping=1, out='102.000000')
172 self._test_format("%f", -42, grouping=1, out='-42.000000')
173 self._test_format("%+f", -42, grouping=1, out='-42.000000')
174
175 def test_grouping_and_padding(self):
176 self._test_format("%20.f", -42, grouping=1, out='-42'.rjust(20))
Antoine Pitrou36897e12008-07-26 13:49:13 +0000177 if self.sep:
Antoine Pitrou524f4132008-07-26 10:29:43 +0000178 self._test_format("%+10.f", -4200, grouping=1,
179 out=('-4%s200' % self.sep).rjust(10))
180 self._test_format("%-10.f", -4200, grouping=1,
181 out=('-4%s200' % self.sep).ljust(10))
Antoine Pitrouba54eda2008-07-25 20:40:19 +0000182
183 def test_integer_grouping(self):
184 self._test_format("%d", 4200, grouping=True, out='4%s200' % self.sep)
185 self._test_format("%+d", 4200, grouping=True, out='+4%s200' % self.sep)
186 self._test_format("%+d", -4200, grouping=True, out='-4%s200' % self.sep)
187
Antoine Pitroufeeafff2009-03-14 00:07:21 +0000188 def test_integer_grouping_and_padding(self):
189 self._test_format("%10d", 4200, grouping=True,
190 out=('4%s200' % self.sep).rjust(10))
191 self._test_format("%-10d", -4200, grouping=True,
192 out=('-4%s200' % self.sep).ljust(10))
193
Antoine Pitrouba54eda2008-07-25 20:40:19 +0000194 def test_simple(self):
195 self._test_format("%f", 1024, grouping=0, out='1024.000000')
196 self._test_format("%f", 102, grouping=0, out='102.000000')
197 self._test_format("%f", -42, grouping=0, out='-42.000000')
198 self._test_format("%+f", -42, grouping=0, out='-42.000000')
199
200 def test_padding(self):
201 self._test_format("%20.f", -42, grouping=0, out='-42'.rjust(20))
202 self._test_format("%+10.f", -4200, grouping=0, out='-4200'.rjust(10))
203 self._test_format("%-10.f", 4200, grouping=0, out='4200'.ljust(10))
204
205 def test_complex_formatting(self):
206 # Spaces in formatting string
207 self._test_format_string("One million is %i", 1000000, grouping=1,
208 out='One million is 1%s000%s000' % (self.sep, self.sep))
209 self._test_format_string("One million is %i", 1000000, grouping=1,
210 out='One million is 1%s000%s000' % (self.sep, self.sep))
211 # Dots in formatting string
212 self._test_format_string(".%f.", 1000.0, out='.1000.000000.')
213 # Padding
Antoine Pitrou36897e12008-07-26 13:49:13 +0000214 if self.sep:
215 self._test_format_string("--> %10.2f", 4200, grouping=1,
216 out='--> ' + ('4%s200.00' % self.sep).rjust(10))
Antoine Pitrouba54eda2008-07-25 20:40:19 +0000217 # Asterisk formats
218 self._test_format_string("%10.*f", (2, 1000), grouping=0,
219 out='1000.00'.rjust(10))
Antoine Pitrou36897e12008-07-26 13:49:13 +0000220 if self.sep:
221 self._test_format_string("%*.*f", (10, 2, 1000), grouping=1,
222 out=('1%s000.00' % self.sep).rjust(10))
Antoine Pitrouba54eda2008-07-25 20:40:19 +0000223 # Test more-in-one
Antoine Pitrou36897e12008-07-26 13:49:13 +0000224 if self.sep:
225 self._test_format_string("int %i float %.2f str %s",
226 (1000, 1000.0, 'str'), grouping=1,
227 out='int 1%s000 float 1%s000.00 str str' %
228 (self.sep, self.sep))
Antoine Pitrouba54eda2008-07-25 20:40:19 +0000229
230
R. David Murraya83da352009-04-01 03:21:43 +0000231class TestFormatPatternArg(unittest.TestCase):
232 # Test handling of pattern argument of format
233
234 def test_onlyOnePattern(self):
235 # Issue 2522: accept exactly one % pattern, and no extra chars.
236 self.assertRaises(ValueError, locale.format, "%f\n", 'foo')
237 self.assertRaises(ValueError, locale.format, "%f\r", 'foo')
238 self.assertRaises(ValueError, locale.format, "%f\r\n", 'foo')
239 self.assertRaises(ValueError, locale.format, " %f", 'foo')
240 self.assertRaises(ValueError, locale.format, "%fg", 'foo')
241 self.assertRaises(ValueError, locale.format, "%^g", 'foo')
R. David Murray3939dcd2010-04-26 21:17:14 +0000242 self.assertRaises(ValueError, locale.format, "%f%%", 'foo')
243
244
245class TestLocaleFormatString(unittest.TestCase):
246 """General tests on locale.format_string"""
247
248 def test_percent_escape(self):
249 self.assertEqual(locale.format_string('%f%%', 1.0), '%f%%' % 1.0)
250 self.assertEqual(locale.format_string('%d %f%%d', (1, 1.0)),
251 '%d %f%%d' % (1, 1.0))
252 self.assertEqual(locale.format_string('%(foo)s %%d', {'foo': 'bar'}),
253 ('%(foo)s %%d' % {'foo': 'bar'}))
254
255 def test_mapping(self):
256 self.assertEqual(locale.format_string('%(foo)s bing.', {'foo': 'bar'}),
257 ('%(foo)s bing.' % {'foo': 'bar'}))
258 self.assertEqual(locale.format_string('%(foo)s', {'foo': 'bar'}),
259 ('%(foo)s' % {'foo': 'bar'}))
260
R. David Murraya83da352009-04-01 03:21:43 +0000261
262
Antoine Pitrouba54eda2008-07-25 20:40:19 +0000263class TestNumberFormatting(BaseLocalizedTest, EnUSNumberFormatting):
264 # Test number formatting with a real English locale.
265
266 locale_type = locale.LC_NUMERIC
267
268 def setUp(self):
269 BaseLocalizedTest.setUp(self)
270 EnUSNumberFormatting.setUp(self)
271
272
273class TestEnUSNumberFormatting(EnUSCookedTest, EnUSNumberFormatting):
274 # Test number formatting with a cooked "en_US" locale.
275
276 def setUp(self):
277 EnUSCookedTest.setUp(self)
278 EnUSNumberFormatting.setUp(self)
279
280 def test_currency(self):
281 self._test_currency(50000, "$50000.00")
282 self._test_currency(50000, "$50,000.00", grouping=True)
283 self._test_currency(50000, "USD 50,000.00",
284 grouping=True, international=True)
285
286
287class TestCNumberFormatting(CCookedTest, BaseFormattingTest):
288 # Test number formatting with a cooked "C" locale.
289
290 def test_grouping(self):
291 self._test_format("%.2f", 12345.67, grouping=True, out='12345.67')
292
293 def test_grouping_and_padding(self):
294 self._test_format("%9.2f", 12345.67, grouping=True, out=' 12345.67')
295
296
Antoine Pitroufeeafff2009-03-14 00:07:21 +0000297class TestFrFRNumberFormatting(FrFRCookedTest, BaseFormattingTest):
298 # Test number formatting with a cooked "fr_FR" locale.
299
300 def test_decimal_point(self):
301 self._test_format("%.2f", 12345.67, out='12345,67')
302
303 def test_grouping(self):
304 self._test_format("%.2f", 345.67, grouping=True, out='345,67')
305 self._test_format("%.2f", 12345.67, grouping=True, out='12 345,67')
306
307 def test_grouping_and_padding(self):
308 self._test_format("%6.2f", 345.67, grouping=True, out='345,67')
309 self._test_format("%7.2f", 345.67, grouping=True, out=' 345,67')
310 self._test_format("%8.2f", 12345.67, grouping=True, out='12 345,67')
311 self._test_format("%9.2f", 12345.67, grouping=True, out='12 345,67')
312 self._test_format("%10.2f", 12345.67, grouping=True, out=' 12 345,67')
313 self._test_format("%-6.2f", 345.67, grouping=True, out='345,67')
314 self._test_format("%-7.2f", 345.67, grouping=True, out='345,67 ')
315 self._test_format("%-8.2f", 12345.67, grouping=True, out='12 345,67')
316 self._test_format("%-9.2f", 12345.67, grouping=True, out='12 345,67')
317 self._test_format("%-10.2f", 12345.67, grouping=True, out='12 345,67 ')
318
319 def test_integer_grouping(self):
320 self._test_format("%d", 200, grouping=True, out='200')
321 self._test_format("%d", 4200, grouping=True, out='4 200')
322
323 def test_integer_grouping_and_padding(self):
324 self._test_format("%4d", 4200, grouping=True, out='4 200')
325 self._test_format("%5d", 4200, grouping=True, out='4 200')
326 self._test_format("%10d", 4200, grouping=True, out='4 200'.rjust(10))
327 self._test_format("%-4d", 4200, grouping=True, out='4 200')
328 self._test_format("%-5d", 4200, grouping=True, out='4 200')
329 self._test_format("%-10d", 4200, grouping=True, out='4 200'.ljust(10))
330
331 def test_currency(self):
332 euro = u'\u20ac'.encode('utf-8')
333 self._test_currency(50000, "50000,00 " + euro)
334 self._test_currency(50000, "50 000,00 " + euro, grouping=True)
335 # XXX is the trailing space a bug?
336 self._test_currency(50000, "50 000,00 EUR ",
337 grouping=True, international=True)
338
339
Antoine Pitrou6327e842008-07-26 11:56:37 +0000340class TestStringMethods(BaseLocalizedTest):
341 locale_type = locale.LC_CTYPE
Antoine Pitrouba54eda2008-07-25 20:40:19 +0000342
Antoine Pitrou6327e842008-07-26 11:56:37 +0000343 if sys.platform != 'sunos5' and not sys.platform.startswith("win"):
Antoine Pitrou524f4132008-07-26 10:29:43 +0000344 # Test BSD Rune locale's bug for isctype functions.
Antoine Pitrouba54eda2008-07-25 20:40:19 +0000345
Antoine Pitrou524f4132008-07-26 10:29:43 +0000346 def test_isspace(self):
347 self.assertEqual('\x20'.isspace(), True)
Antoine Pitrouba54eda2008-07-25 20:40:19 +0000348 self.assertEqual('\xa0'.isspace(), False)
Antoine Pitrou524f4132008-07-26 10:29:43 +0000349 self.assertEqual('\xa1'.isspace(), False)
Antoine Pitrouba54eda2008-07-25 20:40:19 +0000350
Antoine Pitrou524f4132008-07-26 10:29:43 +0000351 def test_isalpha(self):
352 self.assertEqual('\xc0'.isalpha(), False)
Antoine Pitrouba54eda2008-07-25 20:40:19 +0000353
Antoine Pitrou524f4132008-07-26 10:29:43 +0000354 def test_isalnum(self):
355 self.assertEqual('\xc0'.isalnum(), False)
Antoine Pitrouba54eda2008-07-25 20:40:19 +0000356
Antoine Pitrou524f4132008-07-26 10:29:43 +0000357 def test_isupper(self):
358 self.assertEqual('\xc0'.isupper(), False)
Antoine Pitrouba54eda2008-07-25 20:40:19 +0000359
Antoine Pitrou524f4132008-07-26 10:29:43 +0000360 def test_islower(self):
361 self.assertEqual('\xc0'.islower(), False)
Antoine Pitrouba54eda2008-07-25 20:40:19 +0000362
Antoine Pitrou524f4132008-07-26 10:29:43 +0000363 def test_lower(self):
364 self.assertEqual('\xcc\x85'.lower(), '\xcc\x85')
Antoine Pitrouba54eda2008-07-25 20:40:19 +0000365
Antoine Pitrou524f4132008-07-26 10:29:43 +0000366 def test_upper(self):
367 self.assertEqual('\xed\x95\xa0'.upper(), '\xed\x95\xa0')
Antoine Pitrouba54eda2008-07-25 20:40:19 +0000368
Antoine Pitrou524f4132008-07-26 10:29:43 +0000369 def test_strip(self):
370 self.assertEqual('\xed\x95\xa0'.strip(), '\xed\x95\xa0')
Antoine Pitrouba54eda2008-07-25 20:40:19 +0000371
Antoine Pitrou524f4132008-07-26 10:29:43 +0000372 def test_split(self):
373 self.assertEqual('\xec\xa0\xbc'.split(), ['\xec\xa0\xbc'])
Antoine Pitrouba54eda2008-07-25 20:40:19 +0000374
375
376class TestMiscellaneous(unittest.TestCase):
377 def test_getpreferredencoding(self):
378 # Invoke getpreferredencoding to make sure it does not cause exceptions.
379 enc = locale.getpreferredencoding()
380 if enc:
381 # If encoding non-empty, make sure it is valid
382 codecs.lookup(enc)
383
384 if hasattr(locale, "strcoll"):
385 def test_strcoll_3303(self):
386 # test crasher from bug #3303
387 self.assertRaises(TypeError, locale.strcoll, u"a", None)
388
Amaury Forgeot d'Arcd7288712009-12-01 21:51:04 +0000389 def test_setlocale_category(self):
390 locale.setlocale(locale.LC_ALL)
391 locale.setlocale(locale.LC_TIME)
392 locale.setlocale(locale.LC_CTYPE)
393 locale.setlocale(locale.LC_COLLATE)
394 locale.setlocale(locale.LC_MONETARY)
395 locale.setlocale(locale.LC_NUMERIC)
396
397 # crasher from bug #7419
398 self.assertRaises(locale.Error, locale.setlocale, 12345)
399
Stefan Krah01a3ee82011-08-02 01:17:48 +0200400 @unittest.skipIf(linux_distribution()[0] == 'Fedora', "Fedora setlocale() "
401 "bug: https://bugzilla.redhat.com/show_bug.cgi?id=726536")
Antoine Pitrou4cfae022011-07-24 02:51:01 +0200402 def test_getsetlocale_issue1813(self):
403 # Issue #1813: setting and getting the locale under a Turkish locale
404 oldlocale = locale.getlocale()
405 self.addCleanup(locale.setlocale, locale.LC_CTYPE, oldlocale)
406 try:
407 locale.setlocale(locale.LC_CTYPE, 'tr_TR')
408 except locale.Error:
409 # Unsupported locale on this system
410 self.skipTest('test needs Turkish locale')
411 loc = locale.getlocale()
412 locale.setlocale(locale.LC_CTYPE, loc)
413 self.assertEqual(loc, locale.getlocale())
414
Barry Warsawedfba822011-08-15 19:17:12 -0400415 def test_normalize_issue12752(self):
416 # Issue #1813 caused a regression where locale.normalize() would no
417 # longer accept unicode strings.
418 self.assertEqual(locale.normalize(u'en_US'), 'en_US.ISO8859-1')
419
Antoine Pitrouba54eda2008-07-25 20:40:19 +0000420
421def test_main():
Antoine Pitrou6327e842008-07-26 11:56:37 +0000422 tests = [
423 TestMiscellaneous,
R. David Murraya83da352009-04-01 03:21:43 +0000424 TestFormatPatternArg,
R. David Murray3939dcd2010-04-26 21:17:14 +0000425 TestLocaleFormatString,
Antoine Pitrou6327e842008-07-26 11:56:37 +0000426 TestEnUSNumberFormatting,
Antoine Pitroufeeafff2009-03-14 00:07:21 +0000427 TestCNumberFormatting,
428 TestFrFRNumberFormatting,
Antoine Pitrou6327e842008-07-26 11:56:37 +0000429 ]
Benjamin Peterson888a39b2009-03-26 20:48:25 +0000430 # SkipTest can't be raised inside unittests, handle it manually instead
Antoine Pitrou524f4132008-07-26 10:29:43 +0000431 try:
432 get_enUS_locale()
Benjamin Peterson7fa94592009-03-26 21:44:43 +0000433 except unittest.SkipTest as e:
Antoine Pitrou6327e842008-07-26 11:56:37 +0000434 if verbose:
435 print "Some tests will be disabled: %s" % e
Antoine Pitrou524f4132008-07-26 10:29:43 +0000436 else:
437 tests += [TestNumberFormatting, TestStringMethods]
438 run_unittest(*tests)
Antoine Pitrouba54eda2008-07-25 20:40:19 +0000439
440if __name__ == '__main__':
441 test_main()