diff options
Diffstat (limited to 'tests/test_application.py')
-rw-r--r-- | tests/test_application.py | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/tests/test_application.py b/tests/test_application.py new file mode 100644 index 0000000..e297eff --- /dev/null +++ b/tests/test_application.py @@ -0,0 +1,155 @@ +"""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') |