~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_export_pot.py

  • Committer: John Arbash Meinel
  • Author(s): Mark Hammond
  • Date: 2008-09-09 17:02:21 UTC
  • mto: This revision was merged to the branch mainline in revision 3697.
  • Revision ID: john@arbash-meinel.com-20080909170221-svim3jw2mrz0amp3
An updated transparent icon for bzr.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2011, 2016 Canonical Ltd
2
 
#
3
 
# This program is free software; you can redistribute it and/or modify
4
 
# it under the terms of the GNU General Public License as published by
5
 
# the Free Software Foundation; either version 2 of the License, or
6
 
# (at your option) any later version.
7
 
#
8
 
# This program is distributed in the hope that it will be useful,
9
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
 
# GNU General Public License for more details.
12
 
#
13
 
# You should have received a copy of the GNU General Public License
14
 
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
 
 
17
 
from cStringIO import StringIO
18
 
import textwrap
19
 
 
20
 
from bzrlib import (
21
 
    commands,
22
 
    export_pot,
23
 
    option,
24
 
    registry,
25
 
    tests,
26
 
    )
27
 
 
28
 
import re
29
 
 
30
 
 
31
 
class TestEscape(tests.TestCase):
32
 
 
33
 
    def test_simple_escape(self):
34
 
        self.assertEqual(
35
 
                export_pot._escape('foobar'),
36
 
                'foobar')
37
 
 
38
 
        s = '''foo\nbar\r\tbaz\\"spam"'''
39
 
        e = '''foo\\nbar\\r\\tbaz\\\\\\"spam\\"'''
40
 
        self.assertEqual(export_pot._escape(s), e)
41
 
 
42
 
    def test_complex_escape(self):
43
 
        s = '''\\r \\\n'''
44
 
        e = '''\\\\r \\\\\\n'''
45
 
        self.assertEqual(export_pot._escape(s), e)
46
 
 
47
 
 
48
 
class TestNormalize(tests.TestCase):
49
 
 
50
 
    def test_single_line(self):
51
 
        s = 'foobar'
52
 
        e = '"foobar"'
53
 
        self.assertEqual(export_pot._normalize(s), e)
54
 
 
55
 
        s = 'foo"bar'
56
 
        e = '"foo\\"bar"'
57
 
        self.assertEqual(export_pot._normalize(s), e)
58
 
 
59
 
    def test_multi_lines(self):
60
 
        s = 'foo\nbar\n'
61
 
        e = '""\n"foo\\n"\n"bar\\n"'
62
 
        self.assertEqual(export_pot._normalize(s), e)
63
 
 
64
 
        s = '\nfoo\nbar\n'
65
 
        e = ('""\n'
66
 
             '"\\n"\n'
67
 
             '"foo\\n"\n'
68
 
             '"bar\\n"')
69
 
        self.assertEqual(export_pot._normalize(s), e)
70
 
 
71
 
 
72
 
class TestParseSource(tests.TestCase):
73
 
    """Check mappings to line numbers generated from python source"""
74
 
 
75
 
    def test_classes(self):
76
 
        src = '''
77
 
class Ancient:
78
 
    """Old style class"""
79
 
 
80
 
class Modern(object):
81
 
    """New style class"""
82
 
'''
83
 
        cls_lines, _ = export_pot._parse_source(src)
84
 
        self.assertEqual(cls_lines,
85
 
            {"Ancient": 2, "Modern": 5})
86
 
 
87
 
    def test_classes_nested(self):
88
 
        src = '''
89
 
class Matroska(object):
90
 
    class Smaller(object):
91
 
        class Smallest(object):
92
 
            pass
93
 
'''
94
 
        cls_lines, _ = export_pot._parse_source(src)
95
 
        self.assertEqual(cls_lines,
96
 
            {"Matroska": 2, "Smaller": 3, "Smallest":4})
97
 
 
98
 
    def test_strings_docstrings(self):
99
 
        src = '''\
100
 
"""Module"""
101
 
 
102
 
def function():
103
 
    """Function"""
104
 
 
105
 
class Class(object):
106
 
    """Class"""
107
 
 
108
 
    def method(self):
109
 
        """Method"""
110
 
'''
111
 
        _, str_lines = export_pot._parse_source(src)
112
 
        self.assertEqual(str_lines,
113
 
            {"Module": 1, "Function": 4, "Class": 7, "Method": 10})
114
 
 
115
 
    def test_strings_literals(self):
116
 
        src = '''\
117
 
s = "One"
118
 
t = (2, "Two")
119
 
f = dict(key="Three")
120
 
'''
121
 
        _, str_lines = export_pot._parse_source(src)
122
 
        self.assertEqual(str_lines,
123
 
            {"One": 1, "Two": 2, "Three": 3})
124
 
 
125
 
    def test_strings_multiline(self):
126
 
        src = '''\
127
 
"""Start
128
 
 
129
 
End
130
 
"""
131
 
t = (
132
 
    "A"
133
 
    "B"
134
 
    "C"
135
 
    )
136
 
'''
137
 
        _, str_lines = export_pot._parse_source(src)
138
 
        self.assertEqual(str_lines,
139
 
            {"Start\n\nEnd\n": 1, "ABC": 6})
140
 
 
141
 
    def test_strings_multiline_escapes(self):
142
 
        src = '''\
143
 
s = "Escaped\\n"
144
 
r = r"Raw\\n"
145
 
t = (
146
 
    "A\\n\\n"
147
 
    "B\\n\\n"
148
 
    "C\\n\\n"
149
 
    )
150
 
'''
151
 
        _, str_lines = export_pot._parse_source(src)
152
 
        self.expectFailure("Escaped newlines confuses the multiline handling",
153
 
            self.assertNotEqual, str_lines,
154
 
            {"Escaped\n": 0, "Raw\\n": 2, "A\n\nB\n\nC\n\n": -2})
155
 
        self.assertEqual(str_lines,
156
 
            {"Escaped\n": 1, "Raw\\n": 2, "A\n\nB\n\nC\n\n": 4})
157
 
 
158
 
 
159
 
class TestModuleContext(tests.TestCase):
160
 
    """Checks for source context tracking objects"""
161
 
 
162
 
    def check_context(self, context, path, lineno):
163
 
        self.assertEqual((context.path, context.lineno), (path, lineno))
164
 
 
165
 
    def test___init__(self):
166
 
        context = export_pot._ModuleContext("one.py")
167
 
        self.check_context(context, "one.py", 1)
168
 
        context = export_pot._ModuleContext("two.py", 5)
169
 
        self.check_context(context, "two.py", 5)
170
 
 
171
 
    def test_from_class(self):
172
 
        """New context returned with lineno updated from class"""
173
 
        path = "cls.py"
174
 
        class A(object): pass
175
 
        class B(object): pass
176
 
        cls_lines = {"A": 5, "B": 7}
177
 
        context = export_pot._ModuleContext(path, _source_info=(cls_lines, {}))
178
 
        contextA = context.from_class(A)
179
 
        self.check_context(contextA, path, 5)
180
 
        contextB1 = context.from_class(B)
181
 
        self.check_context(contextB1, path, 7)
182
 
        contextB2 = contextA.from_class(B)
183
 
        self.check_context(contextB2, path, 7)
184
 
        self.check_context(context, path, 1)
185
 
        self.assertEqual("", self.get_log())
186
 
 
187
 
    def test_from_class_missing(self):
188
 
        """When class has no lineno the old context details are returned"""
189
 
        path = "cls_missing.py"
190
 
        class A(object): pass
191
 
        class M(object): pass
192
 
        context = export_pot._ModuleContext(path, 3, ({"A": 15}, {}))
193
 
        contextA = context.from_class(A)
194
 
        contextM1 = context.from_class(M)
195
 
        self.check_context(contextM1, path, 3)
196
 
        contextM2 = contextA.from_class(M)
197
 
        self.check_context(contextM2, path, 15)
198
 
        self.assertContainsRe(self.get_log(), "Definition of <.*M'> not found")
199
 
 
200
 
    def test_from_string(self):
201
 
        """New context returned with lineno updated from string"""
202
 
        path = "str.py"
203
 
        str_lines = {"one": 14, "two": 42}
204
 
        context = export_pot._ModuleContext(path, _source_info=({}, str_lines))
205
 
        context1 = context.from_string("one")
206
 
        self.check_context(context1, path, 14)
207
 
        context2A = context.from_string("two")
208
 
        self.check_context(context2A, path, 42)
209
 
        context2B = context1.from_string("two")
210
 
        self.check_context(context2B, path, 42)
211
 
        self.check_context(context, path, 1)
212
 
        self.assertEqual("", self.get_log())
213
 
 
214
 
    def test_from_string_missing(self):
215
 
        """When string has no lineno the old context details are returned"""
216
 
        path = "str_missing.py"
217
 
        context = export_pot._ModuleContext(path, 4, ({}, {"line\n": 21}))
218
 
        context1 = context.from_string("line\n")
219
 
        context2A = context.from_string("not there")
220
 
        self.check_context(context2A, path, 4)
221
 
        context2B = context1.from_string("not there")
222
 
        self.check_context(context2B, path, 21)
223
 
        self.assertContainsRe(self.get_log(), "String 'not there' not found")
224
 
 
225
 
 
226
 
class TestWriteOption(tests.TestCase):
227
 
    """Tests for writing texts extracted from options in pot format"""
228
 
 
229
 
    def pot_from_option(self, opt, context=None, note="test"):
230
 
        sio = StringIO()
231
 
        exporter = export_pot._PotExporter(sio)
232
 
        if context is None:
233
 
            context = export_pot._ModuleContext("nowhere", 0)
234
 
        export_pot._write_option(exporter, context, opt, note)
235
 
        return sio.getvalue()
236
 
 
237
 
    def test_option_without_help(self):
238
 
        opt = option.Option("helpless")
239
 
        self.assertEqual("", self.pot_from_option(opt))
240
 
 
241
 
    def test_option_with_help(self):
242
 
        opt = option.Option("helpful", help="Info.")
243
 
        self.assertContainsString(self.pot_from_option(opt), "\n"
244
 
            "# help of 'helpful' test\n"
245
 
            "msgid \"Info.\"\n")
246
 
 
247
 
    def test_option_hidden(self):
248
 
        opt = option.Option("hidden", help="Unseen.", hidden=True)
249
 
        self.assertEqual("", self.pot_from_option(opt))
250
 
 
251
 
    def test_option_context_missing(self):
252
 
        context = export_pot._ModuleContext("remote.py", 3)
253
 
        opt = option.Option("metaphor", help="Not a literal in the source.")
254
 
        self.assertContainsString(self.pot_from_option(opt, context),
255
 
            "#: remote.py:3\n"
256
 
            "# help of 'metaphor' test\n")
257
 
 
258
 
    def test_option_context_string(self):
259
 
        s = "Literally."
260
 
        context = export_pot._ModuleContext("local.py", 3, ({}, {s: 17}))
261
 
        opt = option.Option("example", help=s)
262
 
        self.assertContainsString(self.pot_from_option(opt, context),
263
 
            "#: local.py:17\n"
264
 
            "# help of 'example' test\n")
265
 
 
266
 
    def test_registry_option_title(self):
267
 
        opt = option.RegistryOption.from_kwargs("group", help="Pick one.",
268
 
            title="Choose!")
269
 
        pot = self.pot_from_option(opt)
270
 
        self.assertContainsString(pot, "\n"
271
 
            "# title of 'group' test\n"
272
 
            "msgid \"Choose!\"\n")
273
 
        self.assertContainsString(pot, "\n"
274
 
            "# help of 'group' test\n"
275
 
            "msgid \"Pick one.\"\n")
276
 
 
277
 
    def test_registry_option_title_context_missing(self):
278
 
        context = export_pot._ModuleContext("theory.py", 3)
279
 
        opt = option.RegistryOption.from_kwargs("abstract", title="Unfounded!")
280
 
        self.assertContainsString(self.pot_from_option(opt, context),
281
 
            "#: theory.py:3\n"
282
 
            "# title of 'abstract' test\n")
283
 
 
284
 
    def test_registry_option_title_context_string(self):
285
 
        s = "Grounded!"
286
 
        context = export_pot._ModuleContext("practice.py", 3, ({}, {s: 144}))
287
 
        opt = option.RegistryOption.from_kwargs("concrete", title=s)
288
 
        self.assertContainsString(self.pot_from_option(opt, context),
289
 
            "#: practice.py:144\n"
290
 
            "# title of 'concrete' test\n")
291
 
 
292
 
    def test_registry_option_value_switches(self):
293
 
        opt = option.RegistryOption.from_kwargs("switch", help="Flip one.",
294
 
            value_switches=True, enum_switch=False,
295
 
            red="Big.", green="Small.")
296
 
        pot = self.pot_from_option(opt)
297
 
        self.assertContainsString(pot, "\n"
298
 
            "# help of 'switch' test\n"
299
 
            "msgid \"Flip one.\"\n")
300
 
        self.assertContainsString(pot, "\n"
301
 
            "# help of 'switch=red' test\n"
302
 
            "msgid \"Big.\"\n")
303
 
        self.assertContainsString(pot, "\n"
304
 
            "# help of 'switch=green' test\n"
305
 
            "msgid \"Small.\"\n")
306
 
 
307
 
    def test_registry_option_value_switches_hidden(self):
308
 
        reg = registry.Registry()
309
 
        class Hider(object):
310
 
            hidden = True
311
 
        reg.register("new", 1, "Current.")
312
 
        reg.register("old", 0, "Legacy.", info=Hider())
313
 
        opt = option.RegistryOption("protocol", "Talking.", reg,
314
 
            value_switches=True, enum_switch=False)
315
 
        pot = self.pot_from_option(opt)
316
 
        self.assertContainsString(pot, "\n"
317
 
            "# help of 'protocol' test\n"
318
 
            "msgid \"Talking.\"\n")
319
 
        self.assertContainsString(pot, "\n"
320
 
            "# help of 'protocol=new' test\n"
321
 
            "msgid \"Current.\"\n")
322
 
        self.assertNotContainsString(pot, "'protocol=old'")
323
 
 
324
 
 
325
 
class TestPotExporter(tests.TestCase):
326
 
    """Test for logic specific to the _PotExporter class"""
327
 
 
328
 
    # This test duplicates test_duplicates below
329
 
    def test_duplicates(self):
330
 
        exporter = export_pot._PotExporter(StringIO())
331
 
        context = export_pot._ModuleContext("mod.py", 1)
332
 
        exporter.poentry_in_context(context, "Common line.")
333
 
        context.lineno = 3
334
 
        exporter.poentry_in_context(context, "Common line.")
335
 
        self.assertEqual(1, exporter.outf.getvalue().count("Common line."))
336
 
    
337
 
    def test_duplicates_included(self):
338
 
        exporter = export_pot._PotExporter(StringIO(), True)
339
 
        context = export_pot._ModuleContext("mod.py", 1)
340
 
        exporter.poentry_in_context(context, "Common line.")
341
 
        context.lineno = 3
342
 
        exporter.poentry_in_context(context, "Common line.")
343
 
        self.assertEqual(2, exporter.outf.getvalue().count("Common line."))
344
 
 
345
 
 
346
 
class PoEntryTestCase(tests.TestCase):
347
 
 
348
 
    def setUp(self):
349
 
        super(PoEntryTestCase, self).setUp()
350
 
        self.exporter = export_pot._PotExporter(StringIO())
351
 
 
352
 
    def check_output(self, expected):
353
 
        self.assertEqual(
354
 
                self.exporter.outf.getvalue(),
355
 
                textwrap.dedent(expected)
356
 
                )
357
 
 
358
 
 
359
 
class TestPoEntry(PoEntryTestCase):
360
 
 
361
 
    def test_simple(self):
362
 
        self.exporter.poentry('dummy', 1, "spam")
363
 
        self.exporter.poentry('dummy', 2, "ham", 'EGG')
364
 
        self.check_output('''\
365
 
                #: dummy:1
366
 
                msgid "spam"
367
 
                msgstr ""
368
 
 
369
 
                #: dummy:2
370
 
                # EGG
371
 
                msgid "ham"
372
 
                msgstr ""
373
 
 
374
 
                ''')
375
 
 
376
 
    def test_duplicate(self):
377
 
        self.exporter.poentry('dummy', 1, "spam")
378
 
        # This should be ignored.
379
 
        self.exporter.poentry('dummy', 2, "spam", 'EGG')
380
 
 
381
 
        self.check_output('''\
382
 
                #: dummy:1
383
 
                msgid "spam"
384
 
                msgstr ""\n
385
 
                ''')
386
 
 
387
 
 
388
 
class TestPoentryPerPergraph(PoEntryTestCase):
389
 
 
390
 
    def test_single(self):
391
 
        self.exporter.poentry_per_paragraph(
392
 
                'dummy',
393
 
                10,
394
 
                '''foo\nbar\nbaz\n'''
395
 
                )
396
 
        self.check_output('''\
397
 
                #: dummy:10
398
 
                msgid ""
399
 
                "foo\\n"
400
 
                "bar\\n"
401
 
                "baz\\n"
402
 
                msgstr ""\n
403
 
                ''')
404
 
 
405
 
    def test_multi(self):
406
 
        self.exporter.poentry_per_paragraph(
407
 
                'dummy',
408
 
                10,
409
 
                '''spam\nham\negg\n\nSPAM\nHAM\nEGG\n'''
410
 
                )
411
 
        self.check_output('''\
412
 
                #: dummy:10
413
 
                msgid ""
414
 
                "spam\\n"
415
 
                "ham\\n"
416
 
                "egg"
417
 
                msgstr ""
418
 
 
419
 
                #: dummy:14
420
 
                msgid ""
421
 
                "SPAM\\n"
422
 
                "HAM\\n"
423
 
                "EGG\\n"
424
 
                msgstr ""\n
425
 
                ''')
426
 
 
427
 
 
428
 
class TestExportCommandHelp(PoEntryTestCase):
429
 
 
430
 
    def test_command_help(self):
431
 
 
432
 
        class cmd_Demo(commands.Command):
433
 
            __doc__ = """A sample command.
434
 
 
435
 
            :Usage:
436
 
                bzr demo
437
 
 
438
 
            :Examples:
439
 
                Example 1::
440
 
 
441
 
                    cmd arg1
442
 
 
443
 
            Blah Blah Blah
444
 
            """
445
 
 
446
 
        export_pot._write_command_help(self.exporter, cmd_Demo())
447
 
        result = self.exporter.outf.getvalue()
448
 
        # We don't care about filename and lineno here.
449
 
        result = re.sub(r'(?m)^#: [^\n]+\n', '', result)
450
 
 
451
 
        self.assertEqualDiff(
452
 
                'msgid "A sample command."\n'
453
 
                'msgstr ""\n'
454
 
                '\n'                # :Usage: should not be translated.
455
 
                'msgid ""\n'
456
 
                '":Examples:\\n"\n'
457
 
                '"    Example 1::"\n'
458
 
                'msgstr ""\n'
459
 
                '\n'
460
 
                'msgid "        cmd arg1"\n'
461
 
                'msgstr ""\n'
462
 
                '\n'
463
 
                'msgid "Blah Blah Blah"\n'
464
 
                'msgstr ""\n'
465
 
                '\n',
466
 
                result
467
 
                )