/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
5830.2.18 by INADA Naoki
Add some tests for export_pot module.
1
# Copyright (C) 2011 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
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
20
from bzrlib 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,
23
    tests,
24
    )
25
5875.3.20 by INADA Naoki
Add test for exporting command help.
26
import re
27
28
5830.2.18 by INADA Naoki
Add some tests for export_pot module.
29
class TestEscape(tests.TestCase):
30
31
    def test_simple_escape(self):
32
        self.assertEqual(
33
                export_pot._escape('foobar'),
34
                'foobar')
35
36
        s = '''foo\nbar\r\tbaz\\"spam"'''
37
        e = '''foo\\nbar\\r\\tbaz\\\\\\"spam\\"'''
38
        self.assertEqual(export_pot._escape(s), e)
39
40
    def test_complex_escape(self):
41
        s = '''\\r \\\n'''
42
        e = '''\\\\r \\\\\\n'''
43
        self.assertEqual(export_pot._escape(s), e)
44
45
46
class TestNormalize(tests.TestCase):
47
48
    def test_single_line(self):
49
        s = 'foobar'
50
        e = '"foobar"'
51
        self.assertEqual(export_pot._normalize(s), e)
52
53
        s = 'foo"bar'
54
        e = '"foo\\"bar"'
55
        self.assertEqual(export_pot._normalize(s), e)
56
57
    def test_multi_lines(self):
58
        s = 'foo\nbar\n'
59
        e = '""\n"foo\\n"\n"bar\\n"'
60
        self.assertEqual(export_pot._normalize(s), e)
61
62
        s = '\nfoo\nbar\n'
63
        e = ('""\n'
64
             '"\\n"\n'
65
             '"foo\\n"\n'
66
             '"bar\\n"')
67
        self.assertEqual(export_pot._normalize(s), e)
68
69
6282.2.2 by Martin Packman
Add export_pot._ModuleContext class for more structured source location tracking, and share option writing logic
70
class TestParseSource(tests.TestCase):
71
    """Check mappings to line numbers generated from python source"""
72
73
    def test_classes(self):
74
        src = '''
75
class Ancient:
76
    """Old style class"""
77
78
class Modern(object):
79
    """New style class"""
80
'''
81
        cls_lines, _ = export_pot._parse_source(src)
82
        self.assertEqual(cls_lines,
83
            {"Ancient": 2, "Modern": 5})
84
85
    def test_classes_nested(self):
86
        src = '''
87
class Matroska(object):
88
    class Smaller(object):
89
        class Smallest(object):
90
            pass
91
'''
92
        cls_lines, _ = export_pot._parse_source(src)
93
        self.assertEqual(cls_lines,
94
            {"Matroska": 2, "Smaller": 3, "Smallest":4})
95
96
    def test_strings_docstrings(self):
97
        src = '''\
98
"""Module"""
99
100
def function():
101
    """Function"""
102
103
class Class(object):
104
    """Class"""
105
106
    def method(self):
107
        """Method"""
108
'''
109
        _, str_lines = export_pot._parse_source(src)
110
        self.assertEqual(str_lines,
111
            {"Module": 1, "Function": 4, "Class": 7, "Method": 10})
112
113
    def test_strings_literals(self):
114
        src = '''\
115
s = "One"
116
t = (2, "Two")
117
f = dict(key="Three")
118
'''
119
        _, str_lines = export_pot._parse_source(src)
120
        self.assertEqual(str_lines,
121
            {"One": 1, "Two": 2, "Three": 3})
122
123
    def test_strings_multiline(self):
124
        src = '''\
125
"""Start
126
127
End
128
"""
129
t = (
130
    "A"
131
    "B"
132
    "C"
133
    )
134
'''
135
        _, str_lines = export_pot._parse_source(src)
136
        self.assertEqual(str_lines,
137
            {"Start\n\nEnd\n": 1, "ABC": 6})
138
139
    def test_strings_multiline_escapes(self):
140
        src = '''\
141
s = "Escaped\\n"
142
r = r"Raw\\n"
143
t = (
144
    "A\\n\\n"
145
    "B\\n\\n"
146
    "C\\n\\n"
147
    )
148
'''
149
        _, str_lines = export_pot._parse_source(src)
150
        self.expectFailure("Escaped newlines confuses the multiline handling",
151
            self.assertNotEqual, str_lines,
152
            {"Escaped\n": 0, "Raw\\n": 2, "A\n\nB\n\nC\n\n": -2})
153
        self.assertEqual(str_lines,
154
            {"Escaped\n": 1, "Raw\\n": 2, "A\n\nB\n\nC\n\n": 4})
155
156
157
class TestModuleContext(tests.TestCase):
158
    """Checks for source context tracking objects"""
159
160
    def check_context(self, context, path, lineno):
161
        self.assertEquals((context.path, context.lineno), (path, lineno))
162
163
    def test___init__(self):
164
        context = export_pot._ModuleContext("one.py")
165
        self.check_context(context, "one.py", 1)
166
        context = export_pot._ModuleContext("two.py", 5)
167
        self.check_context(context, "two.py", 5)
168
169
    def test_from_class(self):
170
        """New context returned with lineno updated from class"""
171
        path = "cls.py"
172
        class A(object): pass
173
        class B(object): pass
174
        cls_lines = {"A": 5, "B": 7}
175
        context = export_pot._ModuleContext(path, _source_info=(cls_lines, {}))
176
        contextA = context.from_class(A)
177
        self.check_context(contextA, path, 5)
178
        contextB1 = context.from_class(B)
179
        self.check_context(contextB1, path, 7)
180
        contextB2 = contextA.from_class(B)
181
        self.check_context(contextB2, path, 7)
182
        self.check_context(context, path, 1)
183
        self.assertEquals("", self.get_log())
184
185
    def test_from_class_missing(self):
186
        """When class has no lineno the old context details are returned"""
187
        path = "cls_missing.py"
188
        class A(object): pass
189
        class M(object): pass
190
        context = export_pot._ModuleContext(path, 3, ({"A": 15}, {}))
191
        contextA = context.from_class(A)
192
        contextM1 = context.from_class(M)
193
        self.check_context(contextM1, path, 3)
194
        contextM2 = contextA.from_class(M)
195
        self.check_context(contextM2, path, 15)
196
        self.assertContainsRe(self.get_log(), "Definition of <.*M'> not found")
197
198
    def test_from_string(self):
199
        """New context returned with lineno updated from string"""
200
        path = "str.py"
201
        str_lines = {"one": 14, "two": 42}
202
        context = export_pot._ModuleContext(path, _source_info=({}, str_lines))
203
        context1 = context.from_string("one")
204
        self.check_context(context1, path, 14)
205
        context2A = context.from_string("two")
206
        self.check_context(context2A, path, 42)
207
        context2B = context1.from_string("two")
208
        self.check_context(context2B, path, 42)
209
        self.check_context(context, path, 1)
210
        self.assertEquals("", self.get_log())
211
212
    def test_from_string_missing(self):
213
        """When string has no lineno the old context details are returned"""
214
        path = "str_missing.py"
215
        context = export_pot._ModuleContext(path, 4, ({}, {"line\n": 21}))
216
        context1 = context.from_string("line\n")
217
        context2A = context.from_string("not there")
218
        self.check_context(context2A, path, 4)
219
        context2B = context1.from_string("not there")
220
        self.check_context(context2B, path, 21)
221
        self.assertContainsRe(self.get_log(), "String 'not there' not found")
222
223
5830.2.20 by INADA Naoki
Add test for _poentry_per_peragraph()
224
class PoEntryTestCase(tests.TestCase):
5830.2.18 by INADA Naoki
Add some tests for export_pot module.
225
226
    def setUp(self):
5830.2.20 by INADA Naoki
Add test for _poentry_per_peragraph()
227
        super(PoEntryTestCase, self).setUp()
6282.2.1 by Martin Packman
Add export_pot._PotExporter class to avoid module global, and other minor cleanups
228
        self.exporter = export_pot._PotExporter(StringIO())
5830.2.20 by INADA Naoki
Add test for _poentry_per_peragraph()
229
230
    def check_output(self, expected):
231
        self.assertEqual(
6282.2.1 by Martin Packman
Add export_pot._PotExporter class to avoid module global, and other minor cleanups
232
                self.exporter.outf.getvalue(),
5830.2.20 by INADA Naoki
Add test for _poentry_per_peragraph()
233
                textwrap.dedent(expected)
234
                )
235
6282.2.2 by Martin Packman
Add export_pot._ModuleContext class for more structured source location tracking, and share option writing logic
236
5830.2.20 by INADA Naoki
Add test for _poentry_per_peragraph()
237
class TestPoEntry(PoEntryTestCase):
5830.2.18 by INADA Naoki
Add some tests for export_pot module.
238
239
    def test_simple(self):
6282.2.1 by Martin Packman
Add export_pot._PotExporter class to avoid module global, and other minor cleanups
240
        self.exporter.poentry('dummy', 1, "spam")
241
        self.exporter.poentry('dummy', 2, "ham", 'EGG')
5830.2.20 by INADA Naoki
Add test for _poentry_per_peragraph()
242
        self.check_output('''\
243
                #: dummy:1
244
                msgid "spam"
245
                msgstr ""
246
247
                #: dummy:2
248
                # EGG
249
                msgid "ham"
250
                msgstr ""
251
252
                ''')
5830.2.18 by INADA Naoki
Add some tests for export_pot module.
253
254
    def test_duplicate(self):
6282.2.1 by Martin Packman
Add export_pot._PotExporter class to avoid module global, and other minor cleanups
255
        self.exporter.poentry('dummy', 1, "spam")
5830.2.18 by INADA Naoki
Add some tests for export_pot module.
256
        # This should be ignored.
6282.2.1 by Martin Packman
Add export_pot._PotExporter class to avoid module global, and other minor cleanups
257
        self.exporter.poentry('dummy', 2, "spam", 'EGG')
5830.2.18 by INADA Naoki
Add some tests for export_pot module.
258
5830.2.20 by INADA Naoki
Add test for _poentry_per_peragraph()
259
        self.check_output('''\
260
                #: dummy:1
261
                msgid "spam"
262
                msgstr ""\n
263
                ''')
264
265
266
class TestPoentryPerPergraph(PoEntryTestCase):
267
268
    def test_single(self):
6282.2.1 by Martin Packman
Add export_pot._PotExporter class to avoid module global, and other minor cleanups
269
        self.exporter.poentry_per_paragraph(
5830.2.20 by INADA Naoki
Add test for _poentry_per_peragraph()
270
                'dummy',
271
                10,
272
                '''foo\nbar\nbaz\n'''
273
                )
274
        self.check_output('''\
275
                #: dummy:10
276
                msgid ""
277
                "foo\\n"
278
                "bar\\n"
279
                "baz\\n"
280
                msgstr ""\n
281
                ''')
282
283
    def test_multi(self):
6282.2.1 by Martin Packman
Add export_pot._PotExporter class to avoid module global, and other minor cleanups
284
        self.exporter.poentry_per_paragraph(
5830.2.20 by INADA Naoki
Add test for _poentry_per_peragraph()
285
                'dummy',
286
                10,
287
                '''spam\nham\negg\n\nSPAM\nHAM\nEGG\n'''
288
                )
289
        self.check_output('''\
290
                #: dummy:10
291
                msgid ""
292
                "spam\\n"
293
                "ham\\n"
294
                "egg"
295
                msgstr ""
296
297
                #: dummy:14
298
                msgid ""
299
                "SPAM\\n"
300
                "HAM\\n"
301
                "EGG\\n"
302
                msgstr ""\n
303
                ''')
5875.3.20 by INADA Naoki
Add test for exporting command help.
304
305
306
class TestExportCommandHelp(PoEntryTestCase):
307
308
    def test_command_help(self):
309
310
        class cmd_Demo(commands.Command):
311
            __doc__ = """A sample command.
312
313
            :Usage:
314
                bzr demo
315
316
            :Examples:
317
                Example 1::
318
319
                    cmd arg1
320
321
            Blah Blah Blah
322
            """
323
6282.2.1 by Martin Packman
Add export_pot._PotExporter class to avoid module global, and other minor cleanups
324
        export_pot._write_command_help(self.exporter, cmd_Demo())
325
        result = self.exporter.outf.getvalue()
5993.1.2 by Vincent Ladeuil
Fix python2.6 compatibility.
326
        # We don't care about filename and lineno here.
327
        result = re.sub(r'(?m)^#: [^\n]+\n', '', result)
5875.3.20 by INADA Naoki
Add test for exporting command help.
328
329
        self.assertEqualDiff(
330
                'msgid "A sample command."\n'
331
                'msgstr ""\n'
332
                '\n'                # :Usage: should not be translated.
333
                'msgid ""\n'
334
                '":Examples:\\n"\n'
335
                '"    Example 1::"\n'
336
                'msgstr ""\n'
337
                '\n'
338
                'msgid "        cmd arg1"\n'
339
                'msgstr ""\n'
340
                '\n'
341
                'msgid "Blah Blah Blah"\n'
342
                'msgstr ""\n'
343
                '\n',
344
                result
345
                )