1from test.test_support import run_unittest, verbose 2import unittest 3import locale 4import sys 5import codecs 6 7 8enUS_locale = None 9 10def get_enUS_locale(): 11 global enUS_locale 12 if sys.platform == 'darwin': 13 import os 14 tlocs = ("en_US.UTF-8", "en_US.ISO8859-1", "en_US") 15 if int(os.uname()[2].split('.')[0]) < 10: 16 # The locale test work fine on OSX 10.6, I (ronaldoussoren) 17 # haven't had time yet to verify if tests work on OSX 10.5 18 # (10.4 is known to be bad) 19 raise unittest.SkipTest("Locale support on MacOSX is minimal") 20 if sys.platform.startswith("win"): 21 tlocs = ("En", "English") 22 else: 23 tlocs = ("en_US.UTF-8", "en_US.US-ASCII", "en_US") 24 oldlocale = locale.setlocale(locale.LC_NUMERIC) 25 for tloc in tlocs: 26 try: 27 locale.setlocale(locale.LC_NUMERIC, tloc) 28 except locale.Error: 29 continue 30 break 31 else: 32 raise unittest.SkipTest( 33 "Test locale not supported (tried %s)" % (', '.join(tlocs))) 34 enUS_locale = tloc 35 locale.setlocale(locale.LC_NUMERIC, oldlocale) 36 37 38class BaseLocalizedTest(unittest.TestCase): 39 # 40 # Base class for tests using a real locale 41 # 42 43 def setUp(self): 44 self.oldlocale = locale.setlocale(self.locale_type) 45 locale.setlocale(self.locale_type, enUS_locale) 46 if verbose: 47 print "testing with \"%s\"..." % enUS_locale, 48 49 def tearDown(self): 50 locale.setlocale(self.locale_type, self.oldlocale) 51 52 53class BaseCookedTest(unittest.TestCase): 54 # 55 # Base class for tests using cooked localeconv() values 56 # 57 58 def setUp(self): 59 locale._override_localeconv = self.cooked_values 60 61 def tearDown(self): 62 locale._override_localeconv = {} 63 64 65class CCookedTest(BaseCookedTest): 66 # A cooked "C" locale 67 68 cooked_values = { 69 'currency_symbol': '', 70 'decimal_point': '.', 71 'frac_digits': 127, 72 'grouping': [], 73 'int_curr_symbol': '', 74 'int_frac_digits': 127, 75 'mon_decimal_point': '', 76 'mon_grouping': [], 77 'mon_thousands_sep': '', 78 'n_cs_precedes': 127, 79 'n_sep_by_space': 127, 80 'n_sign_posn': 127, 81 'negative_sign': '', 82 'p_cs_precedes': 127, 83 'p_sep_by_space': 127, 84 'p_sign_posn': 127, 85 'positive_sign': '', 86 'thousands_sep': '' 87 } 88 89class EnUSCookedTest(BaseCookedTest): 90 # A cooked "en_US" locale 91 92 cooked_values = { 93 'currency_symbol': '$', 94 'decimal_point': '.', 95 'frac_digits': 2, 96 'grouping': [3, 3, 0], 97 'int_curr_symbol': 'USD ', 98 'int_frac_digits': 2, 99 'mon_decimal_point': '.', 100 'mon_grouping': [3, 3, 0], 101 'mon_thousands_sep': ',', 102 'n_cs_precedes': 1, 103 'n_sep_by_space': 0, 104 'n_sign_posn': 1, 105 'negative_sign': '-', 106 'p_cs_precedes': 1, 107 'p_sep_by_space': 0, 108 'p_sign_posn': 1, 109 'positive_sign': '', 110 'thousands_sep': ',' 111 } 112 113 114class FrFRCookedTest(BaseCookedTest): 115 # A cooked "fr_FR" locale with a space character as decimal separator 116 # and a non-ASCII currency symbol. 117 118 cooked_values = { 119 'currency_symbol': '\xe2\x82\xac', 120 'decimal_point': ',', 121 'frac_digits': 2, 122 'grouping': [3, 3, 0], 123 'int_curr_symbol': 'EUR ', 124 'int_frac_digits': 2, 125 'mon_decimal_point': ',', 126 'mon_grouping': [3, 3, 0], 127 'mon_thousands_sep': ' ', 128 'n_cs_precedes': 0, 129 'n_sep_by_space': 1, 130 'n_sign_posn': 1, 131 'negative_sign': '-', 132 'p_cs_precedes': 0, 133 'p_sep_by_space': 1, 134 'p_sign_posn': 1, 135 'positive_sign': '', 136 'thousands_sep': ' ' 137 } 138 139 140class BaseFormattingTest(object): 141 # 142 # Utility functions for formatting tests 143 # 144 145 def _test_formatfunc(self, format, value, out, func, **format_opts): 146 self.assertEqual( 147 func(format, value, **format_opts), out) 148 149 def _test_format(self, format, value, out, **format_opts): 150 self._test_formatfunc(format, value, out, 151 func=locale.format, **format_opts) 152 153 def _test_format_string(self, format, value, out, **format_opts): 154 self._test_formatfunc(format, value, out, 155 func=locale.format_string, **format_opts) 156 157 def _test_currency(self, value, out, **format_opts): 158 self.assertEqual(locale.currency(value, **format_opts), out) 159 160 161class EnUSNumberFormatting(BaseFormattingTest): 162 # XXX there is a grouping + padding bug when the thousands separator 163 # is empty but the grouping array contains values (e.g. Solaris 10) 164 165 def setUp(self): 166 self.sep = locale.localeconv()['thousands_sep'] 167 168 def test_grouping(self): 169 self._test_format("%f", 1024, grouping=1, out='1%s024.000000' % self.sep) 170 self._test_format("%f", 102, grouping=1, out='102.000000') 171 self._test_format("%f", -42, grouping=1, out='-42.000000') 172 self._test_format("%+f", -42, grouping=1, out='-42.000000') 173 174 def test_grouping_and_padding(self): 175 self._test_format("%20.f", -42, grouping=1, out='-42'.rjust(20)) 176 if self.sep: 177 self._test_format("%+10.f", -4200, grouping=1, 178 out=('-4%s200' % self.sep).rjust(10)) 179 self._test_format("%-10.f", -4200, grouping=1, 180 out=('-4%s200' % self.sep).ljust(10)) 181 182 def test_integer_grouping(self): 183 self._test_format("%d", 4200, grouping=True, out='4%s200' % self.sep) 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 187 def test_integer_grouping_and_padding(self): 188 self._test_format("%10d", 4200, grouping=True, 189 out=('4%s200' % self.sep).rjust(10)) 190 self._test_format("%-10d", -4200, grouping=True, 191 out=('-4%s200' % self.sep).ljust(10)) 192 193 def test_simple(self): 194 self._test_format("%f", 1024, grouping=0, out='1024.000000') 195 self._test_format("%f", 102, grouping=0, out='102.000000') 196 self._test_format("%f", -42, grouping=0, out='-42.000000') 197 self._test_format("%+f", -42, grouping=0, out='-42.000000') 198 199 def test_padding(self): 200 self._test_format("%20.f", -42, grouping=0, out='-42'.rjust(20)) 201 self._test_format("%+10.f", -4200, grouping=0, out='-4200'.rjust(10)) 202 self._test_format("%-10.f", 4200, grouping=0, out='4200'.ljust(10)) 203 204 def test_complex_formatting(self): 205 # Spaces in formatting string 206 self._test_format_string("One million is %i", 1000000, grouping=1, 207 out='One million is 1%s000%s000' % (self.sep, self.sep)) 208 self._test_format_string("One million is %i", 1000000, grouping=1, 209 out='One million is 1%s000%s000' % (self.sep, self.sep)) 210 # Dots in formatting string 211 self._test_format_string(".%f.", 1000.0, out='.1000.000000.') 212 # Padding 213 if self.sep: 214 self._test_format_string("--> %10.2f", 4200, grouping=1, 215 out='--> ' + ('4%s200.00' % self.sep).rjust(10)) 216 # Asterisk formats 217 self._test_format_string("%10.*f", (2, 1000), grouping=0, 218 out='1000.00'.rjust(10)) 219 if self.sep: 220 self._test_format_string("%*.*f", (10, 2, 1000), grouping=1, 221 out=('1%s000.00' % self.sep).rjust(10)) 222 # Test more-in-one 223 if self.sep: 224 self._test_format_string("int %i float %.2f str %s", 225 (1000, 1000.0, 'str'), grouping=1, 226 out='int 1%s000 float 1%s000.00 str str' % 227 (self.sep, self.sep)) 228 229 230class TestFormatPatternArg(unittest.TestCase): 231 # Test handling of pattern argument of format 232 233 def test_onlyOnePattern(self): 234 # Issue 2522: accept exactly one % pattern, and no extra chars. 235 self.assertRaises(ValueError, locale.format, "%f\n", 'foo') 236 self.assertRaises(ValueError, locale.format, "%f\r", 'foo') 237 self.assertRaises(ValueError, locale.format, "%f\r\n", 'foo') 238 self.assertRaises(ValueError, locale.format, " %f", 'foo') 239 self.assertRaises(ValueError, locale.format, "%fg", 'foo') 240 self.assertRaises(ValueError, locale.format, "%^g", 'foo') 241 self.assertRaises(ValueError, locale.format, "%f%%", 'foo') 242 243 244class TestLocaleFormatString(unittest.TestCase): 245 """General tests on locale.format_string""" 246 247 def test_percent_escape(self): 248 self.assertEqual(locale.format_string('%f%%', 1.0), '%f%%' % 1.0) 249 self.assertEqual(locale.format_string('%d %f%%d', (1, 1.0)), 250 '%d %f%%d' % (1, 1.0)) 251 self.assertEqual(locale.format_string('%(foo)s %%d', {'foo': 'bar'}), 252 ('%(foo)s %%d' % {'foo': 'bar'})) 253 254 def test_mapping(self): 255 self.assertEqual(locale.format_string('%(foo)s bing.', {'foo': 'bar'}), 256 ('%(foo)s bing.' % {'foo': 'bar'})) 257 self.assertEqual(locale.format_string('%(foo)s', {'foo': 'bar'}), 258 ('%(foo)s' % {'foo': 'bar'})) 259 260 261 262class TestNumberFormatting(BaseLocalizedTest, EnUSNumberFormatting): 263 # Test number formatting with a real English locale. 264 265 locale_type = locale.LC_NUMERIC 266 267 def setUp(self): 268 BaseLocalizedTest.setUp(self) 269 EnUSNumberFormatting.setUp(self) 270 271 272class TestEnUSNumberFormatting(EnUSCookedTest, EnUSNumberFormatting): 273 # Test number formatting with a cooked "en_US" locale. 274 275 def setUp(self): 276 EnUSCookedTest.setUp(self) 277 EnUSNumberFormatting.setUp(self) 278 279 def test_currency(self): 280 self._test_currency(50000, "$50000.00") 281 self._test_currency(50000, "$50,000.00", grouping=True) 282 self._test_currency(50000, "USD 50,000.00", 283 grouping=True, international=True) 284 285 286class TestCNumberFormatting(CCookedTest, BaseFormattingTest): 287 # Test number formatting with a cooked "C" locale. 288 289 def test_grouping(self): 290 self._test_format("%.2f", 12345.67, grouping=True, out='12345.67') 291 292 def test_grouping_and_padding(self): 293 self._test_format("%9.2f", 12345.67, grouping=True, out=' 12345.67') 294 295 296class TestFrFRNumberFormatting(FrFRCookedTest, BaseFormattingTest): 297 # Test number formatting with a cooked "fr_FR" locale. 298 299 def test_decimal_point(self): 300 self._test_format("%.2f", 12345.67, out='12345,67') 301 302 def test_grouping(self): 303 self._test_format("%.2f", 345.67, grouping=True, out='345,67') 304 self._test_format("%.2f", 12345.67, grouping=True, out='12 345,67') 305 306 def test_grouping_and_padding(self): 307 self._test_format("%6.2f", 345.67, grouping=True, out='345,67') 308 self._test_format("%7.2f", 345.67, grouping=True, out=' 345,67') 309 self._test_format("%8.2f", 12345.67, grouping=True, out='12 345,67') 310 self._test_format("%9.2f", 12345.67, grouping=True, out='12 345,67') 311 self._test_format("%10.2f", 12345.67, grouping=True, out=' 12 345,67') 312 self._test_format("%-6.2f", 345.67, grouping=True, out='345,67') 313 self._test_format("%-7.2f", 345.67, grouping=True, out='345,67 ') 314 self._test_format("%-8.2f", 12345.67, grouping=True, out='12 345,67') 315 self._test_format("%-9.2f", 12345.67, grouping=True, out='12 345,67') 316 self._test_format("%-10.2f", 12345.67, grouping=True, out='12 345,67 ') 317 318 def test_integer_grouping(self): 319 self._test_format("%d", 200, grouping=True, out='200') 320 self._test_format("%d", 4200, grouping=True, out='4 200') 321 322 def test_integer_grouping_and_padding(self): 323 self._test_format("%4d", 4200, grouping=True, out='4 200') 324 self._test_format("%5d", 4200, grouping=True, out='4 200') 325 self._test_format("%10d", 4200, grouping=True, out='4 200'.rjust(10)) 326 self._test_format("%-4d", 4200, grouping=True, out='4 200') 327 self._test_format("%-5d", 4200, grouping=True, out='4 200') 328 self._test_format("%-10d", 4200, grouping=True, out='4 200'.ljust(10)) 329 330 def test_currency(self): 331 euro = u'\u20ac'.encode('utf-8') 332 self._test_currency(50000, "50000,00 " + euro) 333 self._test_currency(50000, "50 000,00 " + euro, grouping=True) 334 # XXX is the trailing space a bug? 335 self._test_currency(50000, "50 000,00 EUR ", 336 grouping=True, international=True) 337 338 339class TestStringMethods(BaseLocalizedTest): 340 locale_type = locale.LC_CTYPE 341 342 if sys.platform != 'sunos5' and not sys.platform.startswith("win"): 343 # Test BSD Rune locale's bug for isctype functions. 344 345 def test_isspace(self): 346 self.assertEqual('\x20'.isspace(), True) 347 self.assertEqual('\xa0'.isspace(), False) 348 self.assertEqual('\xa1'.isspace(), False) 349 350 def test_isalpha(self): 351 self.assertEqual('\xc0'.isalpha(), False) 352 353 def test_isalnum(self): 354 self.assertEqual('\xc0'.isalnum(), False) 355 356 def test_isupper(self): 357 self.assertEqual('\xc0'.isupper(), False) 358 359 def test_islower(self): 360 self.assertEqual('\xc0'.islower(), False) 361 362 def test_lower(self): 363 self.assertEqual('\xcc\x85'.lower(), '\xcc\x85') 364 365 def test_upper(self): 366 self.assertEqual('\xed\x95\xa0'.upper(), '\xed\x95\xa0') 367 368 def test_strip(self): 369 self.assertEqual('\xed\x95\xa0'.strip(), '\xed\x95\xa0') 370 371 def test_split(self): 372 self.assertEqual('\xec\xa0\xbc'.split(), ['\xec\xa0\xbc']) 373 374 375class TestMiscellaneous(unittest.TestCase): 376 def test_getpreferredencoding(self): 377 # Invoke getpreferredencoding to make sure it does not cause exceptions. 378 enc = locale.getpreferredencoding() 379 if enc: 380 # If encoding non-empty, make sure it is valid 381 codecs.lookup(enc) 382 383 if hasattr(locale, "strcoll"): 384 def test_strcoll_3303(self): 385 # test crasher from bug #3303 386 self.assertRaises(TypeError, locale.strcoll, u"a", None) 387 388 def test_setlocale_category(self): 389 locale.setlocale(locale.LC_ALL) 390 locale.setlocale(locale.LC_TIME) 391 locale.setlocale(locale.LC_CTYPE) 392 locale.setlocale(locale.LC_COLLATE) 393 locale.setlocale(locale.LC_MONETARY) 394 locale.setlocale(locale.LC_NUMERIC) 395 396 # crasher from bug #7419 397 self.assertRaises(locale.Error, locale.setlocale, 12345) 398 399 400def test_main(): 401 tests = [ 402 TestMiscellaneous, 403 TestFormatPatternArg, 404 TestLocaleFormatString, 405 TestEnUSNumberFormatting, 406 TestCNumberFormatting, 407 TestFrFRNumberFormatting, 408 ] 409 # SkipTest can't be raised inside unittests, handle it manually instead 410 try: 411 get_enUS_locale() 412 except unittest.SkipTest as e: 413 if verbose: 414 print "Some tests will be disabled: %s" % e 415 else: 416 tests += [TestNumberFormatting, TestStringMethods] 417 run_unittest(*tests) 418 419if __name__ == '__main__': 420 test_main() 421