mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
We already have a helper function that allows us to convert a filename to a "docname". Don't reinvent the wheel and simply use this when building specific files with Sphinx. Note that this does change behavior slightly, insofar as filenames that don't resolve to valid docnames will now be ignored rather than being passed with their suffix and silently ignored later, but that seems sane. Signed-off-by: Stephen Finucane <stephen@that.guru>
156 lines
5.5 KiB
Python
156 lines
5.5 KiB
Python
"""Test the Sphinx class."""
|
|
|
|
import shutil
|
|
import sys
|
|
from io import StringIO
|
|
from pathlib import Path
|
|
from unittest.mock import Mock
|
|
|
|
import pytest
|
|
from docutils import nodes
|
|
|
|
import sphinx.application
|
|
from sphinx.errors import ExtensionError
|
|
from sphinx.testing.path import path
|
|
from sphinx.testing.util import SphinxTestApp, strip_escseq
|
|
from sphinx.util import logging
|
|
|
|
|
|
def test_instantiation(tmp_path_factory, rootdir: str, monkeypatch):
|
|
# Given
|
|
src_dir = tmp_path_factory.getbasetemp() / 'root'
|
|
|
|
# special support for sphinx/tests
|
|
if rootdir and not src_dir.exists():
|
|
shutil.copytree(Path(str(rootdir)) / 'test-root', src_dir)
|
|
|
|
monkeypatch.setattr('sphinx.application.abspath', lambda x: x)
|
|
|
|
syspath = sys.path[:]
|
|
|
|
# When
|
|
app_ = SphinxTestApp(
|
|
srcdir=path(src_dir),
|
|
status=StringIO(),
|
|
warning=StringIO()
|
|
)
|
|
sys.path[:] = syspath
|
|
app_.cleanup()
|
|
|
|
# Then
|
|
assert isinstance(app_, sphinx.application.Sphinx)
|
|
|
|
|
|
def test_events(app, status, warning):
|
|
def empty():
|
|
pass
|
|
with pytest.raises(ExtensionError) as excinfo:
|
|
app.connect("invalid", empty)
|
|
assert "Unknown event name: invalid" in str(excinfo.value)
|
|
|
|
app.add_event("my_event")
|
|
with pytest.raises(ExtensionError) as excinfo:
|
|
app.add_event("my_event")
|
|
assert "Event 'my_event' already present" in str(excinfo.value)
|
|
|
|
def mock_callback(a_app, *args):
|
|
assert a_app is app
|
|
assert emit_args == args
|
|
return "ret"
|
|
emit_args = (1, 3, "string")
|
|
listener_id = app.connect("my_event", mock_callback)
|
|
assert app.emit("my_event", *emit_args) == ["ret"], "Callback not called"
|
|
|
|
app.disconnect(listener_id)
|
|
assert app.emit("my_event", *emit_args) == [], \
|
|
"Callback called when disconnected"
|
|
|
|
|
|
def test_emit_with_nonascii_name_node(app, status, warning):
|
|
node = nodes.section(names=['\u65e5\u672c\u8a9e'])
|
|
app.emit('my_event', node)
|
|
|
|
|
|
def test_extensions(app, status, warning):
|
|
app.setup_extension('shutil')
|
|
warning = strip_escseq(warning.getvalue())
|
|
assert "extension 'shutil' has no setup() function" in warning
|
|
|
|
|
|
def test_extension_in_blacklist(app, status, warning):
|
|
app.setup_extension('sphinxjp.themecore')
|
|
msg = strip_escseq(warning.getvalue())
|
|
assert msg.startswith("WARNING: the extension 'sphinxjp.themecore' was")
|
|
|
|
|
|
@pytest.mark.sphinx(testroot='add_source_parser')
|
|
def test_add_source_parser(app, status, warning):
|
|
assert set(app.config.source_suffix) == {'.rst', '.test'}
|
|
|
|
# .rst; only in :confval:`source_suffix`
|
|
assert '.rst' not in app.registry.get_source_parsers()
|
|
assert app.registry.source_suffix['.rst'] is None
|
|
|
|
# .test; configured by API
|
|
assert app.registry.source_suffix['.test'] == 'test'
|
|
assert 'test' in app.registry.get_source_parsers()
|
|
assert app.registry.get_source_parsers()['test'].__name__ == 'TestSourceParser'
|
|
|
|
|
|
@pytest.mark.sphinx(testroot='extensions')
|
|
def test_add_is_parallel_allowed(app, status, warning):
|
|
logging.setup(app, status, warning)
|
|
|
|
assert app.is_parallel_allowed('read') is True
|
|
assert app.is_parallel_allowed('write') is True
|
|
assert warning.getvalue() == ''
|
|
|
|
app.setup_extension('read_parallel')
|
|
assert app.is_parallel_allowed('read') is True
|
|
assert app.is_parallel_allowed('write') is True
|
|
assert warning.getvalue() == ''
|
|
app.extensions.pop('read_parallel')
|
|
|
|
app.setup_extension('write_parallel')
|
|
assert app.is_parallel_allowed('read') is False
|
|
assert app.is_parallel_allowed('write') is True
|
|
assert ("the write_parallel extension does not declare if it is safe "
|
|
"for parallel reading, assuming it isn't - please ") in warning.getvalue()
|
|
app.extensions.pop('write_parallel')
|
|
warning.truncate(0) # reset warnings
|
|
|
|
app.setup_extension('read_serial')
|
|
assert app.is_parallel_allowed('read') is False
|
|
assert "the read_serial extension is not safe for parallel reading" in warning.getvalue()
|
|
warning.truncate(0) # reset warnings
|
|
assert app.is_parallel_allowed('write') is True
|
|
assert warning.getvalue() == ''
|
|
app.extensions.pop('read_serial')
|
|
|
|
app.setup_extension('write_serial')
|
|
assert app.is_parallel_allowed('read') is False
|
|
assert app.is_parallel_allowed('write') is False
|
|
assert ("the write_serial extension does not declare if it is safe "
|
|
"for parallel reading, assuming it isn't - please ") in warning.getvalue()
|
|
app.extensions.pop('write_serial')
|
|
warning.truncate(0) # reset warnings
|
|
|
|
|
|
@pytest.mark.sphinx('dummy', testroot='root')
|
|
def test_build_specific(app):
|
|
app.builder.build = Mock()
|
|
filenames = [app.srcdir / 'index.txt', # normal
|
|
app.srcdir / 'images', # without suffix
|
|
app.srcdir / 'notfound.txt', # not found
|
|
app.srcdir / 'img.png', # unknown suffix
|
|
'/index.txt', # external file
|
|
app.srcdir / 'subdir', # directory
|
|
app.srcdir / 'subdir/includes.txt', # file on subdir
|
|
app.srcdir / 'subdir/../subdir/excluded.txt'] # not normalized
|
|
app.build(False, filenames)
|
|
|
|
expected = ['index', 'subdir/includes', 'subdir/excluded']
|
|
app.builder.build.assert_called_with(expected,
|
|
method='specific',
|
|
summary='3 source files given on command line')
|