/Lib/test/test_locale.py

http://unladen-swallow.googlecode.com/ · Python · 369 lines · 266 code · 73 blank · 30 comment · 21 complexity · bdeacdb0c43de8d840cac774076b885c MD5 · raw file

  1. from test.test_support import run_unittest, verbose, TestSkipped
  2. import unittest
  3. import locale
  4. import sys
  5. import codecs
  6. enUS_locale = None
  7. def get_enUS_locale():
  8. global enUS_locale
  9. if sys.platform == 'darwin':
  10. raise TestSkipped("Locale support on MacOSX is minimal")
  11. if sys.platform.startswith("win"):
  12. tlocs = ("En", "English")
  13. else:
  14. tlocs = ("en_US.UTF-8", "en_US.US-ASCII", "en_US")
  15. oldlocale = locale.setlocale(locale.LC_NUMERIC)
  16. for tloc in tlocs:
  17. try:
  18. locale.setlocale(locale.LC_NUMERIC, tloc)
  19. except locale.Error:
  20. continue
  21. break
  22. else:
  23. raise TestSkipped(
  24. "Test locale not supported (tried %s)" % (', '.join(tlocs)))
  25. enUS_locale = tloc
  26. locale.setlocale(locale.LC_NUMERIC, oldlocale)
  27. class BaseLocalizedTest(unittest.TestCase):
  28. #
  29. # Base class for tests using a real locale
  30. #
  31. def setUp(self):
  32. self.oldlocale = locale.setlocale(self.locale_type)
  33. locale.setlocale(self.locale_type, enUS_locale)
  34. if verbose:
  35. print "testing with \"%s\"..." % enUS_locale,
  36. def tearDown(self):
  37. locale.setlocale(self.locale_type, self.oldlocale)
  38. class BaseCookedTest(unittest.TestCase):
  39. #
  40. # Base class for tests using cooked localeconv() values
  41. #
  42. def setUp(self):
  43. locale._override_localeconv = self.cooked_values
  44. def tearDown(self):
  45. locale._override_localeconv = {}
  46. class CCookedTest(BaseCookedTest):
  47. # A cooked "C" locale
  48. cooked_values = {
  49. 'currency_symbol': '',
  50. 'decimal_point': '.',
  51. 'frac_digits': 127,
  52. 'grouping': [],
  53. 'int_curr_symbol': '',
  54. 'int_frac_digits': 127,
  55. 'mon_decimal_point': '',
  56. 'mon_grouping': [],
  57. 'mon_thousands_sep': '',
  58. 'n_cs_precedes': 127,
  59. 'n_sep_by_space': 127,
  60. 'n_sign_posn': 127,
  61. 'negative_sign': '',
  62. 'p_cs_precedes': 127,
  63. 'p_sep_by_space': 127,
  64. 'p_sign_posn': 127,
  65. 'positive_sign': '',
  66. 'thousands_sep': ''
  67. }
  68. class EnUSCookedTest(BaseCookedTest):
  69. # A cooked "en_US" locale
  70. cooked_values = {
  71. 'currency_symbol': '$',
  72. 'decimal_point': '.',
  73. 'frac_digits': 2,
  74. 'grouping': [3, 3, 0],
  75. 'int_curr_symbol': 'USD ',
  76. 'int_frac_digits': 2,
  77. 'mon_decimal_point': '.',
  78. 'mon_grouping': [3, 3, 0],
  79. 'mon_thousands_sep': ',',
  80. 'n_cs_precedes': 1,
  81. 'n_sep_by_space': 0,
  82. 'n_sign_posn': 1,
  83. 'negative_sign': '-',
  84. 'p_cs_precedes': 1,
  85. 'p_sep_by_space': 0,
  86. 'p_sign_posn': 1,
  87. 'positive_sign': '',
  88. 'thousands_sep': ','
  89. }
  90. class FrFRCookedTest(BaseCookedTest):
  91. # A cooked "fr_FR" locale with a space character as decimal separator
  92. # and a non-ASCII currency symbol.
  93. cooked_values = {
  94. 'currency_symbol': '\xe2\x82\xac',
  95. 'decimal_point': ',',
  96. 'frac_digits': 2,
  97. 'grouping': [3, 3, 0],
  98. 'int_curr_symbol': 'EUR ',
  99. 'int_frac_digits': 2,
  100. 'mon_decimal_point': ',',
  101. 'mon_grouping': [3, 3, 0],
  102. 'mon_thousands_sep': ' ',
  103. 'n_cs_precedes': 0,
  104. 'n_sep_by_space': 1,
  105. 'n_sign_posn': 1,
  106. 'negative_sign': '-',
  107. 'p_cs_precedes': 0,
  108. 'p_sep_by_space': 1,
  109. 'p_sign_posn': 1,
  110. 'positive_sign': '',
  111. 'thousands_sep': ' '
  112. }
  113. class BaseFormattingTest(object):
  114. #
  115. # Utility functions for formatting tests
  116. #
  117. def _test_formatfunc(self, format, value, out, func, **format_opts):
  118. self.assertEqual(
  119. func(format, value, **format_opts), out)
  120. def _test_format(self, format, value, out, **format_opts):
  121. self._test_formatfunc(format, value, out,
  122. func=locale.format, **format_opts)
  123. def _test_format_string(self, format, value, out, **format_opts):
  124. self._test_formatfunc(format, value, out,
  125. func=locale.format_string, **format_opts)
  126. def _test_currency(self, value, out, **format_opts):
  127. self.assertEqual(locale.currency(value, **format_opts), out)
  128. class EnUSNumberFormatting(BaseFormattingTest):
  129. # XXX there is a grouping + padding bug when the thousands separator
  130. # is empty but the grouping array contains values (e.g. Solaris 10)
  131. def setUp(self):
  132. self.sep = locale.localeconv()['thousands_sep']
  133. def test_grouping(self):
  134. self._test_format("%f", 1024, grouping=1, out='1%s024.000000' % self.sep)
  135. self._test_format("%f", 102, grouping=1, out='102.000000')
  136. self._test_format("%f", -42, grouping=1, out='-42.000000')
  137. self._test_format("%+f", -42, grouping=1, out='-42.000000')
  138. def test_grouping_and_padding(self):
  139. self._test_format("%20.f", -42, grouping=1, out='-42'.rjust(20))
  140. if self.sep:
  141. self._test_format("%+10.f", -4200, grouping=1,
  142. out=('-4%s200' % self.sep).rjust(10))
  143. self._test_format("%-10.f", -4200, grouping=1,
  144. out=('-4%s200' % self.sep).ljust(10))
  145. def test_integer_grouping(self):
  146. self._test_format("%d", 4200, grouping=True, out='4%s200' % self.sep)
  147. self._test_format("%+d", 4200, grouping=True, out='+4%s200' % self.sep)
  148. self._test_format("%+d", -4200, grouping=True, out='-4%s200' % self.sep)
  149. def test_integer_grouping_and_padding(self):
  150. self._test_format("%10d", 4200, grouping=True,
  151. out=('4%s200' % self.sep).rjust(10))
  152. self._test_format("%-10d", -4200, grouping=True,
  153. out=('-4%s200' % self.sep).ljust(10))
  154. def test_simple(self):
  155. self._test_format("%f", 1024, grouping=0, out='1024.000000')
  156. self._test_format("%f", 102, grouping=0, out='102.000000')
  157. self._test_format("%f", -42, grouping=0, out='-42.000000')
  158. self._test_format("%+f", -42, grouping=0, out='-42.000000')
  159. def test_padding(self):
  160. self._test_format("%20.f", -42, grouping=0, out='-42'.rjust(20))
  161. self._test_format("%+10.f", -4200, grouping=0, out='-4200'.rjust(10))
  162. self._test_format("%-10.f", 4200, grouping=0, out='4200'.ljust(10))
  163. def test_complex_formatting(self):
  164. # Spaces in formatting string
  165. self._test_format_string("One million is %i", 1000000, grouping=1,
  166. out='One million is 1%s000%s000' % (self.sep, self.sep))
  167. self._test_format_string("One million is %i", 1000000, grouping=1,
  168. out='One million is 1%s000%s000' % (self.sep, self.sep))
  169. # Dots in formatting string
  170. self._test_format_string(".%f.", 1000.0, out='.1000.000000.')
  171. # Padding
  172. if self.sep:
  173. self._test_format_string("--> %10.2f", 4200, grouping=1,
  174. out='--> ' + ('4%s200.00' % self.sep).rjust(10))
  175. # Asterisk formats
  176. self._test_format_string("%10.*f", (2, 1000), grouping=0,
  177. out='1000.00'.rjust(10))
  178. if self.sep:
  179. self._test_format_string("%*.*f", (10, 2, 1000), grouping=1,
  180. out=('1%s000.00' % self.sep).rjust(10))
  181. # Test more-in-one
  182. if self.sep:
  183. self._test_format_string("int %i float %.2f str %s",
  184. (1000, 1000.0, 'str'), grouping=1,
  185. out='int 1%s000 float 1%s000.00 str str' %
  186. (self.sep, self.sep))
  187. class TestNumberFormatting(BaseLocalizedTest, EnUSNumberFormatting):
  188. # Test number formatting with a real English locale.
  189. locale_type = locale.LC_NUMERIC
  190. def setUp(self):
  191. BaseLocalizedTest.setUp(self)
  192. EnUSNumberFormatting.setUp(self)
  193. class TestEnUSNumberFormatting(EnUSCookedTest, EnUSNumberFormatting):
  194. # Test number formatting with a cooked "en_US" locale.
  195. def setUp(self):
  196. EnUSCookedTest.setUp(self)
  197. EnUSNumberFormatting.setUp(self)
  198. def test_currency(self):
  199. self._test_currency(50000, "$50000.00")
  200. self._test_currency(50000, "$50,000.00", grouping=True)
  201. self._test_currency(50000, "USD 50,000.00",
  202. grouping=True, international=True)
  203. class TestCNumberFormatting(CCookedTest, BaseFormattingTest):
  204. # Test number formatting with a cooked "C" locale.
  205. def test_grouping(self):
  206. self._test_format("%.2f", 12345.67, grouping=True, out='12345.67')
  207. def test_grouping_and_padding(self):
  208. self._test_format("%9.2f", 12345.67, grouping=True, out=' 12345.67')
  209. class TestFrFRNumberFormatting(FrFRCookedTest, BaseFormattingTest):
  210. # Test number formatting with a cooked "fr_FR" locale.
  211. def test_decimal_point(self):
  212. self._test_format("%.2f", 12345.67, out='12345,67')
  213. def test_grouping(self):
  214. self._test_format("%.2f", 345.67, grouping=True, out='345,67')
  215. self._test_format("%.2f", 12345.67, grouping=True, out='12 345,67')
  216. def test_grouping_and_padding(self):
  217. self._test_format("%6.2f", 345.67, grouping=True, out='345,67')
  218. self._test_format("%7.2f", 345.67, grouping=True, out=' 345,67')
  219. self._test_format("%8.2f", 12345.67, grouping=True, out='12 345,67')
  220. self._test_format("%9.2f", 12345.67, grouping=True, out='12 345,67')
  221. self._test_format("%10.2f", 12345.67, grouping=True, out=' 12 345,67')
  222. self._test_format("%-6.2f", 345.67, grouping=True, out='345,67')
  223. self._test_format("%-7.2f", 345.67, grouping=True, out='345,67 ')
  224. self._test_format("%-8.2f", 12345.67, grouping=True, out='12 345,67')
  225. self._test_format("%-9.2f", 12345.67, grouping=True, out='12 345,67')
  226. self._test_format("%-10.2f", 12345.67, grouping=True, out='12 345,67 ')
  227. def test_integer_grouping(self):
  228. self._test_format("%d", 200, grouping=True, out='200')
  229. self._test_format("%d", 4200, grouping=True, out='4 200')
  230. def test_integer_grouping_and_padding(self):
  231. self._test_format("%4d", 4200, grouping=True, out='4 200')
  232. self._test_format("%5d", 4200, grouping=True, out='4 200')
  233. self._test_format("%10d", 4200, grouping=True, out='4 200'.rjust(10))
  234. self._test_format("%-4d", 4200, grouping=True, out='4 200')
  235. self._test_format("%-5d", 4200, grouping=True, out='4 200')
  236. self._test_format("%-10d", 4200, grouping=True, out='4 200'.ljust(10))
  237. def test_currency(self):
  238. euro = u'\u20ac'.encode('utf-8')
  239. self._test_currency(50000, "50000,00 " + euro)
  240. self._test_currency(50000, "50 000,00 " + euro, grouping=True)
  241. # XXX is the trailing space a bug?
  242. self._test_currency(50000, "50 000,00 EUR ",
  243. grouping=True, international=True)
  244. class TestStringMethods(BaseLocalizedTest):
  245. locale_type = locale.LC_CTYPE
  246. if sys.platform != 'sunos5' and not sys.platform.startswith("win"):
  247. # Test BSD Rune locale's bug for isctype functions.
  248. def test_isspace(self):
  249. self.assertEqual('\x20'.isspace(), True)
  250. self.assertEqual('\xa0'.isspace(), False)
  251. self.assertEqual('\xa1'.isspace(), False)
  252. def test_isalpha(self):
  253. self.assertEqual('\xc0'.isalpha(), False)
  254. def test_isalnum(self):
  255. self.assertEqual('\xc0'.isalnum(), False)
  256. def test_isupper(self):
  257. self.assertEqual('\xc0'.isupper(), False)
  258. def test_islower(self):
  259. self.assertEqual('\xc0'.islower(), False)
  260. def test_lower(self):
  261. self.assertEqual('\xcc\x85'.lower(), '\xcc\x85')
  262. def test_upper(self):
  263. self.assertEqual('\xed\x95\xa0'.upper(), '\xed\x95\xa0')
  264. def test_strip(self):
  265. self.assertEqual('\xed\x95\xa0'.strip(), '\xed\x95\xa0')
  266. def test_split(self):
  267. self.assertEqual('\xec\xa0\xbc'.split(), ['\xec\xa0\xbc'])
  268. class TestMiscellaneous(unittest.TestCase):
  269. def test_getpreferredencoding(self):
  270. # Invoke getpreferredencoding to make sure it does not cause exceptions.
  271. enc = locale.getpreferredencoding()
  272. if enc:
  273. # If encoding non-empty, make sure it is valid
  274. codecs.lookup(enc)
  275. if hasattr(locale, "strcoll"):
  276. def test_strcoll_3303(self):
  277. # test crasher from bug #3303
  278. self.assertRaises(TypeError, locale.strcoll, u"a", None)
  279. def test_main():
  280. tests = [
  281. TestMiscellaneous,
  282. TestEnUSNumberFormatting,
  283. TestCNumberFormatting,
  284. TestFrFRNumberFormatting,
  285. ]
  286. # TestSkipped can't be raised inside unittests, handle it manually instead
  287. try:
  288. get_enUS_locale()
  289. except TestSkipped as e:
  290. if verbose:
  291. print "Some tests will be disabled: %s" % e
  292. else:
  293. tests += [TestNumberFormatting, TestStringMethods]
  294. run_unittest(*tests)
  295. if __name__ == '__main__':
  296. test_main()