make file closing more robust
[python/dscho.git] / Lib / test / test_gettext.py
blob0023941dd58b890b141ffef6f5102e1bfc52fa99
1 import os
2 import base64
3 import shutil
4 import gettext
5 import unittest
7 from test import support
10 # TODO:
11 # - Add new tests, for example for "dgettext"
12 # - Remove dummy tests, for example testing for single and double quotes
13 # has no sense, it would have if we were testing a parser (i.e. pygettext)
14 # - Tests should have only one assert.
16 GNU_MO_DATA = b'''\
17 3hIElQAAAAAGAAAAHAAAAEwAAAALAAAAfAAAAAAAAACoAAAAFQAAAKkAAAAjAAAAvwAAAKEAAADj
18 AAAABwAAAIUBAAALAAAAjQEAAEUBAACZAQAAFgAAAN8CAAAeAAAA9gIAAKEAAAAVAwAABQAAALcD
19 AAAJAAAAvQMAAAEAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABQAAAAYAAAACAAAAAFJh
20 eW1vbmQgTHV4dXJ5IFlhY2gtdABUaGVyZSBpcyAlcyBmaWxlAFRoZXJlIGFyZSAlcyBmaWxlcwBU
21 aGlzIG1vZHVsZSBwcm92aWRlcyBpbnRlcm5hdGlvbmFsaXphdGlvbiBhbmQgbG9jYWxpemF0aW9u
22 CnN1cHBvcnQgZm9yIHlvdXIgUHl0aG9uIHByb2dyYW1zIGJ5IHByb3ZpZGluZyBhbiBpbnRlcmZh
23 Y2UgdG8gdGhlIEdOVQpnZXR0ZXh0IG1lc3NhZ2UgY2F0YWxvZyBsaWJyYXJ5LgBtdWxsdXNrAG51
24 ZGdlIG51ZGdlAFByb2plY3QtSWQtVmVyc2lvbjogMi4wClBPLVJldmlzaW9uLURhdGU6IDIwMDAt
25 MDgtMjkgMTI6MTktMDQ6MDAKTGFzdC1UcmFuc2xhdG9yOiBKLiBEYXZpZCBJYsOhw7FleiA8ai1k
26 YXZpZEBub29zLmZyPgpMYW5ndWFnZS1UZWFtOiBYWCA8cHl0aG9uLWRldkBweXRob24ub3JnPgpN
27 SU1FLVZlcnNpb246IDEuMApDb250ZW50LVR5cGU6IHRleHQvcGxhaW47IGNoYXJzZXQ9aXNvLTg4
28 NTktMQpDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBub25lCkdlbmVyYXRlZC1CeTogcHlnZXR0
29 ZXh0LnB5IDEuMQpQbHVyYWwtRm9ybXM6IG5wbHVyYWxzPTI7IHBsdXJhbD1uIT0xOwoAVGhyb2F0
30 d29iYmxlciBNYW5ncm92ZQBIYXkgJXMgZmljaGVybwBIYXkgJXMgZmljaGVyb3MAR3V2ZiB6YnFo
31 eXIgY2ViaXZxcmYgdmFncmVhbmd2YmFueXZtbmd2YmEgbmFxIHlicG55dm1uZ3ZiYQpmaGNjYmVn
32 IHNiZSBsYmhlIENsZ3ViYSBjZWJ0ZW56ZiBvbCBjZWJpdnF2YXQgbmEgdmFncmVzbnByIGdiIGd1
33 ciBUQUgKdHJnZ3JrZyB6cmZmbnRyIHBuZ255YnQgeXZvZW5lbC4AYmFjb24Ad2luayB3aW5rAA==
34 '''
36 UMO_DATA = b'''\
37 3hIElQAAAAACAAAAHAAAACwAAAAFAAAAPAAAAAAAAABQAAAABAAAAFEAAAAPAQAAVgAAAAQAAABm
38 AQAAAQAAAAIAAAAAAAAAAAAAAAAAAAAAYWLDngBQcm9qZWN0LUlkLVZlcnNpb246IDIuMApQTy1S
39 ZXZpc2lvbi1EYXRlOiAyMDAzLTA0LTExIDEyOjQyLTA0MDAKTGFzdC1UcmFuc2xhdG9yOiBCYXJy
40 eSBBLiBXQXJzYXcgPGJhcnJ5QHB5dGhvbi5vcmc+Ckxhbmd1YWdlLVRlYW06IFhYIDxweXRob24t
41 ZGV2QHB5dGhvbi5vcmc+Ck1JTUUtVmVyc2lvbjogMS4wCkNvbnRlbnQtVHlwZTogdGV4dC9wbGFp
42 bjsgY2hhcnNldD11dGYtOApDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiA3Yml0CkdlbmVyYXRl
43 ZC1CeTogbWFudWFsbHkKAMKkeXoA
44 '''
46 MMO_DATA = b'''\
47 3hIElQAAAAABAAAAHAAAACQAAAADAAAALAAAAAAAAAA4AAAAeAEAADkAAAABAAAAAAAAAAAAAAAA
48 UHJvamVjdC1JZC1WZXJzaW9uOiBObyBQcm9qZWN0IDAuMApQT1QtQ3JlYXRpb24tRGF0ZTogV2Vk
49 IERlYyAxMSAwNzo0NDoxNSAyMDAyClBPLVJldmlzaW9uLURhdGU6IDIwMDItMDgtMTQgMDE6MTg6
50 NTgrMDA6MDAKTGFzdC1UcmFuc2xhdG9yOiBKb2huIERvZSA8amRvZUBleGFtcGxlLmNvbT4KSmFu
51 ZSBGb29iYXIgPGpmb29iYXJAZXhhbXBsZS5jb20+Ckxhbmd1YWdlLVRlYW06IHh4IDx4eEBleGFt
52 cGxlLmNvbT4KTUlNRS1WZXJzaW9uOiAxLjAKQ29udGVudC1UeXBlOiB0ZXh0L3BsYWluOyBjaGFy
53 c2V0PWlzby04ODU5LTE1CkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6IHF1b3RlZC1wcmludGFi
54 bGUKR2VuZXJhdGVkLUJ5OiBweWdldHRleHQucHkgMS4zCgA=
55 '''
57 LOCALEDIR = os.path.join('xx', 'LC_MESSAGES')
58 MOFILE = os.path.join(LOCALEDIR, 'gettext.mo')
59 UMOFILE = os.path.join(LOCALEDIR, 'ugettext.mo')
60 MMOFILE = os.path.join(LOCALEDIR, 'metadata.mo')
63 class GettextBaseTest(unittest.TestCase):
64 def setUp(self):
65 if not os.path.isdir(LOCALEDIR):
66 os.makedirs(LOCALEDIR)
67 fp = open(MOFILE, 'wb')
68 fp.write(base64.decodebytes(GNU_MO_DATA))
69 fp.close()
70 fp = open(UMOFILE, 'wb')
71 fp.write(base64.decodebytes(UMO_DATA))
72 fp.close()
73 fp = open(MMOFILE, 'wb')
74 fp.write(base64.decodebytes(MMO_DATA))
75 fp.close()
76 self.env = support.EnvironmentVarGuard()
77 self.env['LANGUAGE'] = 'xx'
79 def tearDown(self):
80 self.env.__exit__()
81 del self.env
82 shutil.rmtree(os.path.split(LOCALEDIR)[0])
85 class GettextTestCase1(GettextBaseTest):
86 def setUp(self):
87 GettextBaseTest.setUp(self)
88 self.localedir = os.curdir
89 self.mofile = MOFILE
90 gettext.install('gettext', self.localedir)
92 def test_some_translations(self):
93 eq = self.assertEqual
94 # test some translations
95 eq(_('albatross'), 'albatross')
96 eq(_('mullusk'), 'bacon')
97 eq(_(r'Raymond Luxury Yach-t'), 'Throatwobbler Mangrove')
98 eq(_(r'nudge nudge'), 'wink wink')
100 def test_double_quotes(self):
101 eq = self.assertEqual
102 # double quotes
103 eq(_("albatross"), 'albatross')
104 eq(_("mullusk"), 'bacon')
105 eq(_(r"Raymond Luxury Yach-t"), 'Throatwobbler Mangrove')
106 eq(_(r"nudge nudge"), 'wink wink')
108 def test_triple_single_quotes(self):
109 eq = self.assertEqual
110 # triple single quotes
111 eq(_('''albatross'''), 'albatross')
112 eq(_('''mullusk'''), 'bacon')
113 eq(_(r'''Raymond Luxury Yach-t'''), 'Throatwobbler Mangrove')
114 eq(_(r'''nudge nudge'''), 'wink wink')
116 def test_triple_double_quotes(self):
117 eq = self.assertEqual
118 # triple double quotes
119 eq(_("""albatross"""), 'albatross')
120 eq(_("""mullusk"""), 'bacon')
121 eq(_(r"""Raymond Luxury Yach-t"""), 'Throatwobbler Mangrove')
122 eq(_(r"""nudge nudge"""), 'wink wink')
124 def test_multiline_strings(self):
125 eq = self.assertEqual
126 # multiline strings
127 eq(_('''This module provides internationalization and localization
128 support for your Python programs by providing an interface to the GNU
129 gettext message catalog library.'''),
130 '''Guvf zbqhyr cebivqrf vagreangvbanyvmngvba naq ybpnyvmngvba
131 fhccbeg sbe lbhe Clguba cebtenzf ol cebivqvat na vagresnpr gb gur TAH
132 trggrkg zrffntr pngnybt yvoenel.''')
134 def test_the_alternative_interface(self):
135 eq = self.assertEqual
136 # test the alternative interface
137 fp = open(self.mofile, 'rb')
138 t = gettext.GNUTranslations(fp)
139 fp.close()
140 # Install the translation object
141 t.install()
142 eq(_('nudge nudge'), 'wink wink')
143 # Try unicode return type
144 t.install()
145 eq(_('mullusk'), 'bacon')
146 # Test installation of other methods
147 import builtins
148 t.install(names=["gettext", "lgettext"])
149 eq(_, t.gettext)
150 eq(builtins.gettext, t.gettext)
151 eq(lgettext, t.lgettext)
152 del builtins.gettext
153 del builtins.lgettext
156 class GettextTestCase2(GettextBaseTest):
157 def setUp(self):
158 GettextBaseTest.setUp(self)
159 self.localedir = os.curdir
160 # Set up the bindings
161 gettext.bindtextdomain('gettext', self.localedir)
162 gettext.textdomain('gettext')
163 # For convenience
164 self._ = gettext.gettext
166 def test_bindtextdomain(self):
167 self.assertEqual(gettext.bindtextdomain('gettext'), self.localedir)
169 def test_textdomain(self):
170 self.assertEqual(gettext.textdomain(), 'gettext')
172 def test_some_translations(self):
173 eq = self.assertEqual
174 # test some translations
175 eq(self._('albatross'), 'albatross')
176 eq(self._('mullusk'), 'bacon')
177 eq(self._(r'Raymond Luxury Yach-t'), 'Throatwobbler Mangrove')
178 eq(self._(r'nudge nudge'), 'wink wink')
180 def test_double_quotes(self):
181 eq = self.assertEqual
182 # double quotes
183 eq(self._("albatross"), 'albatross')
184 eq(self._("mullusk"), 'bacon')
185 eq(self._(r"Raymond Luxury Yach-t"), 'Throatwobbler Mangrove')
186 eq(self._(r"nudge nudge"), 'wink wink')
188 def test_triple_single_quotes(self):
189 eq = self.assertEqual
190 # triple single quotes
191 eq(self._('''albatross'''), 'albatross')
192 eq(self._('''mullusk'''), 'bacon')
193 eq(self._(r'''Raymond Luxury Yach-t'''), 'Throatwobbler Mangrove')
194 eq(self._(r'''nudge nudge'''), 'wink wink')
196 def test_triple_double_quotes(self):
197 eq = self.assertEqual
198 # triple double quotes
199 eq(self._("""albatross"""), 'albatross')
200 eq(self._("""mullusk"""), 'bacon')
201 eq(self._(r"""Raymond Luxury Yach-t"""), 'Throatwobbler Mangrove')
202 eq(self._(r"""nudge nudge"""), 'wink wink')
204 def test_multiline_strings(self):
205 eq = self.assertEqual
206 # multiline strings
207 eq(self._('''This module provides internationalization and localization
208 support for your Python programs by providing an interface to the GNU
209 gettext message catalog library.'''),
210 '''Guvf zbqhyr cebivqrf vagreangvbanyvmngvba naq ybpnyvmngvba
211 fhccbeg sbe lbhe Clguba cebtenzf ol cebivqvat na vagresnpr gb gur TAH
212 trggrkg zrffntr pngnybt yvoenel.''')
215 class PluralFormsTestCase(GettextBaseTest):
216 def setUp(self):
217 GettextBaseTest.setUp(self)
218 self.mofile = MOFILE
220 def test_plural_forms1(self):
221 eq = self.assertEqual
222 x = gettext.ngettext('There is %s file', 'There are %s files', 1)
223 eq(x, 'Hay %s fichero')
224 x = gettext.ngettext('There is %s file', 'There are %s files', 2)
225 eq(x, 'Hay %s ficheros')
227 def test_plural_forms2(self):
228 eq = self.assertEqual
229 fp = open(self.mofile, 'rb')
230 t = gettext.GNUTranslations(fp)
231 fp.close()
232 x = t.ngettext('There is %s file', 'There are %s files', 1)
233 eq(x, 'Hay %s fichero')
234 x = t.ngettext('There is %s file', 'There are %s files', 2)
235 eq(x, 'Hay %s ficheros')
237 def test_hu(self):
238 eq = self.assertEqual
239 f = gettext.c2py('0')
240 s = ''.join([ str(f(x)) for x in range(200) ])
241 eq(s, "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
243 def test_de(self):
244 eq = self.assertEqual
245 f = gettext.c2py('n != 1')
246 s = ''.join([ str(f(x)) for x in range(200) ])
247 eq(s, "10111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111")
249 def test_fr(self):
250 eq = self.assertEqual
251 f = gettext.c2py('n>1')
252 s = ''.join([ str(f(x)) for x in range(200) ])
253 eq(s, "00111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111")
255 def test_gd(self):
256 eq = self.assertEqual
257 f = gettext.c2py('n==1 ? 0 : n==2 ? 1 : 2')
258 s = ''.join([ str(f(x)) for x in range(200) ])
259 eq(s, "20122222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222")
261 def test_gd2(self):
262 eq = self.assertEqual
263 # Tests the combination of parentheses and "?:"
264 f = gettext.c2py('n==1 ? 0 : (n==2 ? 1 : 2)')
265 s = ''.join([ str(f(x)) for x in range(200) ])
266 eq(s, "20122222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222")
268 def test_lt(self):
269 eq = self.assertEqual
270 f = gettext.c2py('n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2')
271 s = ''.join([ str(f(x)) for x in range(200) ])
272 eq(s, "20111111112222222222201111111120111111112011111111201111111120111111112011111111201111111120111111112011111111222222222220111111112011111111201111111120111111112011111111201111111120111111112011111111")
274 def test_ru(self):
275 eq = self.assertEqual
276 f = gettext.c2py('n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2')
277 s = ''.join([ str(f(x)) for x in range(200) ])
278 eq(s, "20111222222222222222201112222220111222222011122222201112222220111222222011122222201112222220111222222011122222222222222220111222222011122222201112222220111222222011122222201112222220111222222011122222")
280 def test_pl(self):
281 eq = self.assertEqual
282 f = gettext.c2py('n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2')
283 s = ''.join([ str(f(x)) for x in range(200) ])
284 eq(s, "20111222222222222222221112222222111222222211122222221112222222111222222211122222221112222222111222222211122222222222222222111222222211122222221112222222111222222211122222221112222222111222222211122222")
286 def test_sl(self):
287 eq = self.assertEqual
288 f = gettext.c2py('n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3')
289 s = ''.join([ str(f(x)) for x in range(200) ])
290 eq(s, "30122333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333012233333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333")
292 def test_security(self):
293 raises = self.assertRaises
294 # Test for a dangerous expression
295 raises(ValueError, gettext.c2py, "os.chmod('/etc/passwd',0777)")
298 class UnicodeTranslationsTest(GettextBaseTest):
299 def setUp(self):
300 GettextBaseTest.setUp(self)
301 fp = open(UMOFILE, 'rb')
302 try:
303 self.t = gettext.GNUTranslations(fp)
304 finally:
305 fp.close()
306 self._ = self.t.gettext
308 def test_unicode_msgid(self):
309 unless = self.failUnless
310 unless(isinstance(self._(''), str))
311 unless(isinstance(self._(''), str))
313 def test_unicode_msgstr(self):
314 eq = self.assertEqual
315 eq(self._('ab\xde'), '\xa4yz')
318 class WeirdMetadataTest(GettextBaseTest):
319 def setUp(self):
320 GettextBaseTest.setUp(self)
321 fp = open(MMOFILE, 'rb')
322 try:
323 try:
324 self.t = gettext.GNUTranslations(fp)
325 except:
326 self.tearDown()
327 raise
328 finally:
329 fp.close()
331 def test_weird_metadata(self):
332 info = self.t.info()
333 self.assertEqual(len(info), 9)
334 self.assertEqual(info['last-translator'],
335 'John Doe <jdoe@example.com>\nJane Foobar <jfoobar@example.com>')
338 def test_main():
339 support.run_unittest(__name__)
341 if __name__ == '__main__':
342 test_main()
345 # For reference, here's the .po file used to created the GNU_MO_DATA above.
347 # The original version was automatically generated from the sources with
348 # pygettext. Later it was manually modified to add plural forms support.
351 # Dummy translation for the Python test_gettext.py module.
352 # Copyright (C) 2001 Python Software Foundation
353 # Barry Warsaw <barry@python.org>, 2000.
355 msgid ""
356 msgstr ""
357 "Project-Id-Version: 2.0\n"
358 "PO-Revision-Date: 2003-04-11 14:32-0400\n"
359 "Last-Translator: J. David Ibanez <j-david@noos.fr>\n"
360 "Language-Team: XX <python-dev@python.org>\n"
361 "MIME-Version: 1.0\n"
362 "Content-Type: text/plain; charset=iso-8859-1\n"
363 "Content-Transfer-Encoding: 8bit\n"
364 "Generated-By: pygettext.py 1.1\n"
365 "Plural-Forms: nplurals=2; plural=n!=1;\n"
367 #: test_gettext.py:19 test_gettext.py:25 test_gettext.py:31 test_gettext.py:37
368 #: test_gettext.py:51 test_gettext.py:80 test_gettext.py:86 test_gettext.py:92
369 #: test_gettext.py:98
370 msgid "nudge nudge"
371 msgstr "wink wink"
373 #: test_gettext.py:16 test_gettext.py:22 test_gettext.py:28 test_gettext.py:34
374 #: test_gettext.py:77 test_gettext.py:83 test_gettext.py:89 test_gettext.py:95
375 msgid "albatross"
376 msgstr ""
378 #: test_gettext.py:18 test_gettext.py:24 test_gettext.py:30 test_gettext.py:36
379 #: test_gettext.py:79 test_gettext.py:85 test_gettext.py:91 test_gettext.py:97
380 msgid "Raymond Luxury Yach-t"
381 msgstr "Throatwobbler Mangrove"
383 #: test_gettext.py:17 test_gettext.py:23 test_gettext.py:29 test_gettext.py:35
384 #: test_gettext.py:56 test_gettext.py:78 test_gettext.py:84 test_gettext.py:90
385 #: test_gettext.py:96
386 msgid "mullusk"
387 msgstr "bacon"
389 #: test_gettext.py:40 test_gettext.py:101
390 msgid ""
391 "This module provides internationalization and localization\n"
392 "support for your Python programs by providing an interface to the GNU\n"
393 "gettext message catalog library."
394 msgstr ""
395 "Guvf zbqhyr cebivqrf vagreangvbanyvmngvba naq ybpnyvmngvba\n"
396 "fhccbeg sbe lbhe Clguba cebtenzf ol cebivqvat na vagresnpr gb gur TAH\n"
397 "trggrkg zrffntr pngnybt yvoenel."
399 # Manually added, as neither pygettext nor xgettext support plural forms
400 # in Python.
401 msgid "There is %s file"
402 msgid_plural "There are %s files"
403 msgstr[0] "Hay %s fichero"
404 msgstr[1] "Hay %s ficheros"
407 # Here's the second example po file example, used to generate the UMO_DATA
408 # containing utf-8 encoded Unicode strings
411 # Dummy translation for the Python test_gettext.py module.
412 # Copyright (C) 2001 Python Software Foundation
413 # Barry Warsaw <barry@python.org>, 2000.
415 msgid ""
416 msgstr ""
417 "Project-Id-Version: 2.0\n"
418 "PO-Revision-Date: 2003-04-11 12:42-0400\n"
419 "Last-Translator: Barry A. WArsaw <barry@python.org>\n"
420 "Language-Team: XX <python-dev@python.org>\n"
421 "MIME-Version: 1.0\n"
422 "Content-Type: text/plain; charset=utf-8\n"
423 "Content-Transfer-Encoding: 7bit\n"
424 "Generated-By: manually\n"
426 #: nofile:0
427 msgid "ab\xc3\x9e"
428 msgstr "\xc2\xa4yz"
431 # Here's the third example po file, used to generate MMO_DATA
434 msgid ""
435 msgstr ""
436 "Project-Id-Version: No Project 0.0\n"
437 "POT-Creation-Date: Wed Dec 11 07:44:15 2002\n"
438 "PO-Revision-Date: 2002-08-14 01:18:58+00:00\n"
439 "Last-Translator: John Doe <jdoe@example.com>\n"
440 "Jane Foobar <jfoobar@example.com>\n"
441 "Language-Team: xx <xx@example.com>\n"
442 "MIME-Version: 1.0\n"
443 "Content-Type: text/plain; charset=iso-8859-15\n"
444 "Content-Transfer-Encoding: quoted-printable\n"
445 "Generated-By: pygettext.py 1.3\n"