1"""
2    test_build
3    ~~~~~~~~~~
4
5    Test all builders.
6
7    :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
8    :license: BSD, see LICENSE for details.
9"""
10
11import sys
12from textwrap import dedent
13from unittest import mock
14
15import pytest
16from docutils import nodes
17
18from sphinx.errors import SphinxError
19from sphinx.testing.path import path
20
21
22def request_session_head(url, **kwargs):
23    response = mock.Mock()
24    response.status_code = 200
25    response.url = url
26    return response
27
28
29@pytest.fixture
30def nonascii_srcdir(request, rootdir, sphinx_test_tempdir):
31    # If supported, build in a non-ASCII source dir
32    test_name = '\u65e5\u672c\u8a9e'
33    basedir = sphinx_test_tempdir / request.node.originalname
34    try:
35        srcdir = basedir / test_name
36        if not srcdir.exists():
37            (rootdir / 'test-root').copytree(srcdir)
38    except UnicodeEncodeError:
39        # Now Python 3.7+ follows PEP-540 and uses utf-8 encoding for filesystem by default.
40        # So this error handling will be no longer used (after dropping python 3.6 support).
41        srcdir = basedir / 'all'
42        if not srcdir.exists():
43            (rootdir / 'test-root').copytree(srcdir)
44    else:
45        # add a doc with a non-ASCII file name to the source dir
46        (srcdir / (test_name + '.txt')).write_text(dedent("""
47            nonascii file name page
48            =======================
49            """))
50
51        master_doc = srcdir / 'index.txt'
52        master_doc.write_text(master_doc.read_text() + dedent("""
53                              .. toctree::
54
55                                 %(test_name)s/%(test_name)s
56                              """ % {'test_name': test_name}))
57    return srcdir
58
59
60# note: this test skips building docs for some builders because they have independent testcase.
61#       (html, changes, epub, latex, texinfo and manpage)
62@pytest.mark.parametrize(
63    "buildername",
64    ['dirhtml', 'singlehtml', 'text', 'xml', 'pseudoxml', 'linkcheck'],
65)
66@mock.patch('sphinx.builders.linkcheck.requests.head',
67            side_effect=request_session_head)
68@pytest.mark.xfail(sys.platform == 'win32', reason="Not working on windows")
69def test_build_all(requests_head, make_app, nonascii_srcdir, buildername):
70    app = make_app(buildername, srcdir=nonascii_srcdir)
71    app.build()
72
73
74def test_master_doc_not_found(tempdir, make_app):
75    (tempdir / 'conf.py').write_text('')
76    assert tempdir.listdir() == ['conf.py']
77
78    app = make_app('dummy', srcdir=tempdir)
79    with pytest.raises(SphinxError):
80        app.builder.build_all()  # no index.rst
81
82
83@pytest.mark.sphinx(buildername='text', testroot='circular')
84def test_circular_toctree(app, status, warning):
85    app.builder.build_all()
86    warnings = warning.getvalue()
87    assert (
88        'circular toctree references detected, ignoring: '
89        'sub <- index <- sub') in warnings
90    assert (
91        'circular toctree references detected, ignoring: '
92        'index <- sub <- index') in warnings
93
94
95@pytest.mark.sphinx(buildername='text', testroot='numbered-circular')
96def test_numbered_circular_toctree(app, status, warning):
97    app.builder.build_all()
98    warnings = warning.getvalue()
99    assert (
100        'circular toctree references detected, ignoring: '
101        'sub <- index <- sub') in warnings
102    assert (
103        'circular toctree references detected, ignoring: '
104        'index <- sub <- index') in warnings
105
106
107@pytest.mark.sphinx(buildername='dummy', testroot='images')
108def test_image_glob(app, status, warning):
109    app.builder.build_all()
110
111    # index.rst
112    doctree = app.env.get_doctree('index')
113
114    assert isinstance(doctree[0][1], nodes.image)
115    assert doctree[0][1]['candidates'] == {'*': 'rimg.png'}
116    assert doctree[0][1]['uri'] == 'rimg.png'
117
118    assert isinstance(doctree[0][2], nodes.figure)
119    assert isinstance(doctree[0][2][0], nodes.image)
120    assert doctree[0][2][0]['candidates'] == {'*': 'rimg.png'}
121    assert doctree[0][2][0]['uri'] == 'rimg.png'
122
123    assert isinstance(doctree[0][3], nodes.image)
124    assert doctree[0][3]['candidates'] == {'application/pdf': 'img.pdf',
125                                           'image/gif': 'img.gif',
126                                           'image/png': 'img.png'}
127    assert doctree[0][3]['uri'] == 'img.*'
128
129    assert isinstance(doctree[0][4], nodes.figure)
130    assert isinstance(doctree[0][4][0], nodes.image)
131    assert doctree[0][4][0]['candidates'] == {'application/pdf': 'img.pdf',
132                                              'image/gif': 'img.gif',
133                                              'image/png': 'img.png'}
134    assert doctree[0][4][0]['uri'] == 'img.*'
135
136    # subdir/index.rst
137    doctree = app.env.get_doctree('subdir/index')
138
139    assert isinstance(doctree[0][1], nodes.image)
140    sub = path('subdir')
141    assert doctree[0][1]['candidates'] == {'*': sub / 'rimg.png'}
142    assert doctree[0][1]['uri'] == sub / 'rimg.png'
143
144    assert isinstance(doctree[0][2], nodes.image)
145    assert doctree[0][2]['candidates'] == {'application/pdf': 'subdir/svgimg.pdf',
146                                           'image/svg+xml': 'subdir/svgimg.svg'}
147    assert doctree[0][2]['uri'] == sub / 'svgimg.*'
148
149    assert isinstance(doctree[0][3], nodes.figure)
150    assert isinstance(doctree[0][3][0], nodes.image)
151    assert doctree[0][3][0]['candidates'] == {'application/pdf': 'subdir/svgimg.pdf',
152                                              'image/svg+xml': 'subdir/svgimg.svg'}
153    assert doctree[0][3][0]['uri'] == sub / 'svgimg.*'
154