/brz/remove-bazaar

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