1"""
2    test_setup_command
3    ~~~~~~~~~~~~~~~~~~~
4
5    Test setup_command for distutils.
6
7    :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
8    :license: BSD, see LICENSE for details.
9"""
10
11import os
12import subprocess
13import sys
14from collections import namedtuple
15from textwrap import dedent
16
17import pytest
18
19import sphinx
20from sphinx.util.osutil import cd
21
22
23@pytest.fixture
24def setup_command(request, tempdir, rootdir):
25    """
26    Run `setup.py build_sphinx` with args and kwargs,
27    pass it to the test and clean up properly.
28    """
29    if hasattr(request.node, 'get_closest_marker'):  # pytest-3.6.0 or newer
30        marker = request.node.get_closest_marker('setup_command')
31    else:
32        marker = request.node.get_marker('setup_command')
33    args = marker.args if marker else []
34
35    pkgrootdir = tempdir / 'test-setup'
36    (rootdir / 'test-setup').copytree(pkgrootdir)
37
38    with cd(pkgrootdir):
39        pythonpath = os.path.dirname(os.path.dirname(sphinx.__file__))
40        if os.getenv('PYTHONPATH'):
41            pythonpath = os.getenv('PYTHONPATH') + os.pathsep + pythonpath
42        command = [sys.executable, 'setup.py', 'build_sphinx']
43        command.extend(args)
44
45        proc = subprocess.Popen(
46            command,
47            env=dict(os.environ, PYTHONPATH=pythonpath),
48            stdout=subprocess.PIPE,
49            stderr=subprocess.PIPE)
50        yield namedtuple('setup', 'pkgroot,proc')(pkgrootdir, proc)
51
52
53def test_build_sphinx(setup_command):
54    proc = setup_command.proc
55    out, err = proc.communicate()
56    print(out.decode())
57    print(err.decode())
58    assert proc.returncode == 0
59
60
61@pytest.mark.setup_command('-b', 'html,man')
62def test_build_sphinx_multiple_builders(setup_command):
63    proc = setup_command.proc
64    out, err = proc.communicate()
65    print(out.decode())
66    print(err.decode())
67    assert proc.returncode == 0
68
69
70@pytest.mark.setup_command('-b', 'html,bar')
71def test_build_sphinx_multiple_invalid_builders(setup_command):
72    proc = setup_command.proc
73    out, err = proc.communicate()
74    print(out.decode())
75    print(err.decode())
76    assert proc.returncode == 1
77
78
79@pytest.fixture
80def nonascii_srcdir(request, setup_command):
81    mb_name = '\u65e5\u672c\u8a9e'
82    srcdir = (setup_command.pkgroot / 'doc')
83    try:
84        (srcdir / mb_name).makedirs()
85    except UnicodeEncodeError:
86        from sphinx.testing.path import FILESYSTEMENCODING
87        pytest.skip(
88            'non-ASCII filename not supported on this filesystem encoding: '
89            '%s' % FILESYSTEMENCODING)
90
91    (srcdir / mb_name / (mb_name + '.txt')).write_text(dedent("""
92        multi byte file name page
93        ==========================
94        """))
95
96    master_doc = srcdir / 'index.txt'
97    master_doc.write_bytes((master_doc.read_text() + dedent("""
98                            .. toctree::
99
100                               %(mb_name)s/%(mb_name)s
101                            """ % locals())).encode())
102
103
104@pytest.mark.usefixtures('nonascii_srcdir')
105def test_build_sphinx_with_nonascii_path(setup_command):
106    proc = setup_command.proc
107    out, err = proc.communicate()
108    print(out.decode())
109    print(err.decode())
110    assert proc.returncode == 0
111
112
113@pytest.mark.setup_command('-b', 'linkcheck')
114def test_build_sphinx_return_nonzero_status(setup_command):
115    srcdir = (setup_command.pkgroot / 'doc')
116    (srcdir / 'contents.txt').write_text(
117        'http://localhost.unexistentdomain/index.html')
118    proc = setup_command.proc
119    out, err = proc.communicate()
120    print(out.decode())
121    print(err.decode())
122    assert proc.returncode != 0, 'expect non-zero status for setup.py'
123
124
125def test_build_sphinx_warning_return_zero_status(setup_command):
126    srcdir = (setup_command.pkgroot / 'doc')
127    (srcdir / 'contents.txt').write_text(
128        'See :ref:`unexisting-reference-label`')
129    proc = setup_command.proc
130    out, err = proc.communicate()
131    print(out.decode())
132    print(err.decode())
133    assert proc.returncode == 0
134
135
136@pytest.mark.setup_command('--warning-is-error')
137def test_build_sphinx_warning_is_error_return_nonzero_status(setup_command):
138    srcdir = (setup_command.pkgroot / 'doc')
139    (srcdir / 'contents.txt').write_text(
140        'See :ref:`unexisting-reference-label`')
141    proc = setup_command.proc
142    out, err = proc.communicate()
143    print(out.decode())
144    print(err.decode())
145    assert proc.returncode != 0, 'expect non-zero status for setup.py'
146