~ubuntu-branches/ubuntu/trusty/python-babel/trusty

« back to all changes in this revision

Viewing changes to tests/messages/test_catalog.py

  • Committer: Package Import Robot
  • Author(s): Chuck Short
  • Date: 2013-10-28 10:11:31 UTC
  • mfrom: (4.1.2 sid)
  • Revision ID: package-import@ubuntu.com-20131028101131-zwbmm8sc29iemmlr
Tags: 1.3-2ubuntu1
* Merge from Debian unstable.  Remaining changes:
  - debian/rules: Run the testsuite during builds.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- coding: utf-8 -*-
 
2
#
 
3
# Copyright (C) 2007-2011 Edgewall Software
 
4
# All rights reserved.
 
5
#
 
6
# This software is licensed as described in the file COPYING, which
 
7
# you should have received as part of this distribution. The terms
 
8
# are also available at http://babel.edgewall.org/wiki/License.
 
9
#
 
10
# This software consists of voluntary contributions made by many
 
11
# individuals. For the exact contribution history, see the revision
 
12
# history and logs, available at http://babel.edgewall.org/log/.
 
13
 
 
14
import copy
 
15
import datetime
 
16
import unittest
 
17
 
 
18
from babel.dates import format_datetime, UTC
 
19
from babel.messages import catalog
 
20
from babel.util import FixedOffsetTimezone
 
21
 
 
22
 
 
23
class MessageTestCase(unittest.TestCase):
 
24
 
 
25
    def test_python_format(self):
 
26
        assert catalog.PYTHON_FORMAT.search('foo %d bar')
 
27
        assert catalog.PYTHON_FORMAT.search('foo %s bar')
 
28
        assert catalog.PYTHON_FORMAT.search('foo %r bar')
 
29
        assert catalog.PYTHON_FORMAT.search('foo %(name).1f')
 
30
        assert catalog.PYTHON_FORMAT.search('foo %(name)3.3f')
 
31
        assert catalog.PYTHON_FORMAT.search('foo %(name)3f')
 
32
        assert catalog.PYTHON_FORMAT.search('foo %(name)06d')
 
33
        assert catalog.PYTHON_FORMAT.search('foo %(name)Li')
 
34
        assert catalog.PYTHON_FORMAT.search('foo %(name)#d')
 
35
        assert catalog.PYTHON_FORMAT.search('foo %(name)-4.4hs')
 
36
        assert catalog.PYTHON_FORMAT.search('foo %(name)*.3f')
 
37
        assert catalog.PYTHON_FORMAT.search('foo %(name).*f')
 
38
        assert catalog.PYTHON_FORMAT.search('foo %(name)3.*f')
 
39
        assert catalog.PYTHON_FORMAT.search('foo %(name)*.*f')
 
40
        assert catalog.PYTHON_FORMAT.search('foo %()s')
 
41
 
 
42
    def test_translator_comments(self):
 
43
        mess = catalog.Message('foo', user_comments=['Comment About `foo`'])
 
44
        self.assertEqual(mess.user_comments, ['Comment About `foo`'])
 
45
        mess = catalog.Message('foo',
 
46
                               auto_comments=['Comment 1 About `foo`',
 
47
                                         'Comment 2 About `foo`'])
 
48
        self.assertEqual(mess.auto_comments, ['Comment 1 About `foo`',
 
49
                                         'Comment 2 About `foo`'])
 
50
 
 
51
    def test_clone_message_object(self):
 
52
        msg = catalog.Message('foo', locations=[('foo.py', 42)])
 
53
        clone = msg.clone()
 
54
        clone.locations.append(('bar.py', 42))
 
55
        self.assertEqual(msg.locations, [('foo.py', 42)])
 
56
        msg.flags.add('fuzzy')
 
57
        assert not clone.fuzzy and msg.fuzzy
 
58
 
 
59
 
 
60
class CatalogTestCase(unittest.TestCase):
 
61
    def test_add_returns_message_instance(self):
 
62
        cat = catalog.Catalog()
 
63
        message = cat.add('foo')
 
64
        self.assertEquals('foo', message.id)
 
65
 
 
66
    def test_two_messages_with_same_singular(self):
 
67
        cat = catalog.Catalog()
 
68
        cat.add('foo')
 
69
        cat.add(('foo', 'foos'))
 
70
        self.assertEqual(1, len(cat))
 
71
 
 
72
    def test_duplicate_auto_comment(self):
 
73
        cat = catalog.Catalog()
 
74
        cat.add('foo', auto_comments=['A comment'])
 
75
        cat.add('foo', auto_comments=['A comment', 'Another comment'])
 
76
        self.assertEqual(['A comment', 'Another comment'],
 
77
                         cat['foo'].auto_comments)
 
78
 
 
79
    def test_duplicate_user_comment(self):
 
80
        cat = catalog.Catalog()
 
81
        cat.add('foo', user_comments=['A comment'])
 
82
        cat.add('foo', user_comments=['A comment', 'Another comment'])
 
83
        self.assertEqual(['A comment', 'Another comment'],
 
84
                         cat['foo'].user_comments)
 
85
 
 
86
    def test_duplicate_location(self):
 
87
        cat = catalog.Catalog()
 
88
        cat.add('foo', locations=[('foo.py', 1)])
 
89
        cat.add('foo', locations=[('foo.py', 1)])
 
90
        self.assertEqual([('foo.py', 1)], cat['foo'].locations)
 
91
 
 
92
    def test_update_message_changed_to_plural(self):
 
93
        cat = catalog.Catalog()
 
94
        cat.add(u'foo', u'Voh')
 
95
        tmpl = catalog.Catalog()
 
96
        tmpl.add((u'foo', u'foos'))
 
97
        cat.update(tmpl)
 
98
        self.assertEqual((u'Voh', ''), cat['foo'].string)
 
99
        assert cat['foo'].fuzzy
 
100
 
 
101
    def test_update_message_changed_to_simple(self):
 
102
        cat = catalog.Catalog()
 
103
        cat.add((u'foo' u'foos'), (u'Voh', u'Vöhs'))
 
104
        tmpl = catalog.Catalog()
 
105
        tmpl.add(u'foo')
 
106
        cat.update(tmpl)
 
107
        self.assertEqual(u'Voh', cat['foo'].string)
 
108
        assert cat['foo'].fuzzy
 
109
 
 
110
    def test_update_message_updates_comments(self):
 
111
        cat = catalog.Catalog()
 
112
        cat[u'foo'] = catalog.Message('foo', locations=[('main.py', 5)])
 
113
        self.assertEqual(cat[u'foo'].auto_comments, [])
 
114
        self.assertEqual(cat[u'foo'].user_comments, [])
 
115
        # Update cat[u'foo'] with a new location and a comment
 
116
        cat[u'foo'] = catalog.Message('foo', locations=[('main.py', 7)],
 
117
                                      user_comments=['Foo Bar comment 1'])
 
118
        self.assertEqual(cat[u'foo'].user_comments, ['Foo Bar comment 1'])
 
119
        # now add yet another location with another comment
 
120
        cat[u'foo'] = catalog.Message('foo', locations=[('main.py', 9)],
 
121
                                      auto_comments=['Foo Bar comment 2'])
 
122
        self.assertEqual(cat[u'foo'].auto_comments, ['Foo Bar comment 2'])
 
123
 
 
124
    def test_update_fuzzy_matching_with_case_change(self):
 
125
        cat = catalog.Catalog()
 
126
        cat.add('foo', 'Voh')
 
127
        cat.add('bar', 'Bahr')
 
128
        tmpl = catalog.Catalog()
 
129
        tmpl.add('Foo')
 
130
        cat.update(tmpl)
 
131
        self.assertEqual(1, len(cat.obsolete))
 
132
        assert 'foo' not in cat
 
133
 
 
134
        self.assertEqual('Voh', cat['Foo'].string)
 
135
        self.assertEqual(True, cat['Foo'].fuzzy)
 
136
 
 
137
    def test_update_fuzzy_matching_with_char_change(self):
 
138
        cat = catalog.Catalog()
 
139
        cat.add('fo', 'Voh')
 
140
        cat.add('bar', 'Bahr')
 
141
        tmpl = catalog.Catalog()
 
142
        tmpl.add('foo')
 
143
        cat.update(tmpl)
 
144
        self.assertEqual(1, len(cat.obsolete))
 
145
        assert 'fo' not in cat
 
146
 
 
147
        self.assertEqual('Voh', cat['foo'].string)
 
148
        self.assertEqual(True, cat['foo'].fuzzy)
 
149
 
 
150
    def test_update_fuzzy_matching_no_msgstr(self):
 
151
        cat = catalog.Catalog()
 
152
        cat.add('fo', '')
 
153
        tmpl = catalog.Catalog()
 
154
        tmpl.add('fo')
 
155
        tmpl.add('foo')
 
156
        cat.update(tmpl)
 
157
        assert 'fo' in cat
 
158
        assert 'foo' in cat
 
159
 
 
160
        self.assertEqual('', cat['fo'].string)
 
161
        self.assertEqual(False, cat['fo'].fuzzy)
 
162
        self.assertEqual(None, cat['foo'].string)
 
163
        self.assertEqual(False, cat['foo'].fuzzy)
 
164
 
 
165
    def test_update_fuzzy_matching_with_new_context(self):
 
166
        cat = catalog.Catalog()
 
167
        cat.add('foo', 'Voh')
 
168
        cat.add('bar', 'Bahr')
 
169
        tmpl = catalog.Catalog()
 
170
        tmpl.add('Foo', context='Menu')
 
171
        cat.update(tmpl)
 
172
        self.assertEqual(1, len(cat.obsolete))
 
173
        assert 'foo' not in cat
 
174
 
 
175
        message = cat.get('Foo', 'Menu')
 
176
        self.assertEqual('Voh', message.string)
 
177
        self.assertEqual(True, message.fuzzy)
 
178
        self.assertEqual('Menu', message.context)
 
179
 
 
180
    def test_update_fuzzy_matching_with_changed_context(self):
 
181
        cat = catalog.Catalog()
 
182
        cat.add('foo', 'Voh', context='Menu|File')
 
183
        cat.add('bar', 'Bahr', context='Menu|File')
 
184
        tmpl = catalog.Catalog()
 
185
        tmpl.add('Foo', context='Menu|Edit')
 
186
        cat.update(tmpl)
 
187
        self.assertEqual(1, len(cat.obsolete))
 
188
        assert cat.get('Foo', 'Menu|File') is None
 
189
 
 
190
        message = cat.get('Foo', 'Menu|Edit')
 
191
        self.assertEqual('Voh', message.string)
 
192
        self.assertEqual(True, message.fuzzy)
 
193
        self.assertEqual('Menu|Edit', message.context)
 
194
 
 
195
    def test_update_fuzzy_matching_no_cascading(self):
 
196
        cat = catalog.Catalog()
 
197
        cat.add('fo', 'Voh')
 
198
        cat.add('foo', 'Vohe')
 
199
        tmpl = catalog.Catalog()
 
200
        tmpl.add('fo')
 
201
        tmpl.add('foo')
 
202
        tmpl.add('fooo')
 
203
        cat.update(tmpl)
 
204
        assert 'fo' in cat
 
205
        assert 'foo' in cat
 
206
 
 
207
        self.assertEqual('Voh', cat['fo'].string)
 
208
        self.assertEqual(False, cat['fo'].fuzzy)
 
209
        self.assertEqual('Vohe', cat['foo'].string)
 
210
        self.assertEqual(False, cat['foo'].fuzzy)
 
211
        self.assertEqual('Vohe', cat['fooo'].string)
 
212
        self.assertEqual(True, cat['fooo'].fuzzy)
 
213
 
 
214
    def test_update_without_fuzzy_matching(self):
 
215
        cat = catalog.Catalog()
 
216
        cat.add('fo', 'Voh')
 
217
        cat.add('bar', 'Bahr')
 
218
        tmpl = catalog.Catalog()
 
219
        tmpl.add('foo')
 
220
        cat.update(tmpl, no_fuzzy_matching=True)
 
221
        self.assertEqual(2, len(cat.obsolete))
 
222
 
 
223
    def test_fuzzy_matching_regarding_plurals(self):
 
224
        cat = catalog.Catalog()
 
225
        cat.add(('foo', 'foh'), ('foo', 'foh'))
 
226
        ru = copy.copy(cat)
 
227
        ru.locale = 'ru_RU'
 
228
        ru.update(cat)
 
229
        self.assertEqual(True, ru['foo'].fuzzy)
 
230
        ru = copy.copy(cat)
 
231
        ru.locale = 'ru_RU'
 
232
        ru['foo'].string = ('foh', 'fohh', 'fohhh')
 
233
        ru.update(cat)
 
234
        self.assertEqual(False, ru['foo'].fuzzy)
 
235
 
 
236
    def test_update_no_template_mutation(self):
 
237
        tmpl = catalog.Catalog()
 
238
        tmpl.add('foo')
 
239
        cat1 = catalog.Catalog()
 
240
        cat1.add('foo', 'Voh')
 
241
        cat1.update(tmpl)
 
242
        cat2 = catalog.Catalog()
 
243
        cat2.update(tmpl)
 
244
 
 
245
        self.assertEqual(None, cat2['foo'].string)
 
246
        self.assertEqual(False, cat2['foo'].fuzzy)
 
247
 
 
248
    def test_update_po_updates_pot_creation_date(self):
 
249
        template = catalog.Catalog()
 
250
        localized_catalog = copy.deepcopy(template)
 
251
        localized_catalog.locale = 'de_DE'
 
252
        self.assertNotEqual(template.mime_headers,
 
253
                            localized_catalog.mime_headers)
 
254
        self.assertEqual(template.creation_date,
 
255
                         localized_catalog.creation_date)
 
256
        template.creation_date = datetime.datetime.now() - \
 
257
                                                datetime.timedelta(minutes=5)
 
258
        localized_catalog.update(template)
 
259
        self.assertEqual(template.creation_date,
 
260
                         localized_catalog.creation_date)
 
261
 
 
262
    def test_update_po_keeps_po_revision_date(self):
 
263
        template = catalog.Catalog()
 
264
        localized_catalog = copy.deepcopy(template)
 
265
        localized_catalog.locale = 'de_DE'
 
266
        fake_rev_date = datetime.datetime.now() - datetime.timedelta(days=5)
 
267
        localized_catalog.revision_date = fake_rev_date
 
268
        self.assertNotEqual(template.mime_headers,
 
269
                            localized_catalog.mime_headers)
 
270
        self.assertEqual(template.creation_date,
 
271
                         localized_catalog.creation_date)
 
272
        template.creation_date = datetime.datetime.now() - \
 
273
                                                datetime.timedelta(minutes=5)
 
274
        localized_catalog.update(template)
 
275
        self.assertEqual(localized_catalog.revision_date, fake_rev_date)
 
276
 
 
277
    def test_stores_datetime_correctly(self):
 
278
        localized = catalog.Catalog()
 
279
        localized.locale = 'de_DE'
 
280
        localized[''] = catalog.Message('',
 
281
                       "POT-Creation-Date: 2009-03-09 15:47-0700\n" +
 
282
                       "PO-Revision-Date: 2009-03-09 15:47-0700\n")
 
283
        for key, value in localized.mime_headers:
 
284
            if key in ('POT-Creation-Date', 'PO-Revision-Date'):
 
285
                self.assertEqual(value, '2009-03-09 15:47-0700')
 
286
 
 
287
    def test_mime_headers_contain_same_information_as_attributes(self):
 
288
        cat = catalog.Catalog()
 
289
        cat[''] = catalog.Message('',
 
290
                      "Last-Translator: Foo Bar <foo.bar@example.com>\n" +
 
291
                      "Language-Team: de <de@example.com>\n" +
 
292
                      "POT-Creation-Date: 2009-03-01 11:20+0200\n" +
 
293
                      "PO-Revision-Date: 2009-03-09 15:47-0700\n")
 
294
        self.assertEqual(None, cat.locale)
 
295
        mime_headers = dict(cat.mime_headers)
 
296
 
 
297
        self.assertEqual('Foo Bar <foo.bar@example.com>', cat.last_translator)
 
298
        self.assertEqual('Foo Bar <foo.bar@example.com>',
 
299
                         mime_headers['Last-Translator'])
 
300
 
 
301
        self.assertEqual('de <de@example.com>', cat.language_team)
 
302
        self.assertEqual('de <de@example.com>', mime_headers['Language-Team'])
 
303
 
 
304
        dt = datetime.datetime(2009, 3, 9, 15, 47, tzinfo=FixedOffsetTimezone(-7 * 60))
 
305
        self.assertEqual(dt, cat.revision_date)
 
306
        formatted_dt = format_datetime(dt, 'yyyy-MM-dd HH:mmZ', locale='en')
 
307
        self.assertEqual(formatted_dt, mime_headers['PO-Revision-Date'])
 
308
 
 
309
 
 
310
def test_message_fuzzy():
 
311
    assert not catalog.Message('foo').fuzzy
 
312
    msg = catalog.Message('foo', 'foo', flags=['fuzzy'])
 
313
    assert msg.fuzzy
 
314
    assert msg.id == 'foo'
 
315
 
 
316
def test_message_pluralizable():
 
317
    assert not catalog.Message('foo').pluralizable
 
318
    assert catalog.Message(('foo', 'bar')).pluralizable
 
319
 
 
320
def test_message_python_format():
 
321
    assert catalog.Message('foo %(name)s bar').python_format
 
322
    assert catalog.Message(('foo %(name)s', 'foo %(name)s')).python_format
 
323
 
 
324
 
 
325
def test_catalog():
 
326
    cat = catalog.Catalog(project='Foobar', version='1.0',
 
327
                          copyright_holder='Foo Company')
 
328
    assert cat.header_comment == (
 
329
        '# Translations template for Foobar.\n'
 
330
        '# Copyright (C) %(year)d Foo Company\n'
 
331
        '# This file is distributed under the same '
 
332
            'license as the Foobar project.\n'
 
333
        '# FIRST AUTHOR <EMAIL@ADDRESS>, %(year)d.\n'
 
334
        '#') % {'year': datetime.date.today().year}
 
335
 
 
336
    cat = catalog.Catalog(project='Foobar', version='1.0',
 
337
                          copyright_holder='Foo Company')
 
338
    cat.header_comment = (
 
339
        '# The POT for my really cool PROJECT project.\n'
 
340
        '# Copyright (C) 1990-2003 ORGANIZATION\n'
 
341
        '# This file is distributed under the same license as the PROJECT\n'
 
342
        '# project.\n'
 
343
        '#\n')
 
344
    assert cat.header_comment == (
 
345
        '# The POT for my really cool Foobar project.\n'
 
346
        '# Copyright (C) 1990-2003 Foo Company\n'
 
347
        '# This file is distributed under the same license as the Foobar\n'
 
348
        '# project.\n'
 
349
        '#\n')
 
350
 
 
351
 
 
352
def test_catalog_mime_headers():
 
353
    created = datetime.datetime(1990, 4, 1, 15, 30, tzinfo=UTC)
 
354
    cat = catalog.Catalog(project='Foobar', version='1.0',
 
355
                          creation_date=created)
 
356
    assert cat.mime_headers == [
 
357
        ('Project-Id-Version', 'Foobar 1.0'),
 
358
        ('Report-Msgid-Bugs-To', 'EMAIL@ADDRESS'),
 
359
        ('POT-Creation-Date', '1990-04-01 15:30+0000'),
 
360
        ('PO-Revision-Date', 'YEAR-MO-DA HO:MI+ZONE'),
 
361
        ('Last-Translator', 'FULL NAME <EMAIL@ADDRESS>'),
 
362
        ('Language-Team', 'LANGUAGE <LL@li.org>'),
 
363
        ('MIME-Version', '1.0'),
 
364
        ('Content-Type', 'text/plain; charset=utf-8'),
 
365
        ('Content-Transfer-Encoding', '8bit'),
 
366
        ('Generated-By', 'Babel %s\n' % catalog.VERSION),
 
367
    ]
 
368
 
 
369
 
 
370
def test_catalog_mime_headers_set_locale():
 
371
    created = datetime.datetime(1990, 4, 1, 15, 30, tzinfo=UTC)
 
372
    revised = datetime.datetime(1990, 8, 3, 12, 0, tzinfo=UTC)
 
373
    cat = catalog.Catalog(locale='de_DE', project='Foobar', version='1.0',
 
374
                          creation_date=created, revision_date=revised,
 
375
                          last_translator='John Doe <jd@example.com>',
 
376
                          language_team='de_DE <de@example.com>')
 
377
    assert cat.mime_headers == [
 
378
        ('Project-Id-Version', 'Foobar 1.0'),
 
379
        ('Report-Msgid-Bugs-To', 'EMAIL@ADDRESS'),
 
380
        ('POT-Creation-Date', '1990-04-01 15:30+0000'),
 
381
        ('PO-Revision-Date', '1990-08-03 12:00+0000'),
 
382
        ('Last-Translator', 'John Doe <jd@example.com>'),
 
383
        ('Language-Team', 'de_DE <de@example.com>'),
 
384
        ('Plural-Forms', 'nplurals=2; plural=(n != 1)'),
 
385
        ('MIME-Version', '1.0'),
 
386
        ('Content-Type', 'text/plain; charset=utf-8'),
 
387
        ('Content-Transfer-Encoding', '8bit'),
 
388
        ('Generated-By', 'Babel %s\n' % catalog.VERSION),
 
389
    ]
 
390
 
 
391
 
 
392
def test_catalog_num_plurals():
 
393
    assert catalog.Catalog(locale='en').num_plurals == 2
 
394
    assert catalog.Catalog(locale='ga').num_plurals == 3
 
395
 
 
396
 
 
397
def test_catalog_plural_expr():
 
398
    assert catalog.Catalog(locale='en').plural_expr == '(n != 1)'
 
399
    assert (catalog.Catalog(locale='ga').plural_expr
 
400
            == '(n==1 ? 0 : n==2 ? 1 : 2)')
 
401
 
 
402
 
 
403
def test_catalog_plural_forms():
 
404
    assert (catalog.Catalog(locale='en').plural_forms
 
405
            == 'nplurals=2; plural=(n != 1)')
 
406
    assert (catalog.Catalog(locale='pt_BR').plural_forms
 
407
            == 'nplurals=2; plural=(n > 1)')
 
408
 
 
409
 
 
410
def test_catalog_setitem():
 
411
    cat = catalog.Catalog()
 
412
    cat[u'foo'] = catalog.Message(u'foo')
 
413
    assert cat[u'foo'].id == 'foo'
 
414
 
 
415
    cat = catalog.Catalog()
 
416
    cat[u'foo'] = catalog.Message(u'foo', locations=[('main.py', 1)])
 
417
    assert cat[u'foo'].locations == [('main.py', 1)]
 
418
    cat[u'foo'] = catalog.Message(u'foo', locations=[('utils.py', 5)])
 
419
    assert cat[u'foo'].locations == [('main.py', 1), ('utils.py', 5)]
 
420
 
 
421
 
 
422
def test_catalog_add():
 
423
    cat = catalog.Catalog()
 
424
    foo = cat.add(u'foo')
 
425
    assert foo.id == 'foo'
 
426
    assert cat[u'foo'] is foo
 
427
 
 
428
 
 
429
def test_catalog_update():
 
430
    template = catalog.Catalog()
 
431
    template.add('green', locations=[('main.py', 99)])
 
432
    template.add('blue', locations=[('main.py', 100)])
 
433
    template.add(('salad', 'salads'), locations=[('util.py', 42)])
 
434
    cat = catalog.Catalog(locale='de_DE')
 
435
    cat.add('blue', u'blau', locations=[('main.py', 98)])
 
436
    cat.add('head', u'Kopf', locations=[('util.py', 33)])
 
437
    cat.add(('salad', 'salads'), (u'Salat', u'Salate'),
 
438
                locations=[('util.py', 38)])
 
439
 
 
440
    cat.update(template)
 
441
    assert len(cat) == 3
 
442
 
 
443
    msg1 = cat['green']
 
444
    msg1.string
 
445
    assert msg1.locations == [('main.py', 99)]
 
446
 
 
447
    msg2 = cat['blue']
 
448
    assert msg2.string == u'blau'
 
449
    assert msg2.locations == [('main.py', 100)]
 
450
 
 
451
    msg3 = cat['salad']
 
452
    assert msg3.string == (u'Salat', u'Salate')
 
453
    assert msg3.locations == [('util.py', 42)]
 
454
 
 
455
    assert not 'head' in cat
 
456
    assert list(cat.obsolete.values())[0].id == 'head'