/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)
7008.2.2 by Martin
Fix regressed tests and add to python3.passing
224
        self.assertContainsRe(self.get_log(), "String b?'not there' not found")
6282.2.2 by Martin Packman
Add export_pot._ModuleContext class for more structured source location tracking, and share option writing logic
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")
6973.11.1 by Jelmer Vernooij
Fix export_pot.
240
        self.assertEqual(b"", self.pot_from_option(opt))
6282.2.3 by Martin Packman
Export registry help to pot for unhidden option value switches
241
242
    def test_option_with_help(self):
243
        opt = option.Option("helpful", help="Info.")
6973.11.1 by Jelmer Vernooij
Fix export_pot.
244
        self.assertContainsString(self.pot_from_option(opt), b"\n"
245
            b"# help of 'helpful' test\n"
246
            b"msgid \"Info.\"\n")
6282.2.3 by Martin Packman
Export registry help to pot for unhidden option value switches
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),
6973.11.1 by Jelmer Vernooij
Fix export_pot.
256
            b"#: remote.py:3\n"
257
            b"# help of 'metaphor' test\n")
6282.2.3 by Martin Packman
Export registry help to pot for unhidden option value switches
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),
6973.11.1 by Jelmer Vernooij
Fix export_pot.
264
            b"#: local.py:17\n"
265
            b"# help of 'example' test\n")
6282.2.3 by Martin Packman
Export registry help to pot for unhidden option value switches
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)
6973.11.1 by Jelmer Vernooij
Fix export_pot.
271
        self.assertContainsString(pot, b"\n"
272
            b"# title of 'group' test\n"
273
            b"msgid \"Choose!\"\n")
274
        self.assertContainsString(pot, b"\n"
275
            b"# help of 'group' test\n"
276
            b"msgid \"Pick one.\"\n")
6282.2.3 by Martin Packman
Export registry help to pot for unhidden option value switches
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),
6973.11.1 by Jelmer Vernooij
Fix export_pot.
282
            b"#: theory.py:3\n"
283
            b"# title of 'abstract' test\n")
6282.2.3 by Martin Packman
Export registry help to pot for unhidden option value switches
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),
6973.11.1 by Jelmer Vernooij
Fix export_pot.
290
            b"#: practice.py:144\n"
291
            b"# title of 'concrete' test\n")
6282.2.3 by Martin Packman
Export registry help to pot for unhidden option value switches
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)
6973.11.1 by Jelmer Vernooij
Fix export_pot.
298
        self.assertContainsString(pot, b"\n"
299
            b"# help of 'switch' test\n"
300
            b"msgid \"Flip one.\"\n")
301
        self.assertContainsString(pot, b"\n"
302
            b"# help of 'switch=red' test\n"
303
            b"msgid \"Big.\"\n")
304
        self.assertContainsString(pot, b"\n"
305
            b"# help of 'switch=green' test\n"
306
            b"msgid \"Small.\"\n")
6282.2.3 by Martin Packman
Export registry help to pot for unhidden option value switches
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)
6973.11.1 by Jelmer Vernooij
Fix export_pot.
317
        self.assertContainsString(pot, b"\n"
318
            b"# help of 'protocol' test\n"
319
            b"msgid \"Talking.\"\n")
320
        self.assertContainsString(pot, b"\n"
321
            b"# help of 'protocol=new' test\n"
322
            b"msgid \"Current.\"\n")
323
        self.assertNotContainsString(pot, b"'protocol=old'")
6282.2.3 by Martin Packman
Export registry help to pot for unhidden option value switches
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.")
6973.11.1 by Jelmer Vernooij
Fix export_pot.
336
        self.assertEqual(1, exporter.outf.getvalue().count(b"Common line."))
337
6351.2.1 by Martin Packman
Add export-pot --include-duplicates option for permitting multiple entries with the same msgid
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.")
6973.11.1 by Jelmer Vernooij
Fix export_pot.
344
        self.assertEqual(2, exporter.outf.getvalue().count(b"Common line."))
6351.2.1 by Martin Packman
Add export-pot --include-duplicates option for permitting multiple entries with the same msgid
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(),
6973.11.1 by Jelmer Vernooij
Fix export_pot.
356
                textwrap.dedent(expected.decode('utf-8')).encode('utf-8')
5830.2.20 by INADA Naoki
Add test for _poentry_per_peragraph()
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')
6973.11.1 by Jelmer Vernooij
Fix export_pot.
365
        self.check_output(b'''\
5830.2.20 by INADA Naoki
Add test for _poentry_per_peragraph()
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
6973.11.1 by Jelmer Vernooij
Fix export_pot.
382
        self.check_output(b'''\
5830.2.20 by INADA Naoki
Add test for _poentry_per_peragraph()
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
                )
6973.11.1 by Jelmer Vernooij
Fix export_pot.
397
        self.check_output(b'''\
5830.2.20 by INADA Naoki
Add test for _poentry_per_peragraph()
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
                )
6973.11.1 by Jelmer Vernooij
Fix export_pot.
412
        self.check_output(b'''\
5830.2.20 by INADA Naoki
Add test for _poentry_per_peragraph()
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.
6973.11.1 by Jelmer Vernooij
Fix export_pot.
450
        result = re.sub(br'(?m)^#: [^\n]+\n', b'', result)
5875.3.20 by INADA Naoki
Add test for exporting command help.
451
452
        self.assertEqualDiff(
6973.11.1 by Jelmer Vernooij
Fix export_pot.
453
                b'msgid "A sample command."\n'
454
                b'msgstr ""\n'
455
                b'\n'                # :Usage: should not be translated.
456
                b'msgid ""\n'
457
                b'":Examples:\\n"\n'
458
                b'"    Example 1::"\n'
459
                b'msgstr ""\n'
460
                b'\n'
461
                b'msgid "        cmd arg1"\n'
462
                b'msgstr ""\n'
463
                b'\n'
464
                b'msgid "Blah Blah Blah"\n'
465
                b'msgstr ""\n'
466
                b'\n',
5875.3.20 by INADA Naoki
Add test for exporting command help.
467
                result
468
                )