1"""
2    test_build_gettext
3    ~~~~~~~~~~~~~~~~~~
4
5    Test the build process with gettext builder with the test root.
6
7    :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
8    :license: BSD, see LICENSE for details.
9"""
10
11import gettext
12import os
13import re
14import subprocess
15from subprocess import PIPE, CalledProcessError
16
17import pytest
18
19from sphinx.util.osutil import cd
20
21
22@pytest.mark.sphinx('gettext', srcdir='root-gettext')
23def test_build_gettext(app):
24    # Generic build; should fail only when the builder is horribly broken.
25    app.builder.build_all()
26
27    # Do messages end up in the correct location?
28    # top-level documents end up in a message catalog
29    assert (app.outdir / 'extapi.pot').isfile()
30    # directory items are grouped into sections
31    assert (app.outdir / 'subdir.pot').isfile()
32
33    # regression test for issue #960
34    catalog = (app.outdir / 'markup.pot').read_text()
35    assert 'msgid "something, something else, something more"' in catalog
36
37
38@pytest.mark.sphinx('gettext', srcdir='root-gettext')
39def test_msgfmt(app):
40    app.builder.build_all()
41    (app.outdir / 'en' / 'LC_MESSAGES').makedirs()
42    with cd(app.outdir):
43        try:
44            args = ['msginit', '--no-translator', '-i', 'markup.pot', '--locale', 'en_US']
45            subprocess.run(args, stdout=PIPE, stderr=PIPE, check=True)
46        except OSError:
47            pytest.skip()  # most likely msginit was not found
48        except CalledProcessError as exc:
49            print(exc.stdout)
50            print(exc.stderr)
51            assert False, 'msginit exited with return code %s' % exc.returncode
52
53        assert (app.outdir / 'en_US.po').isfile(), 'msginit failed'
54        try:
55            args = ['msgfmt', 'en_US.po',
56                    '-o', os.path.join('en', 'LC_MESSAGES', 'test_root.mo')]
57            subprocess.run(args, stdout=PIPE, stderr=PIPE, check=True)
58        except OSError:
59            pytest.skip()  # most likely msgfmt was not found
60        except CalledProcessError as exc:
61            print(exc.stdout)
62            print(exc.stderr)
63            assert False, 'msgfmt exited with return code %s' % exc.returncode
64
65        mo = app.outdir / 'en' / 'LC_MESSAGES' / 'test_root.mo'
66        assert mo.isfile(), 'msgfmt failed'
67
68    _ = gettext.translation('test_root', app.outdir, languages=['en']).gettext
69    assert _("Testing various markup") == "Testing various markup"
70
71
72@pytest.mark.sphinx(
73    'gettext', testroot='intl', srcdir='gettext',
74    confoverrides={'gettext_compact': False})
75def test_gettext_index_entries(app):
76    # regression test for #976
77    app.builder.build(['index_entries'])
78
79    _msgid_getter = re.compile(r'msgid "(.*)"').search
80
81    def msgid_getter(msgid):
82        m = _msgid_getter(msgid)
83        if m:
84            return m.groups()[0]
85        return None
86
87    pot = (app.outdir / 'index_entries.pot').read_text()
88    msgids = [_f for _f in map(msgid_getter, pot.splitlines()) if _f]
89
90    expected_msgids = [
91        "i18n with index entries",
92        "index target section",
93        "this is :index:`Newsletter` target paragraph.",
94        "various index entries",
95        "That's all.",
96        "Mailing List",
97        "Newsletter",
98        "Recipients List",
99        "First",
100        "Second",
101        "Third",
102        "Entry",
103        "See",
104        "Module",
105        "Keyword",
106        "Operator",
107        "Object",
108        "Exception",
109        "Statement",
110        "Builtin",
111    ]
112    for expect in expected_msgids:
113        assert expect in msgids
114        msgids.remove(expect)
115
116    # unexpected msgid existent
117    assert msgids == []
118
119
120@pytest.mark.sphinx(
121    'gettext', testroot='intl', srcdir='gettext',
122    confoverrides={'gettext_compact': False,
123                   'gettext_additional_targets': []})
124def test_gettext_disable_index_entries(app):
125    # regression test for #976
126    app.builder.build(['index_entries'])
127
128    _msgid_getter = re.compile(r'msgid "(.*)"').search
129
130    def msgid_getter(msgid):
131        m = _msgid_getter(msgid)
132        if m:
133            return m.groups()[0]
134        return None
135
136    pot = (app.outdir / 'index_entries.pot').read_text()
137    msgids = [_f for _f in map(msgid_getter, pot.splitlines()) if _f]
138
139    expected_msgids = [
140        "i18n with index entries",
141        "index target section",
142        "this is :index:`Newsletter` target paragraph.",
143        "various index entries",
144        "That's all.",
145    ]
146    for expect in expected_msgids:
147        assert expect in msgids
148        msgids.remove(expect)
149
150    # unexpected msgid existent
151    assert msgids == []
152
153
154@pytest.mark.sphinx('gettext', testroot='intl', srcdir='gettext')
155def test_gettext_template(app):
156    app.builder.build_all()
157    assert (app.outdir / 'sphinx.pot').isfile()
158
159    result = (app.outdir / 'sphinx.pot').read_text()
160    assert "Welcome" in result
161    assert "Sphinx %(version)s" in result
162
163
164@pytest.mark.sphinx('gettext', testroot='gettext-template')
165def test_gettext_template_msgid_order_in_sphinxpot(app):
166    app.builder.build_all()
167    assert (app.outdir / 'sphinx.pot').isfile()
168
169    result = (app.outdir / 'sphinx.pot').read_text()
170    assert re.search(
171        ('msgid "Template 1".*'
172         'msgid "This is Template 1\\.".*'
173         'msgid "Template 2".*'
174         'msgid "This is Template 2\\.".*'),
175        result,
176        flags=re.S)
177
178
179@pytest.mark.sphinx(
180    'gettext', srcdir='root-gettext',
181    confoverrides={'gettext_compact': 'documentation'})
182def test_build_single_pot(app):
183    app.builder.build_all()
184
185    assert (app.outdir / 'documentation.pot').isfile()
186
187    result = (app.outdir / 'documentation.pot').read_text()
188    assert re.search(
189        ('msgid "Todo".*'
190         'msgid "Like footnotes.".*'
191         'msgid "The minute.".*'
192         'msgid "Generated section".*'),
193        result,
194        flags=re.S)
195