1"""
2    test_build_latex
3    ~~~~~~~~~~~~~~~~
4
5    Test the build process with LaTeX 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 os
12import re
13import subprocess
14from itertools import product
15from shutil import copyfile
16from subprocess import PIPE, CalledProcessError
17
18import pytest
19
20from sphinx.builders.latex import default_latex_documents
21from sphinx.config import Config
22from sphinx.errors import SphinxError
23from sphinx.testing.util import strip_escseq
24from sphinx.util import docutils
25from sphinx.util.osutil import cd, ensuredir
26from sphinx.writers.latex import LaTeXTranslator
27
28from .test_build_html import ENV_WARNINGS
29
30LATEX_ENGINES = ['pdflatex', 'lualatex', 'xelatex']
31DOCCLASSES = ['howto', 'manual']
32STYLEFILES = ['article.cls', 'fancyhdr.sty', 'titlesec.sty', 'amsmath.sty',
33              'framed.sty', 'color.sty', 'fancyvrb.sty',
34              'fncychap.sty', 'geometry.sty', 'kvoptions.sty', 'hyperref.sty']
35
36LATEX_WARNINGS = ENV_WARNINGS + """\
37%(root)s/index.rst:\\d+: WARNING: unknown option: &option
38%(root)s/index.rst:\\d+: WARNING: citation not found: missing
39%(root)s/index.rst:\\d+: WARNING: a suitable image for latex builder not found: foo.\\*
40%(root)s/index.rst:\\d+: WARNING: Could not lex literal_block as "c". Highlighting skipped.
41"""
42
43
44# only run latex if all needed packages are there
45def kpsetest(*filenames):
46    try:
47        subprocess.run(['kpsewhich'] + list(filenames), stdout=PIPE, stderr=PIPE, check=True)
48        return True
49    except (OSError, CalledProcessError):
50        return False  # command not found or exit with non-zero
51
52
53# compile latex document with app.config.latex_engine
54def compile_latex_document(app, filename='python.tex'):
55    # now, try to run latex over it
56    try:
57        with cd(app.outdir):
58            ensuredir(app.config.latex_engine)
59            # keep a copy of latex file for this engine in case test fails
60            copyfile(filename, app.config.latex_engine + '/' + filename)
61            args = [app.config.latex_engine,
62                    '--halt-on-error',
63                    '--interaction=nonstopmode',
64                    '-output-directory=%s' % app.config.latex_engine,
65                    filename]
66            subprocess.run(args, stdout=PIPE, stderr=PIPE, check=True)
67    except OSError as exc:  # most likely the latex executable was not found
68        raise pytest.skip.Exception from exc
69    except CalledProcessError as exc:
70        print(exc.stdout)
71        print(exc.stderr)
72        assert False, '%s exited with return code %s' % (app.config.latex_engine,
73                                                         exc.returncode)
74
75
76def skip_if_requested(testfunc):
77    if 'SKIP_LATEX_BUILD' in os.environ:
78        msg = 'Skip LaTeX builds because SKIP_LATEX_BUILD is set'
79        return pytest.mark.skipif(True, reason=msg)(testfunc)
80    else:
81        return testfunc
82
83
84def skip_if_stylefiles_notfound(testfunc):
85    if kpsetest(*STYLEFILES) is False:
86        msg = 'not running latex, the required styles do not seem to be installed'
87        return pytest.mark.skipif(True, reason=msg)(testfunc)
88    else:
89        return testfunc
90
91
92@skip_if_requested
93@skip_if_stylefiles_notfound
94@pytest.mark.parametrize(
95    "engine,docclass",
96    product(LATEX_ENGINES, DOCCLASSES),
97)
98@pytest.mark.sphinx('latex')
99def test_build_latex_doc(app, status, warning, engine, docclass):
100    app.config.latex_engine = engine
101    app.config.latex_documents = [app.config.latex_documents[0][:4] + (docclass,)]
102    app.builder.init()
103
104    LaTeXTranslator.ignore_missing_images = True
105    app.builder.build_all()
106
107    # file from latex_additional_files
108    assert (app.outdir / 'svgimg.svg').isfile()
109
110    compile_latex_document(app, 'sphinxtests.tex')
111
112
113@pytest.mark.sphinx('latex')
114def test_writer(app, status, warning):
115    app.builder.build_all()
116    result = (app.outdir / 'sphinxtests.tex').read_text()
117
118    assert ('\\begin{sphinxfigure-in-table}\n\\centering\n\\capstart\n'
119            '\\noindent\\sphinxincludegraphics{{img}.png}\n'
120            '\\sphinxfigcaption{figure in table}\\label{\\detokenize{markup:id8}}'
121            '\\end{sphinxfigure-in-table}\\relax' in result)
122
123    assert ('\\begin{wrapfigure}{r}{0pt}\n\\centering\n'
124            '\\noindent\\sphinxincludegraphics{{rimg}.png}\n'
125            '\\caption{figure with align option}\\label{\\detokenize{markup:id9}}'
126            '\\end{wrapfigure}' in result)
127
128    assert ('\\begin{wrapfigure}{r}{0.500\\linewidth}\n\\centering\n'
129            '\\noindent\\sphinxincludegraphics{{rimg}.png}\n'
130            '\\caption{figure with align \\& figwidth option}'
131            '\\label{\\detokenize{markup:id10}}'
132            '\\end{wrapfigure}' in result)
133
134    assert ('\\begin{wrapfigure}{r}{3cm}\n\\centering\n'
135            '\\noindent\\sphinxincludegraphics[width=3cm]{{rimg}.png}\n'
136            '\\caption{figure with align \\& width option}'
137            '\\label{\\detokenize{markup:id11}}'
138            '\\end{wrapfigure}' in result)
139
140    assert 'Footnotes' not in result
141
142
143@pytest.mark.sphinx('latex', testroot='warnings', freshenv=True)
144def test_latex_warnings(app, status, warning):
145    app.builder.build_all()
146
147    warnings = strip_escseq(re.sub(re.escape(os.sep) + '{1,2}', '/', warning.getvalue()))
148    warnings_exp = LATEX_WARNINGS % {
149        'root': re.escape(app.srcdir.replace(os.sep, '/'))}
150    assert re.match(warnings_exp + '$', warnings), \
151        'Warnings don\'t match:\n' + \
152        '--- Expected (regex):\n' + warnings_exp + \
153        '--- Got:\n' + warnings
154
155
156@pytest.mark.sphinx('latex', testroot='basic')
157def test_latex_basic(app, status, warning):
158    app.builder.build_all()
159    result = (app.outdir / 'test.tex').read_text()
160    print(result)
161    print(status.getvalue())
162    print(warning.getvalue())
163    assert r'\title{The basic Sphinx documentation for testing}' in result
164    assert r'\release{}' in result
165    assert r'\renewcommand{\releasename}{}' in result
166
167
168@pytest.mark.sphinx('latex', testroot='basic',
169                    confoverrides={
170                        'latex_documents': [('index', 'test.tex', 'title', 'author', 'manual')]
171                    })
172def test_latex_basic_manual(app, status, warning):
173    app.builder.build_all()
174    result = (app.outdir / 'test.tex').read_text(encoding='utf8')
175    print(result)
176    assert r'\def\sphinxdocclass{report}' in result
177    assert r'\documentclass[letterpaper,10pt,english]{sphinxmanual}' in result
178
179
180@pytest.mark.sphinx('latex', testroot='basic',
181                    confoverrides={
182                        'latex_documents': [('index', 'test.tex', 'title', 'author', 'howto')]
183                    })
184def test_latex_basic_howto(app, status, warning):
185    app.builder.build_all()
186    result = (app.outdir / 'test.tex').read_text(encoding='utf8')
187    print(result)
188    assert r'\def\sphinxdocclass{article}' in result
189    assert r'\documentclass[letterpaper,10pt,english]{sphinxhowto}' in result
190
191
192@pytest.mark.sphinx('latex', testroot='basic',
193                    confoverrides={
194                        'language': 'ja',
195                        'latex_documents': [('index', 'test.tex', 'title', 'author', 'manual')]
196                    })
197def test_latex_basic_manual_ja(app, status, warning):
198    app.builder.build_all()
199    result = (app.outdir / 'test.tex').read_text(encoding='utf8')
200    print(result)
201    assert r'\def\sphinxdocclass{jsbook}' in result
202    assert r'\documentclass[letterpaper,10pt,dvipdfmx]{sphinxmanual}' in result
203
204
205@pytest.mark.sphinx('latex', testroot='basic',
206                    confoverrides={
207                        'language': 'ja',
208                        'latex_documents': [('index', 'test.tex', 'title', 'author', 'howto')]
209                    })
210def test_latex_basic_howto_ja(app, status, warning):
211    app.builder.build_all()
212    result = (app.outdir / 'test.tex').read_text(encoding='utf8')
213    print(result)
214    assert r'\def\sphinxdocclass{jreport}' in result
215    assert r'\documentclass[letterpaper,10pt,dvipdfmx]{sphinxhowto}' in result
216
217
218@pytest.mark.sphinx('latex', testroot='latex-theme')
219def test_latex_theme(app, status, warning):
220    app.builder.build_all()
221    result = (app.outdir / 'python.tex').read_text(encoding='utf8')
222    print(result)
223    assert r'\def\sphinxdocclass{book}' in result
224    assert r'\documentclass[a4paper,12pt,english]{sphinxbook}' in result
225
226
227@pytest.mark.sphinx('latex', testroot='latex-theme',
228                    confoverrides={'latex_elements': {'papersize': 'b5paper',
229                                                      'pointsize': '9pt'}})
230def test_latex_theme_papersize(app, status, warning):
231    app.builder.build_all()
232    result = (app.outdir / 'python.tex').read_text(encoding='utf8')
233    print(result)
234    assert r'\def\sphinxdocclass{book}' in result
235    assert r'\documentclass[b5paper,9pt,english]{sphinxbook}' in result
236
237
238@pytest.mark.sphinx('latex', testroot='latex-theme',
239                    confoverrides={'latex_theme_options': {'papersize': 'b5paper',
240                                                           'pointsize': '9pt'}})
241def test_latex_theme_options(app, status, warning):
242    app.builder.build_all()
243    result = (app.outdir / 'python.tex').read_text(encoding='utf8')
244    print(result)
245    assert r'\def\sphinxdocclass{book}' in result
246    assert r'\documentclass[b5paper,9pt,english]{sphinxbook}' in result
247
248
249@pytest.mark.sphinx('latex', testroot='basic', confoverrides={'language': 'zh'})
250def test_latex_additional_settings_for_language_code(app, status, warning):
251    app.builder.build_all()
252    result = (app.outdir / 'test.tex').read_text()
253    print(result)
254    print(status.getvalue())
255    print(warning.getvalue())
256    assert r'\usepackage{xeCJK}' in result
257
258
259@pytest.mark.sphinx('latex', testroot='basic', confoverrides={'language': 'el'})
260def test_latex_additional_settings_for_greek(app, status, warning):
261    app.builder.build_all()
262    result = (app.outdir / 'test.tex').read_text()
263    print(result)
264    print(status.getvalue())
265    print(warning.getvalue())
266    assert '\\usepackage{polyglossia}\n\\setmainlanguage{greek}' in result
267    assert '\\newfontfamily\\greekfonttt{FreeMono}' in result
268
269
270@pytest.mark.sphinx('latex', testroot='latex-title')
271def test_latex_title_after_admonitions(app, status, warning):
272    app.builder.build_all()
273    result = (app.outdir / 'test.tex').read_text()
274    print(result)
275    print(status.getvalue())
276    print(warning.getvalue())
277    assert '\\title{test\\sphinxhyphen{}latex\\sphinxhyphen{}title}' in result
278
279
280@pytest.mark.sphinx('latex', testroot='basic',
281                    confoverrides={'release': '1.0'})
282def test_latex_release(app, status, warning):
283    app.builder.build_all()
284    result = (app.outdir / 'test.tex').read_text()
285    print(result)
286    print(status.getvalue())
287    print(warning.getvalue())
288    assert r'\release{1.0}' in result
289    assert r'\renewcommand{\releasename}{Release}' in result
290
291
292@pytest.mark.sphinx('latex', testroot='numfig',
293                    confoverrides={'numfig': True})
294def test_numref(app, status, warning):
295    app.builder.build_all()
296    result = (app.outdir / 'python.tex').read_text()
297    print(result)
298    print(status.getvalue())
299    print(warning.getvalue())
300    assert ('\\hyperref[\\detokenize{index:fig1}]'
301            '{Fig.\\@ \\ref{\\detokenize{index:fig1}}}') in result
302    assert ('\\hyperref[\\detokenize{baz:fig22}]'
303            '{Figure\\ref{\\detokenize{baz:fig22}}}') in result
304    assert ('\\hyperref[\\detokenize{index:table-1}]'
305            '{Table \\ref{\\detokenize{index:table-1}}}') in result
306    assert ('\\hyperref[\\detokenize{baz:table22}]'
307            '{Table:\\ref{\\detokenize{baz:table22}}}') in result
308    assert ('\\hyperref[\\detokenize{index:code-1}]'
309            '{Listing \\ref{\\detokenize{index:code-1}}}') in result
310    assert ('\\hyperref[\\detokenize{baz:code22}]'
311            '{Code\\sphinxhyphen{}\\ref{\\detokenize{baz:code22}}}') in result
312    assert ('\\hyperref[\\detokenize{foo:foo}]'
313            '{Section \\ref{\\detokenize{foo:foo}}}') in result
314    assert ('\\hyperref[\\detokenize{bar:bar-a}]'
315            '{Section \\ref{\\detokenize{bar:bar-a}}}') in result
316    assert ('\\hyperref[\\detokenize{index:fig1}]{Fig.\\ref{\\detokenize{index:fig1}} '
317            '\\nameref{\\detokenize{index:fig1}}}') in result
318    assert ('\\hyperref[\\detokenize{foo:foo}]{Sect.\\ref{\\detokenize{foo:foo}} '
319            '\\nameref{\\detokenize{foo:foo}}}') in result
320
321    # sphinxmessages.sty
322    result = (app.outdir / 'sphinxmessages.sty').read_text()
323    print(result)
324    assert r'\addto\captionsenglish{\renewcommand{\figurename}{Fig.\@{} }}' in result
325    assert r'\addto\captionsenglish{\renewcommand{\tablename}{Table }}' in result
326    assert r'\addto\captionsenglish{\renewcommand{\literalblockname}{Listing}}' in result
327
328
329@pytest.mark.sphinx(
330    'latex', testroot='numfig',
331    confoverrides={'numfig': True,
332                   'numfig_format': {'figure': 'Figure:%s',
333                                     'table': 'Tab_%s',
334                                     'code-block': 'Code-%s',
335                                     'section': 'SECTION-%s'}})
336def test_numref_with_prefix1(app, status, warning):
337    app.builder.build_all()
338    result = (app.outdir / 'python.tex').read_text()
339    print(result)
340    print(status.getvalue())
341    print(warning.getvalue())
342    assert '\\ref{\\detokenize{index:fig1}}' in result
343    assert '\\ref{\\detokenize{baz:fig22}}' in result
344    assert '\\ref{\\detokenize{index:table-1}}' in result
345    assert '\\ref{\\detokenize{baz:table22}}' in result
346    assert '\\ref{\\detokenize{index:code-1}}' in result
347    assert '\\ref{\\detokenize{baz:code22}}' in result
348    assert ('\\hyperref[\\detokenize{index:fig1}]'
349            '{Figure:\\ref{\\detokenize{index:fig1}}}') in result
350    assert ('\\hyperref[\\detokenize{baz:fig22}]'
351            '{Figure\\ref{\\detokenize{baz:fig22}}}') in result
352    assert ('\\hyperref[\\detokenize{index:table-1}]'
353            '{Tab\\_\\ref{\\detokenize{index:table-1}}}') in result
354    assert ('\\hyperref[\\detokenize{baz:table22}]'
355            '{Table:\\ref{\\detokenize{baz:table22}}}') in result
356    assert ('\\hyperref[\\detokenize{index:code-1}]'
357            '{Code\\sphinxhyphen{}\\ref{\\detokenize{index:code-1}}}') in result
358    assert ('\\hyperref[\\detokenize{baz:code22}]'
359            '{Code\\sphinxhyphen{}\\ref{\\detokenize{baz:code22}}}') in result
360    assert ('\\hyperref[\\detokenize{foo:foo}]'
361            '{SECTION\\sphinxhyphen{}\\ref{\\detokenize{foo:foo}}}') in result
362    assert ('\\hyperref[\\detokenize{bar:bar-a}]'
363            '{SECTION\\sphinxhyphen{}\\ref{\\detokenize{bar:bar-a}}}') in result
364    assert ('\\hyperref[\\detokenize{index:fig1}]{Fig.\\ref{\\detokenize{index:fig1}} '
365            '\\nameref{\\detokenize{index:fig1}}}') in result
366    assert ('\\hyperref[\\detokenize{foo:foo}]{Sect.\\ref{\\detokenize{foo:foo}} '
367            '\\nameref{\\detokenize{foo:foo}}}') in result
368
369    # sphinxmessages.sty
370    result = (app.outdir / 'sphinxmessages.sty').read_text()
371    print(result)
372    assert r'\addto\captionsenglish{\renewcommand{\figurename}{Figure:}}' in result
373    assert r'\addto\captionsenglish{\renewcommand{\tablename}{Tab\_}}' in result
374    assert r'\addto\captionsenglish{\renewcommand{\literalblockname}{Code-}}' in result
375
376
377@pytest.mark.sphinx(
378    'latex', testroot='numfig',
379    confoverrides={'numfig': True,
380                   'numfig_format': {'figure': 'Figure:%s.',
381                                     'table': 'Tab_%s:',
382                                     'code-block': 'Code-%s | ',
383                                     'section': 'SECTION_%s_'}})
384def test_numref_with_prefix2(app, status, warning):
385    app.builder.build_all()
386    result = (app.outdir / 'python.tex').read_text()
387    print(result)
388    print(status.getvalue())
389    print(warning.getvalue())
390    assert ('\\hyperref[\\detokenize{index:fig1}]'
391            '{Figure:\\ref{\\detokenize{index:fig1}}.\\@}') in result
392    assert ('\\hyperref[\\detokenize{baz:fig22}]'
393            '{Figure\\ref{\\detokenize{baz:fig22}}}') in result
394    assert ('\\hyperref[\\detokenize{index:table-1}]'
395            '{Tab\\_\\ref{\\detokenize{index:table-1}}:}') in result
396    assert ('\\hyperref[\\detokenize{baz:table22}]'
397            '{Table:\\ref{\\detokenize{baz:table22}}}') in result
398    assert ('\\hyperref[\\detokenize{index:code-1}]{Code\\sphinxhyphen{}\\ref{\\detokenize{index:code-1}} '
399            '| }') in result
400    assert ('\\hyperref[\\detokenize{baz:code22}]'
401            '{Code\\sphinxhyphen{}\\ref{\\detokenize{baz:code22}}}') in result
402    assert ('\\hyperref[\\detokenize{foo:foo}]'
403            '{SECTION\\_\\ref{\\detokenize{foo:foo}}\\_}') in result
404    assert ('\\hyperref[\\detokenize{bar:bar-a}]'
405            '{SECTION\\_\\ref{\\detokenize{bar:bar-a}}\\_}') in result
406    assert ('\\hyperref[\\detokenize{index:fig1}]{Fig.\\ref{\\detokenize{index:fig1}} '
407            '\\nameref{\\detokenize{index:fig1}}}') in result
408    assert ('\\hyperref[\\detokenize{foo:foo}]{Sect.\\ref{\\detokenize{foo:foo}} '
409            '\\nameref{\\detokenize{foo:foo}}}') in result
410
411    # sphinxmessages.sty
412    result = (app.outdir / 'sphinxmessages.sty').read_text()
413    print(result)
414    assert r'\addto\captionsenglish{\renewcommand{\figurename}{Figure:}}' in result
415    assert r'\def\fnum@figure{\figurename\thefigure{}.}' in result
416    assert r'\addto\captionsenglish{\renewcommand{\tablename}{Tab\_}}' in result
417    assert r'\def\fnum@table{\tablename\thetable{}:}' in result
418    assert r'\addto\captionsenglish{\renewcommand{\literalblockname}{Code-}}' in result
419
420
421@pytest.mark.sphinx(
422    'latex', testroot='numfig',
423    confoverrides={'numfig': True, 'language': 'ja'})
424def test_numref_with_language_ja(app, status, warning):
425    app.builder.build_all()
426    result = (app.outdir / 'python.tex').read_text()
427    print(result)
428    print(status.getvalue())
429    print(warning.getvalue())
430    assert ('\\hyperref[\\detokenize{index:fig1}]'
431            '{\u56f3 \\ref{\\detokenize{index:fig1}}}') in result
432    assert ('\\hyperref[\\detokenize{baz:fig22}]'
433            '{Figure\\ref{\\detokenize{baz:fig22}}}') in result
434    assert ('\\hyperref[\\detokenize{index:table-1}]'
435            '{\u8868 \\ref{\\detokenize{index:table-1}}}') in result
436    assert ('\\hyperref[\\detokenize{baz:table22}]'
437            '{Table:\\ref{\\detokenize{baz:table22}}}') in result
438    assert ('\\hyperref[\\detokenize{index:code-1}]'
439            '{\u30ea\u30b9\u30c8 \\ref{\\detokenize{index:code-1}}}') in result
440    assert ('\\hyperref[\\detokenize{baz:code22}]'
441            '{Code\\sphinxhyphen{}\\ref{\\detokenize{baz:code22}}}') in result
442    assert ('\\hyperref[\\detokenize{foo:foo}]'
443            '{\\ref{\\detokenize{foo:foo}} \u7ae0}') in result
444    assert ('\\hyperref[\\detokenize{bar:bar-a}]'
445            '{\\ref{\\detokenize{bar:bar-a}} \u7ae0}') in result
446    assert ('\\hyperref[\\detokenize{index:fig1}]{Fig.\\ref{\\detokenize{index:fig1}} '
447            '\\nameref{\\detokenize{index:fig1}}}') in result
448    assert ('\\hyperref[\\detokenize{foo:foo}]{Sect.\\ref{\\detokenize{foo:foo}} '
449            '\\nameref{\\detokenize{foo:foo}}}') in result
450
451    # sphinxmessages.sty
452    result = (app.outdir / 'sphinxmessages.sty').read_text()
453    print(result)
454    assert '\\@iden{\\renewcommand{\\figurename}{図 }}' in result
455    assert '\\@iden{\\renewcommand{\\tablename}{表 }}' in result
456    assert '\\@iden{\\renewcommand{\\literalblockname}{リスト}}' in result
457
458
459@pytest.mark.sphinx('latex', testroot='latex-numfig')
460def test_latex_obey_numfig_is_false(app, status, warning):
461    app.builder.build_all()
462
463    result = (app.outdir / 'SphinxManual.tex').read_text()
464    assert '\\usepackage{sphinx}' in result
465
466    result = (app.outdir / 'SphinxHowTo.tex').read_text()
467    assert '\\usepackage{sphinx}' in result
468
469
470@pytest.mark.sphinx(
471    'latex', testroot='latex-numfig',
472    confoverrides={'numfig': True, 'numfig_secnum_depth': 0})
473def test_latex_obey_numfig_secnum_depth_is_zero(app, status, warning):
474    app.builder.build_all()
475
476    result = (app.outdir / 'SphinxManual.tex').read_text()
477    assert '\\usepackage[,nonumfigreset,mathnumfig]{sphinx}' in result
478
479    result = (app.outdir / 'SphinxHowTo.tex').read_text()
480    assert '\\usepackage[,nonumfigreset,mathnumfig]{sphinx}' in result
481
482
483@pytest.mark.sphinx(
484    'latex', testroot='latex-numfig',
485    confoverrides={'numfig': True, 'numfig_secnum_depth': 2})
486def test_latex_obey_numfig_secnum_depth_is_two(app, status, warning):
487    app.builder.build_all()
488
489    result = (app.outdir / 'SphinxManual.tex').read_text()
490    assert '\\usepackage[,numfigreset=2,mathnumfig]{sphinx}' in result
491
492    result = (app.outdir / 'SphinxHowTo.tex').read_text()
493    assert '\\usepackage[,numfigreset=3,mathnumfig]{sphinx}' in result
494
495
496@pytest.mark.sphinx(
497    'latex', testroot='latex-numfig',
498    confoverrides={'numfig': True, 'math_numfig': False})
499def test_latex_obey_numfig_but_math_numfig_false(app, status, warning):
500    app.builder.build_all()
501
502    result = (app.outdir / 'SphinxManual.tex').read_text()
503    assert '\\usepackage[,numfigreset=1]{sphinx}' in result
504
505    result = (app.outdir / 'SphinxHowTo.tex').read_text()
506    assert '\\usepackage[,numfigreset=2]{sphinx}' in result
507
508
509@pytest.mark.sphinx('latex', testroot='basic')
510def test_latex_add_latex_package(app, status, warning):
511    app.add_latex_package('foo')
512    app.add_latex_package('bar', 'baz')
513    app.builder.build_all()
514    result = (app.outdir / 'test.tex').read_text()
515    assert '\\usepackage{foo}' in result
516    assert '\\usepackage[baz]{bar}' in result
517
518
519@pytest.mark.sphinx('latex', testroot='latex-babel')
520def test_babel_with_no_language_settings(app, status, warning):
521    app.builder.build_all()
522    result = (app.outdir / 'python.tex').read_text()
523    print(result)
524    print(status.getvalue())
525    print(warning.getvalue())
526    assert '\\documentclass[letterpaper,10pt,english]{sphinxmanual}' in result
527    assert '\\usepackage{babel}' in result
528    assert '\\usepackage{times}' in result
529    assert '\\usepackage[Bjarne]{fncychap}' in result
530    assert ('\\addto\\captionsenglish{\\renewcommand{\\contentsname}{Table of content}}\n'
531            in result)
532    assert '\\shorthandoff' not in result
533
534    # sphinxmessages.sty
535    result = (app.outdir / 'sphinxmessages.sty').read_text()
536    print(result)
537    assert r'\def\pageautorefname{page}' in result
538    assert r'\addto\captionsenglish{\renewcommand{\figurename}{Fig.\@{} }}' in result
539    assert r'\addto\captionsenglish{\renewcommand{\tablename}{Table.\@{} }}' in result
540
541
542@pytest.mark.sphinx(
543    'latex', testroot='latex-babel',
544    confoverrides={'language': 'de'})
545def test_babel_with_language_de(app, status, warning):
546    app.builder.build_all()
547    result = (app.outdir / 'python.tex').read_text()
548    print(result)
549    print(status.getvalue())
550    print(warning.getvalue())
551    assert '\\documentclass[letterpaper,10pt,ngerman]{sphinxmanual}' in result
552    assert '\\usepackage{babel}' in result
553    assert '\\usepackage{times}' in result
554    assert '\\usepackage[Sonny]{fncychap}' in result
555    assert ('\\addto\\captionsngerman{\\renewcommand{\\contentsname}{Table of content}}\n'
556            in result)
557    assert '\\shorthandoff{"}' in result
558
559    # sphinxmessages.sty
560    result = (app.outdir / 'sphinxmessages.sty').read_text()
561    print(result)
562    assert r'\def\pageautorefname{Seite}' in result
563    assert r'\addto\captionsngerman{\renewcommand{\figurename}{Fig.\@{} }}' in result
564    assert r'\addto\captionsngerman{\renewcommand{\tablename}{Table.\@{} }}' in result
565
566
567@pytest.mark.sphinx(
568    'latex', testroot='latex-babel',
569    confoverrides={'language': 'ru'})
570def test_babel_with_language_ru(app, status, warning):
571    app.builder.build_all()
572    result = (app.outdir / 'python.tex').read_text()
573    print(result)
574    print(status.getvalue())
575    print(warning.getvalue())
576    assert '\\documentclass[letterpaper,10pt,russian]{sphinxmanual}' in result
577    assert '\\usepackage{babel}' in result
578    assert '\\usepackage{times}' not in result
579    assert '\\usepackage[Sonny]{fncychap}' in result
580    assert ('\\addto\\captionsrussian{\\renewcommand{\\contentsname}{Table of content}}\n'
581            in result)
582    assert '\\shorthandoff{"}' in result
583
584    # sphinxmessages.sty
585    result = (app.outdir / 'sphinxmessages.sty').read_text()
586    print(result)
587    assert r'\def\pageautorefname{страница}' in result
588    assert r'\addto\captionsrussian{\renewcommand{\figurename}{Fig.\@{} }}' in result
589    assert r'\addto\captionsrussian{\renewcommand{\tablename}{Table.\@{} }}' in result
590
591
592@pytest.mark.sphinx(
593    'latex', testroot='latex-babel',
594    confoverrides={'language': 'tr'})
595def test_babel_with_language_tr(app, status, warning):
596    app.builder.build_all()
597    result = (app.outdir / 'python.tex').read_text()
598    print(result)
599    print(status.getvalue())
600    print(warning.getvalue())
601    assert '\\documentclass[letterpaper,10pt,turkish]{sphinxmanual}' in result
602    assert '\\usepackage{babel}' in result
603    assert '\\usepackage{times}' in result
604    assert '\\usepackage[Sonny]{fncychap}' in result
605    assert ('\\addto\\captionsturkish{\\renewcommand{\\contentsname}{Table of content}}\n'
606            in result)
607    assert '\\shorthandoff{=}' in result
608
609    # sphinxmessages.sty
610    result = (app.outdir / 'sphinxmessages.sty').read_text()
611    print(result)
612    assert r'\def\pageautorefname{sayfa}' in result
613    assert r'\addto\captionsturkish{\renewcommand{\figurename}{Fig.\@{} }}' in result
614    assert r'\addto\captionsturkish{\renewcommand{\tablename}{Table.\@{} }}' in result
615
616
617@pytest.mark.sphinx(
618    'latex', testroot='latex-babel',
619    confoverrides={'language': 'ja'})
620def test_babel_with_language_ja(app, status, warning):
621    app.builder.build_all()
622    result = (app.outdir / 'python.tex').read_text()
623    print(result)
624    print(status.getvalue())
625    print(warning.getvalue())
626    assert '\\documentclass[letterpaper,10pt,dvipdfmx]{sphinxmanual}' in result
627    assert '\\usepackage{babel}' not in result
628    assert '\\usepackage{times}' in result
629    assert '\\usepackage[Sonny]{fncychap}' not in result
630    assert '\\renewcommand{\\contentsname}{Table of content}\n' in result
631    assert '\\shorthandoff' not in result
632
633    # sphinxmessages.sty
634    result = (app.outdir / 'sphinxmessages.sty').read_text()
635    print(result)
636    assert r'\def\pageautorefname{ページ}' in result
637    assert '\\@iden{\\renewcommand{\\figurename}{Fig.\\@{} }}' in result
638    assert '\\@iden{\\renewcommand{\\tablename}{Table.\\@{} }}' in result
639
640
641@pytest.mark.sphinx(
642    'latex', testroot='latex-babel',
643    confoverrides={'language': 'unknown'})
644def test_babel_with_unknown_language(app, status, warning):
645    app.builder.build_all()
646    result = (app.outdir / 'python.tex').read_text()
647    print(result)
648    print(status.getvalue())
649    print(warning.getvalue())
650    assert '\\documentclass[letterpaper,10pt,english]{sphinxmanual}' in result
651    assert '\\usepackage{babel}' in result
652    assert '\\usepackage{times}' in result
653    assert '\\usepackage[Sonny]{fncychap}' in result
654    assert ('\\addto\\captionsenglish{\\renewcommand{\\contentsname}{Table of content}}\n'
655            in result)
656    assert '\\shorthandoff' in result
657
658    assert "WARNING: no Babel option known for language 'unknown'" in warning.getvalue()
659
660    # sphinxmessages.sty
661    result = (app.outdir / 'sphinxmessages.sty').read_text()
662    print(result)
663    assert r'\def\pageautorefname{page}' in result
664    assert r'\addto\captionsenglish{\renewcommand{\figurename}{Fig.\@{} }}' in result
665    assert r'\addto\captionsenglish{\renewcommand{\tablename}{Table.\@{} }}' in result
666
667
668@pytest.mark.sphinx(
669    'latex', testroot='latex-babel',
670    confoverrides={'language': 'de', 'latex_engine': 'lualatex'})
671def test_polyglossia_with_language_de(app, status, warning):
672    app.builder.build_all()
673    result = (app.outdir / 'python.tex').read_text()
674    print(result)
675    print(status.getvalue())
676    print(warning.getvalue())
677    assert '\\documentclass[letterpaper,10pt,german]{sphinxmanual}' in result
678    assert '\\usepackage{polyglossia}' in result
679    assert '\\setmainlanguage[spelling=new]{german}' in result
680    assert '\\usepackage{times}' not in result
681    assert '\\usepackage[Sonny]{fncychap}' in result
682    assert ('\\addto\\captionsgerman{\\renewcommand{\\contentsname}{Table of content}}\n'
683            in result)
684    assert '\\shorthandoff' not in result
685
686    # sphinxmessages.sty
687    result = (app.outdir / 'sphinxmessages.sty').read_text()
688    print(result)
689    assert r'\def\pageautorefname{Seite}' in result
690    assert r'\addto\captionsgerman{\renewcommand{\figurename}{Fig.\@{} }}' in result
691    assert r'\addto\captionsgerman{\renewcommand{\tablename}{Table.\@{} }}' in result
692
693
694@pytest.mark.sphinx(
695    'latex', testroot='latex-babel',
696    confoverrides={'language': 'de-1901', 'latex_engine': 'lualatex'})
697def test_polyglossia_with_language_de_1901(app, status, warning):
698    app.builder.build_all()
699    result = (app.outdir / 'python.tex').read_text()
700    print(result)
701    print(status.getvalue())
702    print(warning.getvalue())
703    assert '\\documentclass[letterpaper,10pt,german]{sphinxmanual}' in result
704    assert '\\usepackage{polyglossia}' in result
705    assert '\\setmainlanguage[spelling=old]{german}' in result
706    assert '\\usepackage{times}' not in result
707    assert '\\usepackage[Sonny]{fncychap}' in result
708    assert ('\\addto\\captionsgerman{\\renewcommand{\\contentsname}{Table of content}}\n'
709            in result)
710    assert '\\shorthandoff' not in result
711
712    # sphinxmessages.sty
713    result = (app.outdir / 'sphinxmessages.sty').read_text()
714    print(result)
715    assert r'\def\pageautorefname{page}' in result
716    assert r'\addto\captionsgerman{\renewcommand{\figurename}{Fig.\@{} }}' in result
717    assert r'\addto\captionsgerman{\renewcommand{\tablename}{Table.\@{} }}' in result
718
719
720@pytest.mark.sphinx('latex')
721def test_footnote(app, status, warning):
722    app.builder.build_all()
723    result = (app.outdir / 'sphinxtests.tex').read_text()
724    print(result)
725    print(status.getvalue())
726    print(warning.getvalue())
727    assert ('\\sphinxstepexplicit %\n\\begin{footnote}[1]\\phantomsection'
728            '\\label{\\thesphinxscope.1}%\n\\sphinxAtStartFootnote\nnumbered\n%\n'
729            '\\end{footnote}') in result
730    assert ('\\begin{footnote}[2]\\sphinxAtStartFootnote\nauto numbered\n%\n'
731            '\\end{footnote}') in result
732    assert '\\begin{footnote}[3]\\sphinxAtStartFootnote\nnamed\n%\n\\end{footnote}' in result
733    assert '\\sphinxcite{footnote:bar}' in result
734    assert ('\\bibitem[bar]{footnote:bar}\n\\sphinxAtStartPar\ncite\n') in result
735    assert '\\sphinxcaption{Table caption \\sphinxfootnotemark[4]' in result
736    assert ('\\hline%\n\\begin{footnotetext}[4]'
737            '\\phantomsection\\label{\\thesphinxscope.4}%\n'
738            '\\sphinxAtStartFootnote\n'
739            'footnote in table caption\n%\n\\end{footnotetext}\\ignorespaces %\n'
740            '\\begin{footnotetext}[5]'
741            '\\phantomsection\\label{\\thesphinxscope.5}%\n'
742            '\\sphinxAtStartFootnote\n'
743            'footnote in table header\n%\n\\end{footnotetext}\\ignorespaces '
744            '\n\\sphinxAtStartPar\n'
745            'VIDIOC\\_CROPCAP\n&\n\\sphinxAtStartPar\n') in result
746    assert ('Information about VIDIOC\\_CROPCAP %\n'
747            '\\begin{footnote}[6]\\sphinxAtStartFootnote\n'
748            'footnote in table not in header\n%\n\\end{footnote}\n\\\\\n\\hline\n'
749            '\\end{tabulary}\n'
750            '\\par\n\\sphinxattableend\\end{savenotes}\n') in result
751
752
753@pytest.mark.sphinx('latex', testroot='footnotes')
754def test_reference_in_caption_and_codeblock_in_footnote(app, status, warning):
755    app.builder.build_all()
756    result = (app.outdir / 'python.tex').read_text()
757    print(result)
758    print(status.getvalue())
759    print(warning.getvalue())
760    assert ('\\caption{This is the figure caption with a reference to '
761            '\\sphinxcite{index:authoryear}.}' in result)
762    assert '\\chapter{The section with a reference to {[}AuthorYear{]}}' in result
763    assert ('\\sphinxcaption{The table title with a reference'
764            ' to {[}AuthorYear{]}}' in result)
765    assert '\\subsubsection*{The rubric title with a reference to {[}AuthorYear{]}}' in result
766    assert ('\\chapter{The section with a reference to \\sphinxfootnotemark[5]}\n'
767            '\\label{\\detokenize{index:the-section-with-a-reference-to}}'
768            '%\n\\begin{footnotetext}[5]'
769            '\\phantomsection\\label{\\thesphinxscope.5}%\n'
770            '\\sphinxAtStartFootnote\n'
771            'Footnote in section\n%\n\\end{footnotetext}') in result
772    assert ('\\caption{This is the figure caption with a footnote to '
773            '\\sphinxfootnotemark[7].}\\label{\\detokenize{index:id29}}\\end{figure}\n'
774            '%\n\\begin{footnotetext}[7]'
775            '\\phantomsection\\label{\\thesphinxscope.7}%\n'
776            '\\sphinxAtStartFootnote\n'
777            'Footnote in caption\n%\n\\end{footnotetext}') in result
778    assert ('\\sphinxcaption{footnote \\sphinxfootnotemark[8] in '
779            'caption of normal table}\\label{\\detokenize{index:id30}}') in result
780    assert ('\\caption{footnote \\sphinxfootnotemark[9] '
781            'in caption \\sphinxfootnotemark[10] of longtable\\strut}') in result
782    assert ('\\endlastfoot\n%\n\\begin{footnotetext}[9]'
783            '\\phantomsection\\label{\\thesphinxscope.9}%\n'
784            '\\sphinxAtStartFootnote\n'
785            'Foot note in longtable\n%\n\\end{footnotetext}\\ignorespaces %\n'
786            '\\begin{footnotetext}[10]'
787            '\\phantomsection\\label{\\thesphinxscope.10}%\n'
788            '\\sphinxAtStartFootnote\n'
789            'Second footnote in caption of longtable\n') in result
790    assert ('This is a reference to the code\\sphinxhyphen{}block in the footnote:\n'
791            '{\\hyperref[\\detokenize{index:codeblockinfootnote}]'
792            '{\\sphinxcrossref{\\DUrole{std,std-ref}{I am in a footnote}}}}') in result
793    assert ('&\n\\sphinxAtStartPar\nThis is one more footnote with some code in it %\n'
794            '\\begin{footnote}[11]\\sphinxAtStartFootnote\n'
795            'Third footnote in longtable\n') in result
796    assert ('\\end{sphinxVerbatim}\n%\n\\end{footnote}.\n') in result
797    assert '\\begin{sphinxVerbatim}[commandchars=\\\\\\{\\}]' in result
798
799
800@pytest.mark.sphinx(
801    'latex', testroot='footnotes',
802    confoverrides={'latex_show_urls': 'inline'})
803def test_latex_show_urls_is_inline(app, status, warning):
804    app.builder.build_all()
805    result = (app.outdir / 'python.tex').read_text()
806    print(result)
807    print(status.getvalue())
808    print(warning.getvalue())
809    assert ('Same footnote number \\sphinxstepexplicit %\n'
810            '\\begin{footnote}[1]\\phantomsection\\label{\\thesphinxscope.1}%\n'
811            '\\sphinxAtStartFootnote\n'
812            'footnote in bar\n%\n\\end{footnote} in bar.rst') in result
813    assert ('Auto footnote number %\n\\begin{footnote}[1]\\sphinxAtStartFootnote\n'
814            'footnote in baz\n%\n\\end{footnote} in baz.rst') in result
815    assert ('\\phantomsection\\label{\\detokenize{index:id32}}'
816            '{\\hyperref[\\detokenize{index:the-section'
817            '-with-a-reference-to-authoryear}]'
818            '{\\sphinxcrossref{The section with a reference to '
819            '\\sphinxcite{index:authoryear}}}}') in result
820    assert ('\\phantomsection\\label{\\detokenize{index:id33}}'
821            '{\\hyperref[\\detokenize{index:the-section-with-a-reference-to}]'
822            '{\\sphinxcrossref{The section with a reference to }}}' in result)
823    assert ('First footnote: %\n\\begin{footnote}[2]\\sphinxAtStartFootnote\n'
824            'First\n%\n\\end{footnote}') in result
825    assert ('Second footnote: \\sphinxstepexplicit %\n'
826            '\\begin{footnote}[1]\\phantomsection\\label{\\thesphinxscope.1}%\n'
827            '\\sphinxAtStartFootnote\n'
828            'Second\n%\n\\end{footnote}') in result
829    assert '\\sphinxhref{http://sphinx-doc.org/}{Sphinx} (http://sphinx\\sphinxhyphen{}doc.org/)' in result
830    assert ('Third footnote: %\n\\begin{footnote}[3]\\sphinxAtStartFootnote\n'
831            'Third \\sphinxfootnotemark[4]\n%\n\\end{footnote}%\n'
832            '\\begin{footnotetext}[4]'
833            '\\phantomsection\\label{\\thesphinxscope.4}%\n'
834            '\\sphinxAtStartFootnote\n'
835            'Footnote inside footnote\n%\n\\end{footnotetext}\\ignorespaces') in result
836    assert ('\\sphinxhref{http://sphinx-doc.org/~test/}{URL including tilde} '
837            '(http://sphinx\\sphinxhyphen{}doc.org/\\textasciitilde{}test/)') in result
838    assert ('\\item[{\\sphinxhref{http://sphinx-doc.org/}{URL in term} '
839            '(http://sphinx\\sphinxhyphen{}doc.org/)}] '
840            '\\leavevmode\n\\sphinxAtStartPar\nDescription' in result)
841    assert ('\\item[{Footnote in term \\sphinxfootnotemark[6]}] '
842            '\\leavevmode%\n\\begin{footnotetext}[6]'
843            '\\phantomsection\\label{\\thesphinxscope.6}%\n'
844            '\\sphinxAtStartFootnote\n'
845            'Footnote in term\n%\n\\end{footnotetext}\\ignorespaces '
846            '\n\\sphinxAtStartPar\nDescription') in result
847    assert ('\\item[{\\sphinxhref{http://sphinx-doc.org/}{Term in deflist} '
848            '(http://sphinx\\sphinxhyphen{}doc.org/)}] '
849            '\\leavevmode\n\\sphinxAtStartPar\nDescription') in result
850    assert '\\sphinxurl{https://github.com/sphinx-doc/sphinx}\n' in result
851    assert ('\\sphinxhref{mailto:sphinx-dev@googlegroups.com}'
852            '{sphinx\\sphinxhyphen{}dev@googlegroups.com}') in result
853    assert '\\begin{savenotes}\\begin{fulllineitems}' not in result
854
855
856@pytest.mark.sphinx(
857    'latex', testroot='footnotes',
858    confoverrides={'latex_show_urls': 'footnote'})
859def test_latex_show_urls_is_footnote(app, status, warning):
860    app.builder.build_all()
861    result = (app.outdir / 'python.tex').read_text()
862    print(result)
863    print(status.getvalue())
864    print(warning.getvalue())
865    assert ('Same footnote number \\sphinxstepexplicit %\n'
866            '\\begin{footnote}[1]\\phantomsection\\label{\\thesphinxscope.1}%\n'
867            '\\sphinxAtStartFootnote\n'
868            'footnote in bar\n%\n\\end{footnote} in bar.rst') in result
869    assert ('Auto footnote number %\n\\begin{footnote}[2]\\sphinxAtStartFootnote\n'
870            'footnote in baz\n%\n\\end{footnote} in baz.rst') in result
871    assert ('\\phantomsection\\label{\\detokenize{index:id32}}'
872            '{\\hyperref[\\detokenize{index:the-section-with-a-reference-to-authoryear}]'
873            '{\\sphinxcrossref{The section with a reference '
874            'to \\sphinxcite{index:authoryear}}}}') in result
875    assert ('\\phantomsection\\label{\\detokenize{index:id33}}'
876            '{\\hyperref[\\detokenize{index:the-section-with-a-reference-to}]'
877            '{\\sphinxcrossref{The section with a reference to }}}') in result
878    assert ('First footnote: %\n\\begin{footnote}[3]\\sphinxAtStartFootnote\n'
879            'First\n%\n\\end{footnote}') in result
880    assert ('Second footnote: \\sphinxstepexplicit %\n'
881            '\\begin{footnote}[1]\\phantomsection\\label{\\thesphinxscope.1}%\n'
882            '\\sphinxAtStartFootnote\n'
883            'Second\n%\n\\end{footnote}') in result
884    assert ('\\sphinxhref{http://sphinx-doc.org/}{Sphinx}'
885            '%\n\\begin{footnote}[4]\\sphinxAtStartFootnote\n'
886            '\\sphinxnolinkurl{http://sphinx-doc.org/}\n%\n\\end{footnote}') in result
887    assert ('Third footnote: %\n\\begin{footnote}[6]\\sphinxAtStartFootnote\n'
888            'Third \\sphinxfootnotemark[7]\n%\n\\end{footnote}%\n'
889            '\\begin{footnotetext}[7]'
890            '\\phantomsection\\label{\\thesphinxscope.7}%\n'
891            '\\sphinxAtStartFootnote\n'
892            'Footnote inside footnote\n%\n'
893            '\\end{footnotetext}\\ignorespaces') in result
894    assert ('\\sphinxhref{http://sphinx-doc.org/~test/}{URL including tilde}'
895            '%\n\\begin{footnote}[5]\\sphinxAtStartFootnote\n'
896            '\\sphinxnolinkurl{http://sphinx-doc.org/~test/}\n%\n\\end{footnote}') in result
897    assert ('\\item[{\\sphinxhref{http://sphinx-doc.org/}'
898            '{URL in term}\\sphinxfootnotemark[9]}] '
899            '\\leavevmode%\n\\begin{footnotetext}[9]'
900            '\\phantomsection\\label{\\thesphinxscope.9}%\n'
901            '\\sphinxAtStartFootnote\n'
902            '\\sphinxnolinkurl{http://sphinx-doc.org/}\n%\n'
903            '\\end{footnotetext}\\ignorespaces \n\\sphinxAtStartPar\nDescription') in result
904    assert ('\\item[{Footnote in term \\sphinxfootnotemark[11]}] '
905            '\\leavevmode%\n\\begin{footnotetext}[11]'
906            '\\phantomsection\\label{\\thesphinxscope.11}%\n'
907            '\\sphinxAtStartFootnote\n'
908            'Footnote in term\n%\n\\end{footnotetext}\\ignorespaces '
909            '\n\\sphinxAtStartPar\nDescription') in result
910    assert ('\\item[{\\sphinxhref{http://sphinx-doc.org/}{Term in deflist}'
911            '\\sphinxfootnotemark[10]}] '
912            '\\leavevmode%\n\\begin{footnotetext}[10]'
913            '\\phantomsection\\label{\\thesphinxscope.10}%\n'
914            '\\sphinxAtStartFootnote\n'
915            '\\sphinxnolinkurl{http://sphinx-doc.org/}\n%\n'
916            '\\end{footnotetext}\\ignorespaces \n\\sphinxAtStartPar\nDescription') in result
917    assert ('\\sphinxurl{https://github.com/sphinx-doc/sphinx}\n' in result)
918    assert ('\\sphinxhref{mailto:sphinx-dev@googlegroups.com}'
919            '{sphinx\\sphinxhyphen{}dev@googlegroups.com}\n') in result
920    assert '\\begin{savenotes}\\begin{fulllineitems}' in result
921
922
923@pytest.mark.sphinx(
924    'latex', testroot='footnotes',
925    confoverrides={'latex_show_urls': 'no'})
926def test_latex_show_urls_is_no(app, status, warning):
927    app.builder.build_all()
928    result = (app.outdir / 'python.tex').read_text()
929    print(result)
930    print(status.getvalue())
931    print(warning.getvalue())
932    assert ('Same footnote number \\sphinxstepexplicit %\n'
933            '\\begin{footnote}[1]\\phantomsection\\label{\\thesphinxscope.1}%\n'
934            '\\sphinxAtStartFootnote\n'
935            'footnote in bar\n%\n\\end{footnote} in bar.rst') in result
936    assert ('Auto footnote number %\n\\begin{footnote}[1]\\sphinxAtStartFootnote\n'
937            'footnote in baz\n%\n\\end{footnote} in baz.rst') in result
938    assert ('\\phantomsection\\label{\\detokenize{index:id32}}'
939            '{\\hyperref[\\detokenize{index:the-section-with-a-reference-to-authoryear}]'
940            '{\\sphinxcrossref{The section with a reference '
941            'to \\sphinxcite{index:authoryear}}}}') in result
942    assert ('\\phantomsection\\label{\\detokenize{index:id33}}'
943            '{\\hyperref[\\detokenize{index:the-section-with-a-reference-to}]'
944            '{\\sphinxcrossref{The section with a reference to }}}' in result)
945    assert ('First footnote: %\n\\begin{footnote}[2]\\sphinxAtStartFootnote\n'
946            'First\n%\n\\end{footnote}') in result
947    assert ('Second footnote: \\sphinxstepexplicit %\n'
948            '\\begin{footnote}[1]\\phantomsection\\label{\\thesphinxscope.1}%\n'
949            '\\sphinxAtStartFootnote\n'
950            'Second\n%\n\\end{footnote}') in result
951    assert '\\sphinxhref{http://sphinx-doc.org/}{Sphinx}' in result
952    assert ('Third footnote: %\n\\begin{footnote}[3]\\sphinxAtStartFootnote\n'
953            'Third \\sphinxfootnotemark[4]\n%\n\\end{footnote}%\n'
954            '\\begin{footnotetext}[4]'
955            '\\phantomsection\\label{\\thesphinxscope.4}%\n'
956            '\\sphinxAtStartFootnote\n'
957            'Footnote inside footnote\n%\n\\end{footnotetext}\\ignorespaces') in result
958    assert '\\sphinxhref{http://sphinx-doc.org/~test/}{URL including tilde}' in result
959    assert ('\\item[{\\sphinxhref{http://sphinx-doc.org/}{URL in term}}] '
960            '\\leavevmode\n\\sphinxAtStartPar\nDescription') in result
961    assert ('\\item[{Footnote in term \\sphinxfootnotemark[6]}] '
962            '\\leavevmode%\n\\begin{footnotetext}[6]'
963            '\\phantomsection\\label{\\thesphinxscope.6}%\n'
964            '\\sphinxAtStartFootnote\n'
965            'Footnote in term\n%\n\\end{footnotetext}\\ignorespaces '
966            '\n\\sphinxAtStartPar\nDescription') in result
967    assert ('\\item[{\\sphinxhref{http://sphinx-doc.org/}{Term in deflist}}] '
968            '\\leavevmode\n\\sphinxAtStartPar\nDescription') in result
969    assert ('\\sphinxurl{https://github.com/sphinx-doc/sphinx}\n' in result)
970    assert ('\\sphinxhref{mailto:sphinx-dev@googlegroups.com}'
971            '{sphinx\\sphinxhyphen{}dev@googlegroups.com}\n') in result
972    assert '\\begin{savenotes}\\begin{fulllineitems}' not in result
973
974
975@pytest.mark.sphinx(
976    'latex', testroot='footnotes',
977    confoverrides={'latex_show_urls': 'footnote',
978                   'rst_prolog': '.. |URL| replace:: `text <http://www.example.com/>`__'})
979def test_latex_show_urls_footnote_and_substitutions(app, status, warning):
980    # hyperlinks in substitutions should not effect to make footnotes (refs: #4784)
981    test_latex_show_urls_is_footnote(app, status, warning)
982
983
984@pytest.mark.sphinx('latex', testroot='image-in-section')
985def test_image_in_section(app, status, warning):
986    app.builder.build_all()
987    result = (app.outdir / 'python.tex').read_text()
988    print(result)
989    print(status.getvalue())
990    print(warning.getvalue())
991    assert ('\\chapter[Test section]{\\lowercase{\\sphinxincludegraphics'
992            '[width=15bp,height=15bp]}{{pic}.png} Test section}'
993            in result)
994    assert ('\\chapter[Other {[}blah{]} section]{Other {[}blah{]} '
995            '\\lowercase{\\sphinxincludegraphics[width=15bp,height=15bp]}'
996            '{{pic}.png} section}' in result)
997    assert ('\\chapter{Another section}' in result)
998
999
1000@pytest.mark.sphinx('latex', testroot='basic',
1001                    confoverrides={'latex_logo': 'notfound.jpg'})
1002def test_latex_logo_if_not_found(app, status, warning):
1003    try:
1004        app.builder.build_all()
1005        assert False  # SphinxError not raised
1006    except Exception as exc:
1007        assert isinstance(exc, SphinxError)
1008
1009
1010@pytest.mark.sphinx('latex', testroot='toctree-maxdepth')
1011def test_toctree_maxdepth_manual(app, status, warning):
1012    app.builder.build_all()
1013    result = (app.outdir / 'python.tex').read_text()
1014    print(result)
1015    print(status.getvalue())
1016    print(warning.getvalue())
1017    assert '\\setcounter{tocdepth}{1}' in result
1018    assert '\\setcounter{secnumdepth}' not in result
1019    assert '\\chapter{Foo}' in result
1020
1021
1022@pytest.mark.sphinx(
1023    'latex', testroot='toctree-maxdepth',
1024    confoverrides={'latex_documents': [
1025        ('index', 'python.tex', 'Sphinx Tests Documentation',
1026         'Georg Brandl', 'howto'),
1027    ]})
1028def test_toctree_maxdepth_howto(app, status, warning):
1029    app.builder.build_all()
1030    result = (app.outdir / 'python.tex').read_text()
1031    print(result)
1032    print(status.getvalue())
1033    print(warning.getvalue())
1034    assert '\\setcounter{tocdepth}{2}' in result
1035    assert '\\setcounter{secnumdepth}' not in result
1036    assert '\\section{Foo}' in result
1037
1038
1039@pytest.mark.sphinx(
1040    'latex', testroot='toctree-maxdepth',
1041    confoverrides={'master_doc': 'foo'})
1042def test_toctree_not_found(app, status, warning):
1043    app.builder.build_all()
1044    result = (app.outdir / 'python.tex').read_text()
1045    print(result)
1046    print(status.getvalue())
1047    print(warning.getvalue())
1048    assert '\\setcounter{tocdepth}' not in result
1049    assert '\\setcounter{secnumdepth}' not in result
1050    assert '\\chapter{Foo A}' in result
1051
1052
1053@pytest.mark.sphinx(
1054    'latex', testroot='toctree-maxdepth',
1055    confoverrides={'master_doc': 'bar'})
1056def test_toctree_without_maxdepth(app, status, warning):
1057    app.builder.build_all()
1058    result = (app.outdir / 'python.tex').read_text()
1059    print(result)
1060    print(status.getvalue())
1061    print(warning.getvalue())
1062    assert '\\setcounter{tocdepth}' not in result
1063    assert '\\setcounter{secnumdepth}' not in result
1064
1065
1066@pytest.mark.sphinx(
1067    'latex', testroot='toctree-maxdepth',
1068    confoverrides={'master_doc': 'qux'})
1069def test_toctree_with_deeper_maxdepth(app, status, warning):
1070    app.builder.build_all()
1071    result = (app.outdir / 'python.tex').read_text()
1072    print(result)
1073    print(status.getvalue())
1074    print(warning.getvalue())
1075    assert '\\setcounter{tocdepth}{3}' in result
1076    assert '\\setcounter{secnumdepth}{3}' in result
1077
1078
1079@pytest.mark.sphinx(
1080    'latex', testroot='toctree-maxdepth',
1081    confoverrides={'latex_toplevel_sectioning': None})
1082def test_latex_toplevel_sectioning_is_None(app, status, warning):
1083    app.builder.build_all()
1084    result = (app.outdir / 'python.tex').read_text()
1085    print(result)
1086    print(status.getvalue())
1087    print(warning.getvalue())
1088    assert '\\chapter{Foo}' in result
1089
1090
1091@pytest.mark.sphinx(
1092    'latex', testroot='toctree-maxdepth',
1093    confoverrides={'latex_toplevel_sectioning': 'part'})
1094def test_latex_toplevel_sectioning_is_part(app, status, warning):
1095    app.builder.build_all()
1096    result = (app.outdir / 'python.tex').read_text()
1097    print(result)
1098    print(status.getvalue())
1099    print(warning.getvalue())
1100    assert '\\part{Foo}' in result
1101    assert '\\chapter{Foo A}' in result
1102    assert '\\chapter{Foo B}' in result
1103
1104
1105@pytest.mark.sphinx(
1106    'latex', testroot='toctree-maxdepth',
1107    confoverrides={'latex_toplevel_sectioning': 'part',
1108                   'latex_documents': [
1109                       ('index', 'python.tex', 'Sphinx Tests Documentation',
1110                        'Georg Brandl', 'howto')
1111                   ]})
1112def test_latex_toplevel_sectioning_is_part_with_howto(app, status, warning):
1113    app.builder.build_all()
1114    result = (app.outdir / 'python.tex').read_text()
1115    print(result)
1116    print(status.getvalue())
1117    print(warning.getvalue())
1118    assert '\\part{Foo}' in result
1119    assert '\\section{Foo A}' in result
1120    assert '\\section{Foo B}' in result
1121
1122
1123@pytest.mark.sphinx(
1124    'latex', testroot='toctree-maxdepth',
1125    confoverrides={'latex_toplevel_sectioning': 'chapter'})
1126def test_latex_toplevel_sectioning_is_chapter(app, status, warning):
1127    app.builder.build_all()
1128    result = (app.outdir / 'python.tex').read_text()
1129    print(result)
1130    print(status.getvalue())
1131    print(warning.getvalue())
1132    assert '\\chapter{Foo}' in result
1133
1134
1135@pytest.mark.sphinx(
1136    'latex', testroot='toctree-maxdepth',
1137    confoverrides={'latex_toplevel_sectioning': 'chapter',
1138                   'latex_documents': [
1139                       ('index', 'python.tex', 'Sphinx Tests Documentation',
1140                        'Georg Brandl', 'howto')
1141                   ]})
1142def test_latex_toplevel_sectioning_is_chapter_with_howto(app, status, warning):
1143    app.builder.build_all()
1144    result = (app.outdir / 'python.tex').read_text()
1145    print(result)
1146    print(status.getvalue())
1147    print(warning.getvalue())
1148    assert '\\section{Foo}' in result
1149
1150
1151@pytest.mark.sphinx(
1152    'latex', testroot='toctree-maxdepth',
1153    confoverrides={'latex_toplevel_sectioning': 'section'})
1154def test_latex_toplevel_sectioning_is_section(app, status, warning):
1155    app.builder.build_all()
1156    result = (app.outdir / 'python.tex').read_text()
1157    print(result)
1158    print(status.getvalue())
1159    print(warning.getvalue())
1160    assert '\\section{Foo}' in result
1161
1162
1163@skip_if_stylefiles_notfound
1164@pytest.mark.sphinx('latex', testroot='maxlistdepth')
1165def test_maxlistdepth_at_ten(app, status, warning):
1166    app.builder.build_all()
1167    result = (app.outdir / 'python.tex').read_text()
1168    print(result)
1169    print(status.getvalue())
1170    print(warning.getvalue())
1171    compile_latex_document(app, 'python.tex')
1172
1173
1174@pytest.mark.skipif(docutils.__version_info__ < (0, 13),
1175                    reason='docutils-0.13 or above is required')
1176@pytest.mark.sphinx('latex', testroot='latex-table')
1177@pytest.mark.test_params(shared_result='latex-table')
1178def test_latex_table_tabulars(app, status, warning):
1179    app.builder.build_all()
1180    result = (app.outdir / 'python.tex').read_text()
1181    tables = {}
1182    for chap in re.split(r'\\(?:section|chapter){', result)[1:]:
1183        sectname, content = chap.split('}', 1)
1184        tables[sectname] = content.strip()
1185
1186    def get_expected(name):
1187        return (app.srcdir / 'expects' / (name + '.tex')).read_text().strip()
1188
1189    # simple_table
1190    actual = tables['simple table']
1191    expected = get_expected('simple_table')
1192    assert actual == expected
1193
1194    # table having :widths: option
1195    actual = tables['table having :widths: option']
1196    expected = get_expected('table_having_widths')
1197    assert actual == expected
1198
1199    # table having :align: option (tabulary)
1200    actual = tables['table having :align: option (tabulary)']
1201    expected = get_expected('tabulary_having_widths')
1202    assert actual == expected
1203
1204    # table having :align: option (tabular)
1205    actual = tables['table having :align: option (tabular)']
1206    expected = get_expected('tabular_having_widths')
1207    assert actual == expected
1208
1209    # table with tabularcolumn
1210    actual = tables['table with tabularcolumn']
1211    expected = get_expected('tabularcolumn')
1212    assert actual == expected
1213
1214    # table with cell in first column having three paragraphs
1215    actual = tables['table with cell in first column having three paragraphs']
1216    expected = get_expected('table_having_threeparagraphs_cell_in_first_col')
1217    assert actual == expected
1218
1219    # table having caption
1220    actual = tables['table having caption']
1221    expected = get_expected('table_having_caption')
1222    assert actual == expected
1223
1224    # table having verbatim
1225    actual = tables['table having verbatim']
1226    expected = get_expected('table_having_verbatim')
1227    assert actual == expected
1228
1229    # table having problematic cell
1230    actual = tables['table having problematic cell']
1231    expected = get_expected('table_having_problematic_cell')
1232    assert actual == expected
1233
1234    # table having both :widths: and problematic cell
1235    actual = tables['table having both :widths: and problematic cell']
1236    expected = get_expected('table_having_widths_and_problematic_cell')
1237    assert actual == expected
1238
1239    # table having both stub columns and problematic cell
1240    actual = tables['table having both stub columns and problematic cell']
1241    expected = get_expected('table_having_stub_columns_and_problematic_cell')
1242    assert actual == expected
1243
1244
1245@pytest.mark.skipif(docutils.__version_info__ < (0, 13),
1246                    reason='docutils-0.13 or above is required')
1247@pytest.mark.sphinx('latex', testroot='latex-table')
1248@pytest.mark.test_params(shared_result='latex-table')
1249def test_latex_table_longtable(app, status, warning):
1250    app.builder.build_all()
1251    result = (app.outdir / 'python.tex').read_text()
1252    tables = {}
1253    for chap in re.split(r'\\(?:section|chapter){', result)[1:]:
1254        sectname, content = chap.split('}', 1)
1255        tables[sectname] = content.strip()
1256
1257    def get_expected(name):
1258        return (app.srcdir / 'expects' / (name + '.tex')).read_text().strip()
1259
1260    # longtable
1261    actual = tables['longtable']
1262    expected = get_expected('longtable')
1263    assert actual == expected
1264
1265    # longtable having :widths: option
1266    actual = tables['longtable having :widths: option']
1267    expected = get_expected('longtable_having_widths')
1268    assert actual == expected
1269
1270    # longtable having :align: option
1271    actual = tables['longtable having :align: option']
1272    expected = get_expected('longtable_having_align')
1273    assert actual == expected
1274
1275    # longtable with tabularcolumn
1276    actual = tables['longtable with tabularcolumn']
1277    expected = get_expected('longtable_with_tabularcolumn')
1278    assert actual == expected
1279
1280    # longtable having caption
1281    actual = tables['longtable having caption']
1282    expected = get_expected('longtable_having_caption')
1283    assert actual == expected
1284
1285    # longtable having verbatim
1286    actual = tables['longtable having verbatim']
1287    expected = get_expected('longtable_having_verbatim')
1288    assert actual == expected
1289
1290    # longtable having problematic cell
1291    actual = tables['longtable having problematic cell']
1292    expected = get_expected('longtable_having_problematic_cell')
1293    assert actual == expected
1294
1295    # longtable having both :widths: and problematic cell
1296    actual = tables['longtable having both :widths: and problematic cell']
1297    expected = get_expected('longtable_having_widths_and_problematic_cell')
1298    assert actual == expected
1299
1300    # longtable having both stub columns and problematic cell
1301    actual = tables['longtable having both stub columns and problematic cell']
1302    expected = get_expected('longtable_having_stub_columns_and_problematic_cell')
1303    assert actual == expected
1304
1305
1306@pytest.mark.skipif(docutils.__version_info__ < (0, 13),
1307                    reason='docutils-0.13 or above is required')
1308@pytest.mark.sphinx('latex', testroot='latex-table')
1309@pytest.mark.test_params(shared_result='latex-table')
1310def test_latex_table_complex_tables(app, status, warning):
1311    app.builder.build_all()
1312    result = (app.outdir / 'python.tex').read_text()
1313    tables = {}
1314    for chap in re.split(r'\\(?:section|renewcommand){', result)[1:]:
1315        sectname, content = chap.split('}', 1)
1316        tables[sectname] = content.strip()
1317
1318    def get_expected(name):
1319        return (app.srcdir / 'expects' / (name + '.tex')).read_text().strip()
1320
1321    # grid table
1322    actual = tables['grid table']
1323    expected = get_expected('gridtable')
1324    assert actual == expected
1325
1326    # complex spanning cell
1327    actual = tables['complex spanning cell']
1328    expected = get_expected('complex_spanning_cell')
1329    assert actual == expected
1330
1331
1332@pytest.mark.sphinx('latex', testroot='latex-table',
1333                    confoverrides={'templates_path': ['_mytemplates/latex']})
1334def test_latex_table_custom_template_caseA(app, status, warning):
1335    app.builder.build_all()
1336    result = (app.outdir / 'python.tex').read_text()
1337    assert 'SALUT LES COPAINS' in result
1338
1339
1340@pytest.mark.sphinx('latex', testroot='latex-table',
1341                    confoverrides={'templates_path': ['_mytemplates']})
1342def test_latex_table_custom_template_caseB(app, status, warning):
1343    app.builder.build_all()
1344    result = (app.outdir / 'python.tex').read_text()
1345    assert 'SALUT LES COPAINS' not in result
1346
1347
1348@pytest.mark.sphinx('latex', testroot='latex-table')
1349@pytest.mark.test_params(shared_result='latex-table')
1350def test_latex_table_custom_template_caseC(app, status, warning):
1351    app.builder.build_all()
1352    result = (app.outdir / 'python.tex').read_text()
1353    assert 'SALUT LES COPAINS' not in result
1354
1355
1356@pytest.mark.sphinx('latex', testroot='directives-raw')
1357def test_latex_raw_directive(app, status, warning):
1358    app.builder.build_all()
1359    result = (app.outdir / 'python.tex').read_text()
1360
1361    # standard case
1362    assert 'standalone raw directive (HTML)' not in result
1363    assert ('\\label{\\detokenize{index:id1}}\n'
1364            'standalone raw directive (LaTeX)' in result)
1365
1366    # with substitution
1367    assert 'HTML: abc  ghi' in result
1368    assert 'LaTeX: abc def ghi' in result
1369
1370
1371@pytest.mark.sphinx('latex', testroot='images')
1372def test_latex_images(app, status, warning):
1373    app.builder.build_all()
1374
1375    result = (app.outdir / 'python.tex').read_text()
1376
1377    # images are copied
1378    assert '\\sphinxincludegraphics{{python-logo}.png}' in result
1379    assert (app.outdir / 'python-logo.png').exists()
1380
1381    # not found images
1382    assert '\\sphinxincludegraphics{{NOT_EXIST}.PNG}' not in result
1383    assert ('WARNING: Could not fetch remote image: '
1384            'https://www.google.com/NOT_EXIST.PNG [404]' in warning.getvalue())
1385
1386    # an image having target
1387    assert ('\\sphinxhref{https://www.sphinx-doc.org/}'
1388            '{\\sphinxincludegraphics{{rimg}.png}}\n\n' in result)
1389
1390    # a centerized image having target
1391    assert ('\\sphinxhref{https://www.python.org/}{{\\hspace*{\\fill}'
1392            '\\sphinxincludegraphics{{rimg}.png}\\hspace*{\\fill}}}\n\n' in result)
1393
1394
1395@pytest.mark.sphinx('latex', testroot='latex-index')
1396def test_latex_index(app, status, warning):
1397    app.builder.build_all()
1398
1399    result = (app.outdir / 'python.tex').read_text()
1400    assert ('A \\index{famous@\\spxentry{famous}}famous '
1401            '\\index{equation@\\spxentry{equation}}equation:\n' in result)
1402    assert ('\n\\index{Einstein@\\spxentry{Einstein}}'
1403            '\\index{relativity@\\spxentry{relativity}}'
1404            '\\ignorespaces \n\\sphinxAtStartPar\nand') in result
1405    assert ('\n\\index{main \\sphinxleftcurlybrace{}@\\spxentry{'
1406            'main \\sphinxleftcurlybrace{}}}\\ignorespaces ' in result)
1407
1408
1409@pytest.mark.sphinx('latex', testroot='latex-equations')
1410def test_latex_equations(app, status, warning):
1411    app.builder.build_all()
1412
1413    result = (app.outdir / 'python.tex').read_text()
1414    expected = (app.srcdir / 'expects' / 'latex-equations.tex').read_text().strip()
1415
1416    assert expected in result
1417
1418
1419@pytest.mark.sphinx('latex', testroot='image-in-parsed-literal')
1420def test_latex_image_in_parsed_literal(app, status, warning):
1421    app.builder.build_all()
1422
1423    result = (app.outdir / 'python.tex').read_text()
1424    assert ('{\\sphinxunactivateextrasandspace \\raisebox{-0.5\\height}'
1425            '{\\sphinxincludegraphics[height=2.00000cm]{{pic}.png}}'
1426            '}AFTER') in result
1427
1428
1429@pytest.mark.sphinx('latex', testroot='nested-enumerated-list')
1430def test_latex_nested_enumerated_list(app, status, warning):
1431    app.builder.build_all()
1432
1433    result = (app.outdir / 'python.tex').read_text()
1434    assert ('\\sphinxsetlistlabels{\\arabic}{enumi}{enumii}{}{.}%\n'
1435            '\\setcounter{enumi}{4}\n' in result)
1436    assert ('\\sphinxsetlistlabels{\\alph}{enumii}{enumiii}{}{.}%\n'
1437            '\\setcounter{enumii}{3}\n' in result)
1438    assert ('\\sphinxsetlistlabels{\\arabic}{enumiii}{enumiv}{}{)}%\n'
1439            '\\setcounter{enumiii}{9}\n' in result)
1440    assert ('\\sphinxsetlistlabels{\\arabic}{enumiv}{enumv}{(}{)}%\n'
1441            '\\setcounter{enumiv}{23}\n' in result)
1442    assert ('\\sphinxsetlistlabels{\\roman}{enumii}{enumiii}{}{.}%\n'
1443            '\\setcounter{enumii}{2}\n' in result)
1444
1445
1446@pytest.mark.sphinx('latex', testroot='footnotes')
1447def test_latex_thebibliography(app, status, warning):
1448    app.builder.build_all()
1449
1450    result = (app.outdir / 'python.tex').read_text()
1451    print(result)
1452    assert ('\\begin{sphinxthebibliography}{AuthorYe}\n'
1453            '\\bibitem[AuthorYear]{index:authoryear}\n\\sphinxAtStartPar\n'
1454            'Author, Title, Year\n'
1455            '\\end{sphinxthebibliography}\n' in result)
1456    assert '\\sphinxcite{index:authoryear}' in result
1457
1458
1459@pytest.mark.sphinx('latex', testroot='glossary')
1460def test_latex_glossary(app, status, warning):
1461    app.builder.build_all()
1462
1463    result = (app.outdir / 'python.tex').read_text()
1464    assert ('\\item[{änhlich\\index{änhlich@\\spxentry{änhlich}|spxpagem}'
1465            r'\phantomsection'
1466            r'\label{\detokenize{index:term-anhlich}}}] \leavevmode' in result)
1467    assert (r'\item[{boson\index{boson@\spxentry{boson}|spxpagem}\phantomsection'
1468            r'\label{\detokenize{index:term-boson}}}] \leavevmode' in result)
1469    assert (r'\item[{\sphinxstyleemphasis{fermion}'
1470            r'\index{fermion@\spxentry{fermion}|spxpagem}'
1471            r'\phantomsection'
1472            r'\label{\detokenize{index:term-fermion}}}] \leavevmode' in result)
1473    assert (r'\item[{tauon\index{tauon@\spxentry{tauon}|spxpagem}\phantomsection'
1474            r'\label{\detokenize{index:term-tauon}}}] \leavevmode'
1475            r'\item[{myon\index{myon@\spxentry{myon}|spxpagem}\phantomsection'
1476            r'\label{\detokenize{index:term-myon}}}] \leavevmode'
1477            r'\item[{electron\index{electron@\spxentry{electron}|spxpagem}\phantomsection'
1478            r'\label{\detokenize{index:term-electron}}}] \leavevmode' in result)
1479    assert ('\\item[{über\\index{über@\\spxentry{über}|spxpagem}\\phantomsection'
1480            r'\label{\detokenize{index:term-uber}}}] \leavevmode' in result)
1481
1482
1483@pytest.mark.sphinx('latex', testroot='latex-labels')
1484def test_latex_labels(app, status, warning):
1485    app.builder.build_all()
1486
1487    result = (app.outdir / 'python.tex').read_text()
1488
1489    # figures
1490    assert (r'\caption{labeled figure}'
1491            r'\label{\detokenize{index:id1}}'
1492            r'\label{\detokenize{index:figure2}}'
1493            r'\label{\detokenize{index:figure1}}'
1494            r'\end{figure}' in result)
1495    assert (r'\caption{labeled figure}'
1496            '\\label{\\detokenize{index:figure3}}\n'
1497            '\\begin{sphinxlegend}\n\\sphinxAtStartPar\n'
1498            'with a legend\n\\end{sphinxlegend}\n'
1499            r'\end{figure}' in result)
1500
1501    # code-blocks
1502    assert (r'\def\sphinxLiteralBlockLabel{'
1503            r'\label{\detokenize{index:codeblock2}}'
1504            r'\label{\detokenize{index:codeblock1}}}' in result)
1505    assert (r'\def\sphinxLiteralBlockLabel{'
1506            r'\label{\detokenize{index:codeblock3}}}' in result)
1507
1508    # tables
1509    assert (r'\sphinxcaption{table caption}'
1510            r'\label{\detokenize{index:id2}}'
1511            r'\label{\detokenize{index:table2}}'
1512            r'\label{\detokenize{index:table1}}' in result)
1513    assert (r'\sphinxcaption{table caption}'
1514            r'\label{\detokenize{index:table3}}' in result)
1515
1516    # sections
1517    assert ('\\chapter{subsection}\n'
1518            r'\label{\detokenize{index:subsection}}'
1519            r'\label{\detokenize{index:section2}}'
1520            r'\label{\detokenize{index:section1}}' in result)
1521    assert ('\\section{subsubsection}\n'
1522            r'\label{\detokenize{index:subsubsection}}'
1523            r'\label{\detokenize{index:section3}}' in result)
1524    assert ('\\subsection{otherdoc}\n'
1525            r'\label{\detokenize{otherdoc:otherdoc}}'
1526            r'\label{\detokenize{otherdoc::doc}}' in result)
1527
1528    # Embedded standalone hyperlink reference (refs: #5948)
1529    assert result.count(r'\label{\detokenize{index:section1}}') == 1
1530
1531
1532@pytest.mark.sphinx('latex', testroot='latex-figure-in-admonition')
1533def test_latex_figure_in_admonition(app, status, warning):
1534    app.builder.build_all()
1535    result = (app.outdir / 'python.tex').read_text()
1536    assert(r'\begin{figure}[H]' in result)
1537
1538
1539def test_default_latex_documents():
1540    from sphinx.util import texescape
1541    texescape.init()
1542    config = Config({'master_doc': 'index',
1543                     'project': 'STASI™ Documentation',
1544                     'author': "Wolfgang Schäuble & G'Beckstein."})
1545    config.init_values()
1546    config.add('latex_engine', None, True, None)
1547    config.add('latex_theme', 'manual', True, None)
1548    expected = [('index', 'stasi.tex', 'STASI™ Documentation',
1549                 r"Wolfgang Schäuble \& G\textquotesingle{}Beckstein.\@{}", 'manual')]
1550    assert default_latex_documents(config) == expected
1551
1552
1553@skip_if_requested
1554@skip_if_stylefiles_notfound
1555@pytest.mark.sphinx('latex', testroot='latex-includegraphics')
1556def test_includegraphics_oversized(app, status, warning):
1557    app.builder.build_all()
1558    print(status.getvalue())
1559    print(warning.getvalue())
1560    compile_latex_document(app)
1561
1562
1563@pytest.mark.sphinx('latex', testroot='index_on_title')
1564def test_index_on_title(app, status, warning):
1565    app.builder.build_all()
1566    result = (app.outdir / 'python.tex').read_text()
1567    assert ('\\chapter{Test for index in top level title}\n'
1568            '\\label{\\detokenize{contents:test-for-index-in-top-level-title}}'
1569            '\\index{index@\\spxentry{index}}\n'
1570            in result)
1571
1572
1573@pytest.mark.sphinx('latex', testroot='latex-unicode',
1574                    confoverrides={'latex_engine': 'pdflatex'})
1575def test_texescape_for_non_unicode_supported_engine(app, status, warning):
1576    app.builder.build_all()
1577    result = (app.outdir / 'python.tex').read_text()
1578    print(result)
1579    assert 'script small e: e' in result
1580    assert 'double struck italic small i: i' in result
1581    assert r'superscript: \(\sp{\text{0}}\), \(\sp{\text{1}}\)' in result
1582    assert r'subscript: \(\sb{\text{0}}\), \(\sb{\text{1}}\)' in result
1583
1584
1585@pytest.mark.sphinx('latex', testroot='latex-unicode',
1586                    confoverrides={'latex_engine': 'xelatex'})
1587def test_texescape_for_unicode_supported_engine(app, status, warning):
1588    app.builder.build_all()
1589    result = (app.outdir / 'python.tex').read_text()
1590    print(result)
1591    assert 'script small e: e' in result
1592    assert 'double struck italic small i: i' in result
1593    assert 'superscript: ⁰, ¹' in result
1594    assert 'subscript: ₀, ₁' in result
1595
1596
1597@pytest.mark.sphinx('latex', testroot='basic',
1598                    confoverrides={'latex_elements': {'extrapackages': r'\usepackage{foo}'}})
1599def test_latex_elements_extrapackages(app, status, warning):
1600    app.builder.build_all()
1601    result = (app.outdir / 'test.tex').read_text()
1602    assert r'\usepackage{foo}' in result
1603
1604
1605@pytest.mark.sphinx('latex', testroot='nested-tables')
1606def test_latex_nested_tables(app, status, warning):
1607    app.builder.build_all()
1608    assert '' == warning.getvalue()
1609