1""" 2 test_application 3 ~~~~~~~~~~~~~~~~ 4 5 Test the Sphinx class. 6 7 :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. 8 :license: BSD, see LICENSE for details. 9""" 10 11from unittest.mock import Mock 12 13import pytest 14from docutils import nodes 15 16from sphinx.errors import ExtensionError 17from sphinx.testing.util import strip_escseq 18from sphinx.util import logging 19 20 21def test_events(app, status, warning): 22 def empty(): 23 pass 24 with pytest.raises(ExtensionError) as excinfo: 25 app.connect("invalid", empty) 26 assert "Unknown event name: invalid" in str(excinfo.value) 27 28 app.add_event("my_event") 29 with pytest.raises(ExtensionError) as excinfo: 30 app.add_event("my_event") 31 assert "Event 'my_event' already present" in str(excinfo.value) 32 33 def mock_callback(a_app, *args): 34 assert a_app is app 35 assert emit_args == args 36 return "ret" 37 emit_args = (1, 3, "string") 38 listener_id = app.connect("my_event", mock_callback) 39 assert app.emit("my_event", *emit_args) == ["ret"], "Callback not called" 40 41 app.disconnect(listener_id) 42 assert app.emit("my_event", *emit_args) == [], \ 43 "Callback called when disconnected" 44 45 46def test_emit_with_nonascii_name_node(app, status, warning): 47 node = nodes.section(names=['\u65e5\u672c\u8a9e']) 48 app.emit('my_event', node) 49 50 51def test_extensions(app, status, warning): 52 app.setup_extension('shutil') 53 warning = strip_escseq(warning.getvalue()) 54 assert "extension 'shutil' has no setup() function" in warning 55 56 57def test_extension_in_blacklist(app, status, warning): 58 app.setup_extension('sphinxjp.themecore') 59 msg = strip_escseq(warning.getvalue()) 60 assert msg.startswith("WARNING: the extension 'sphinxjp.themecore' was") 61 62 63@pytest.mark.sphinx(testroot='add_source_parser') 64def test_add_source_parser(app, status, warning): 65 assert set(app.config.source_suffix) == {'.rst', '.test'} 66 67 # .rst; only in :confval:`source_suffix` 68 assert '.rst' not in app.registry.get_source_parsers() 69 assert app.registry.source_suffix['.rst'] is None 70 71 # .test; configured by API 72 assert app.registry.source_suffix['.test'] == 'test' 73 assert 'test' in app.registry.get_source_parsers() 74 assert app.registry.get_source_parsers()['test'].__name__ == 'TestSourceParser' 75 76 77@pytest.mark.sphinx(testroot='extensions') 78def test_add_is_parallel_allowed(app, status, warning): 79 logging.setup(app, status, warning) 80 81 assert app.is_parallel_allowed('read') is True 82 assert app.is_parallel_allowed('write') is True 83 assert warning.getvalue() == '' 84 85 app.setup_extension('read_parallel') 86 assert app.is_parallel_allowed('read') is True 87 assert app.is_parallel_allowed('write') is True 88 assert warning.getvalue() == '' 89 app.extensions.pop('read_parallel') 90 91 app.setup_extension('write_parallel') 92 assert app.is_parallel_allowed('read') is False 93 assert app.is_parallel_allowed('write') is True 94 assert ("the write_parallel extension does not declare if it is safe " 95 "for parallel reading, assuming it isn't - please ") in warning.getvalue() 96 app.extensions.pop('write_parallel') 97 warning.truncate(0) # reset warnings 98 99 app.setup_extension('read_serial') 100 assert app.is_parallel_allowed('read') is False 101 assert "the read_serial extension is not safe for parallel reading" in warning.getvalue() 102 warning.truncate(0) # reset warnings 103 assert app.is_parallel_allowed('write') is True 104 assert warning.getvalue() == '' 105 app.extensions.pop('read_serial') 106 107 app.setup_extension('write_serial') 108 assert app.is_parallel_allowed('read') is False 109 assert app.is_parallel_allowed('write') is False 110 assert ("the write_serial extension does not declare if it is safe " 111 "for parallel reading, assuming it isn't - please ") in warning.getvalue() 112 app.extensions.pop('write_serial') 113 warning.truncate(0) # reset warnings 114 115 116@pytest.mark.sphinx('dummy', testroot='root') 117def test_build_specific(app): 118 app.builder.build = Mock() 119 filenames = [app.srcdir / 'index.txt', # normal 120 app.srcdir / 'images', # without suffix 121 app.srcdir / 'notfound.txt', # not found 122 app.srcdir / 'img.png', # unknown suffix 123 '/index.txt', # external file 124 app.srcdir / 'subdir', # directory 125 app.srcdir / 'subdir/includes.txt', # file on subdir 126 app.srcdir / 'subdir/../subdir/excluded.txt'] # not normalized 127 app.build(False, filenames) 128 129 expected = ['index', 'img.png', 'subdir/includes', 'subdir/excluded'] 130 app.builder.build.assert_called_with(expected, 131 method='specific', 132 summary='4 source files given on command line') 133