Merge pull request #3718 from sphinx-doc/3458-sphinx-testing

refs #3458 sphinx.testing
This commit is contained in:
Takeshi KOMIYA 2017-05-16 15:06:02 +09:00 committed by GitHub
commit 384839f37c
97 changed files with 535 additions and 452 deletions

View File

@ -34,6 +34,8 @@ Bugs fixed
Testing Testing
-------- --------
* #3458: Add ``sphinx.testing` (experimental)
Release 1.6 beta3 (released May 07, 2017) Release 1.6 beta3 (released May 07, 2017)
========================================= =========================================

View File

@ -337,3 +337,28 @@ warnings with:
* ``PYTHONWARNINGS= make html`` (Linux/Mac) * ``PYTHONWARNINGS= make html`` (Linux/Mac)
* ``export PYTHONWARNINGS=`` and do ``make html`` (Linux/Mac) * ``export PYTHONWARNINGS=`` and do ``make html`` (Linux/Mac)
* ``set PYTHONWARNINGS=`` and do ``make html`` (Windows) * ``set PYTHONWARNINGS=`` and do ``make html`` (Windows)
Unit Testing
------------
Sphinx has been tested with pytest runner. Sphinx developers write unit tests
using pytest notation. Utility functions and pytest fixtures for testing are
provided in ``sphinx.testing``. If you are a developer of Sphinx extensions,
you can write unit tests with using pytest. At this time, ``sphinx.testing``
will help your test implementation.
How to use pytest fixtures that are provided by ``sphinx.teting``?
You can require ``'sphinx.testing.fixtures'`` in your test modules or
``conftest.py`` files like this::
pytest_plugins = 'sphinx.testing.fixtures'
If you want to know more detailed usage, please refer to ``tests/conftest.py``
and other ``test_*.py`` files under ``tests`` directory.
.. note::
Prior to Sphinx - 1.5.2, Sphinx was running the test with nose.
.. versionadded:: 1.6
``sphinx.testing`` as a experimental.

View File

@ -0,0 +1,15 @@
# -*- coding: utf-8 -*-
"""
sphinx.testing
~~~~~~~~~~~~~~
Sphinx test utilities
You can require sphinx.testing pytest fixtures in a test module or a conftest
file like this:
pytest_plugins = 'sphinx.testing.fixtures'
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

231
sphinx/testing/fixtures.py Normal file
View File

@ -0,0 +1,231 @@
# -*- coding: utf-8 -*-
"""
sphinx.testing.fixtures
~~~~~~~~~~~~~~~~~~~~~~~
Sphinx test fixtures for pytest
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
from __future__ import print_function
import os
import subprocess
import sys
from collections import namedtuple
from tempfile import gettempdir
import pytest
from six import StringIO, string_types
from . import util
if False:
from typing import Dict, Union # NOQA
@pytest.fixture(scope='session')
def rootdir():
return None
@pytest.fixture
def app_params(request, test_params, shared_result, sphinx_test_tempdir, rootdir):
"""
parameters that is specified by 'pytest.mark.sphinx' for
sphinx.application.Sphinx initialization
"""
# ##### process pytest.mark.sphinx
markers = request.node.get_marker("sphinx")
pargs = {}
kwargs = {} # type: Dict[str, str]
if markers is not None:
# to avoid stacking positional args
for info in reversed(list(markers)):
for i, a in enumerate(info.args):
pargs[i] = a
kwargs.update(info.kwargs)
args = [pargs[i] for i in sorted(pargs.keys())]
# ##### process pytest.mark.test_params
if test_params['shared_result']:
if 'srcdir' in kwargs:
raise pytest.Exception('You can not spcify shared_result and '
'srcdir in same time.')
kwargs['srcdir'] = test_params['shared_result']
restore = shared_result.restore(test_params['shared_result'])
kwargs.update(restore)
# ##### prepare Application params
testroot = kwargs.pop('testroot', 'root')
kwargs['srcdir'] = srcdir = sphinx_test_tempdir / kwargs.get('srcdir', testroot)
# special support for sphinx/tests
if rootdir and not srcdir.exists():
testroot_path = rootdir / ('test-' + testroot)
testroot_path.copytree(srcdir)
return namedtuple('app_params', 'args,kwargs')(args, kwargs) # type: ignore
@pytest.fixture
def test_params(request):
"""
test parameters that is specified by 'pytest.mark.test_params'
:param Union[str] shared_result:
If the value is provided, app._status and app._warning objects will be
shared in the parametrized test functions and/or test functions that
have same 'shared_result' value.
**NOTE**: You can not specify shared_result and srcdir in same time.
"""
env = request.node.get_marker('test_params')
kwargs = env.kwargs if env else {}
result = {
'shared_result': None,
}
result.update(kwargs)
if (result['shared_result'] and
not isinstance(result['shared_result'], string_types)):
raise pytest.Exception('You can only provide a string type of value '
'for "shared_result" ')
return result
@pytest.fixture(scope='function')
def app(test_params, app_params, make_app, shared_result):
"""
provides sphinx.application.Sphinx object
"""
args, kwargs = app_params
app_ = make_app(*args, **kwargs)
yield app_
print('# testroot:', kwargs.get('testroot', 'root'))
print('# builder:', app_.builder.name)
print('# srcdir:', app_.srcdir)
print('# outdir:', app_.outdir)
print('# status:', '\n' + app_._status.getvalue())
print('# warning:', '\n' + app_._warning.getvalue())
if test_params['shared_result']:
shared_result.store(test_params['shared_result'], app_)
@pytest.fixture(scope='function')
def status(app):
"""
compat for testing with previous @with_app decorator
"""
return app._status
@pytest.fixture(scope='function')
def warning(app):
"""
compat for testing with previous @with_app decorator
"""
return app._warning
@pytest.fixture()
def make_app(test_params):
"""
provides make_app function to initialize SphinxTestApp instance.
if you want to initialize 'app' in your test function. please use this
instead of using SphinxTestApp class directory.
"""
apps = []
syspath = sys.path[:]
def make(*args, **kwargs):
status, warning = StringIO(), StringIO()
kwargs.setdefault('status', status)
kwargs.setdefault('warning', warning)
app_ = util.SphinxTestApp(*args, **kwargs) # type: Union[util.SphinxTestApp, util.SphinxTestAppWrapperForSkipBuilding] # NOQA
apps.append(app_)
if test_params['shared_result']:
app_ = util.SphinxTestAppWrapperForSkipBuilding(app_)
return app_
yield make
sys.path[:] = syspath
for app_ in apps:
app_.cleanup()
class SharedResult(object):
cache = {} # type: Dict[str, Dict[str, str]]
def store(self, key, app_):
if key in self.cache:
return
data = {
'status': app_._status.getvalue(),
'warning': app_._warning.getvalue(),
}
self.cache[key] = data
def restore(self, key):
if key not in self.cache:
return {}
data = self.cache[key]
return {
'status': StringIO(data['status']),
'warning': StringIO(data['warning']),
}
@pytest.fixture
def shared_result():
return SharedResult()
@pytest.fixture(scope='module', autouse=True)
def _shared_result_cache():
SharedResult.cache.clear()
@pytest.fixture
def if_graphviz_found(app):
"""
The test will be skipped when using 'if_graphviz_found' fixture and graphviz
dot command is not found.
"""
graphviz_dot = getattr(app.config, 'graphviz_dot', '')
try:
if graphviz_dot:
dot = subprocess.Popen([graphviz_dot, '-V'],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE) # show version
dot.communicate()
return
except OSError: # No such file or directory
pass
pytest.skip('graphviz "dot" is not available')
@pytest.fixture(scope='session')
def sphinx_test_tempdir():
"""
temporary directory that wrapped with `path` class.
"""
return util.path(os.environ.get('SPHINX_TEST_TEMPDIR', gettempdir())).abspath()
@pytest.fixture
def tempdir(tmpdir):
"""
temporary directory that wrapped with `path` class.
this fixture is for compat with old test implementation.
"""
return util.path(tmpdir)

9
tests/path.py → sphinx/testing/path.py Executable file → Normal file
View File

@ -1,8 +1,7 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
path sphinx.testing.path
~~~~ ~~~~~~~~~~~~~~~~~~~
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
@ -26,8 +25,8 @@ class path(text_type):
def __new__(cls, s, encoding=FILESYSTEMENCODING, errors='strict'): def __new__(cls, s, encoding=FILESYSTEMENCODING, errors='strict'):
if isinstance(s, str): if isinstance(s, str):
s = s.decode(encoding, errors) s = s.decode(encoding, errors)
return text_type.__new__(cls, s) return text_type.__new__(cls, s) # type: ignore
return text_type.__new__(cls, s) return text_type.__new__(cls, s) # type: ignore
@property @property
def parent(self): def parent(self):

View File

@ -1,12 +1,13 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
sphinx.testing.util
~~~~~~~~~~~~~~~~~~~
Sphinx test suite utilities Sphinx test suite utilities
~~~~~~~~~~~~~~~~~~~~~~~~~~~
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
import os import os
import re import re
import sys import sys
@ -28,22 +29,19 @@ from sphinx.ext.autodoc import AutoDirective
from sphinx.pycode import ModuleAnalyzer from sphinx.pycode import ModuleAnalyzer
from sphinx.deprecation import RemovedInSphinx17Warning from sphinx.deprecation import RemovedInSphinx17Warning
from path import path from sphinx.testing.path import path
if False:
from typing import List # NOQA
__all__ = [ __all__ = [
'rootdir', 'tempdir', 'Struct',
'skip_unless_importable', 'Struct', 'SphinxTestApp', 'SphinxTestAppWrapperForSkipBuilding',
'SphinxTestApp',
'path',
'remove_unicode_literals', 'remove_unicode_literals',
] ]
rootdir = path(os.path.dirname(__file__) or '.').abspath()
tempdir = path(os.environ['SPHINX_TEST_TEMPDIR']).abspath()
def assert_re_search(regex, text, flags=0): def assert_re_search(regex, text, flags=0):
if not re.search(regex, text, flags): if not re.search(regex, text, flags):
assert False, '%r did not match %r' % (regex, text) assert False, '%r did not match %r' % (regex, text)
@ -88,16 +86,6 @@ def assert_node(node, cls=None, xpath="", **kwargs):
'The node%s[%s] is not %r: %r' % (xpath, key, value, node[key]) 'The node%s[%s] is not %r: %r' % (xpath, key, value, node[key])
def skip_unless_importable(module, msg=None):
"""Decorator to skip test if module is not importable."""
try:
__import__(module)
except ImportError:
return pytest.mark.skipif(True, reason=(msg or 'conditional skip'))
else:
return pytest.mark.skipif(False, reason=(msg or 'conditional skip'))
def etree_parse(path): def etree_parse(path):
with warnings.catch_warnings(record=False): with warnings.catch_warnings(record=False):
warnings.filterwarnings("ignore", category=DeprecationWarning) warnings.filterwarnings("ignore", category=DeprecationWarning)
@ -115,22 +103,9 @@ class SphinxTestApp(application.Sphinx):
better default values for the initialization parameters. better default values for the initialization parameters.
""" """
def __init__(self, buildername='html', testroot=None, srcdir=None, def __init__(self, buildername='html', srcdir=None,
freshenv=False, confoverrides=None, status=None, warning=None, freshenv=False, confoverrides=None, status=None, warning=None,
tags=None, docutilsconf=None): tags=None, docutilsconf=None):
if testroot is None:
defaultsrcdir = 'root'
testroot = rootdir / 'root'
else:
defaultsrcdir = 'test-' + testroot
testroot = rootdir / 'roots' / ('test-' + testroot)
if srcdir is None:
srcdir = tempdir / defaultsrcdir
else:
srcdir = tempdir / srcdir
if not srcdir.exists():
testroot.copytree(srcdir)
if docutilsconf is not None: if docutilsconf is not None:
(srcdir / 'docutils.conf').write_text(docutilsconf) (srcdir / 'docutils.conf').write_text(docutilsconf)
@ -184,6 +159,26 @@ class SphinxTestApp(application.Sphinx):
return '<%s buildername=%r>' % (self.__class__.__name__, self.builder.name) return '<%s buildername=%r>' % (self.__class__.__name__, self.builder.name)
class SphinxTestAppWrapperForSkipBuilding(object):
"""
This class is a wrapper for SphinxTestApp to speed up the test by skipping
`app.build` process if it is already built and there is even one output
file.
"""
def __init__(self, app_):
self.app = app_
def __getattr__(self, name):
return getattr(self.app, name)
def build(self, *args, **kw):
if not self.app.outdir.listdir():
# if listdir is empty, do build.
self.app.build(*args, **kw)
# otherwise, we can use built cache
_unicode_literals_re = re.compile(r'u(".*?")|u(\'.*?\')') _unicode_literals_re = re.compile(r'u(".*?")|u(\'.*?\')')
@ -313,7 +308,7 @@ class ListOutput(object):
""" """
def __init__(self, name): def __init__(self, name):
self.name = name self.name = name
self.content = [] self.content = [] # type: List[str]
def reset(self): def reset(self):
del self.content[:] del self.content[:]

View File

@ -1,230 +1,20 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import print_function """
pytest config for sphinx/tests
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
import sys :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
import subprocess :license: BSD, see LICENSE for details.
from collections import namedtuple """
import os
import pytest import pytest
from six import StringIO, string_types from sphinx.testing.path import path
import util pytest_plugins = 'sphinx.testing.fixtures'
@pytest.fixture @pytest.fixture(scope='session')
def app_params(request, test_params, shared_result): def rootdir():
""" return path(os.path.dirname(__file__) or '.').abspath() / 'roots'
parameters that is specified by 'pytest.mark.sphinx' for
sphinx.application.Sphinx initialization
"""
# ##### process pytest.mark.sphinx
markers = request.node.get_marker("sphinx")
pargs = {}
kwargs = {}
if markers is not None:
# to avoid stacking positional args
for info in reversed(list(markers)):
for i, a in enumerate(info.args):
pargs[i] = a
kwargs.update(info.kwargs)
args = [pargs[i] for i in sorted(pargs.keys())]
# ##### process pytest.mark.test_params
if test_params['shared_result']:
if 'srcdir' in kwargs:
raise pytest.Exception('You can not spcify shared_result and '
'srcdir in same time.')
kwargs['srcdir'] = test_params['shared_result']
restore = shared_result.restore(test_params['shared_result'])
kwargs.update(restore)
# ##### prepare Application params
if 'srcdir' in kwargs:
srcdir = util.tempdir / kwargs['srcdir']
else:
srcdir = util.tempdir / kwargs.get('testroot', 'root')
kwargs['srcdir'] = srcdir
if kwargs.get('testroot') is None:
testroot_path = util.rootdir / 'root'
else:
testroot_path = util.rootdir / 'roots' / ('test-' + kwargs['testroot'])
if not srcdir.exists():
testroot_path.copytree(srcdir)
return namedtuple('app_params', 'args,kwargs')(args, kwargs)
@pytest.fixture
def test_params(request):
"""
test parameters that is specified by 'pytest.mark.test_params'
:param Union[str] shared_result:
If the value is provided, app._status and app._warning objects will be
shared in the parametrized test functions and/or test functions that
have same 'shared_result' value.
**NOTE**: You can not specify shared_result and srcdir in same time.
"""
env = request.node.get_marker('test_params')
kwargs = env.kwargs if env else {}
result = {
'shared_result': None,
}
result.update(kwargs)
if (result['shared_result'] and
not isinstance(result['shared_result'], string_types)):
raise pytest.Exception('You can only provide a string type of value '
'for "shared_result" ')
return result
class SphinxTestAppWrapperForSkipBuilding(object):
"""
This class is a wrapper for SphinxTestApp to speed up the test by skipping
`app.build` process if it is already built and there is even one output
file.
"""
def __init__(self, app_):
self.app = app_
def __getattr__(self, name):
return getattr(self.app, name)
def build(self, *args, **kw):
if not self.app.outdir.listdir():
# if listdir is empty, do build.
self.app.build(*args, **kw)
# otherwise, we can use built cache
@pytest.fixture(scope='function')
def app(test_params, app_params, make_app, shared_result):
"""
provides sphinx.application.Sphinx object
"""
args, kwargs = app_params
app_ = make_app(*args, **kwargs)
yield app_
print('# testroot:', kwargs.get('testroot', 'root'))
print('# builder:', app_.builder.name)
print('# srcdir:', app_.srcdir)
print('# outdir:', app_.outdir)
print('# status:', '\n' + app_._status.getvalue())
print('# warning:', '\n' + app_._warning.getvalue())
if test_params['shared_result']:
shared_result.store(test_params['shared_result'], app_)
@pytest.fixture(scope='function')
def status(app):
"""
compat for testing with previous @with_app decorator
"""
return app._status
@pytest.fixture(scope='function')
def warning(app):
"""
compat for testing with previous @with_app decorator
"""
return app._warning
@pytest.fixture()
def make_app(test_params):
"""
provides make_app function to initialize SphinxTestApp instance.
if you want to initialize 'app' in your test function. please use this
instead of using SphinxTestApp class directory.
"""
apps = []
syspath = sys.path[:]
def make(*args, **kwargs):
status, warning = StringIO(), StringIO()
kwargs.setdefault('status', status)
kwargs.setdefault('warning', warning)
app_ = util.SphinxTestApp(*args, **kwargs)
apps.append(app_)
if test_params['shared_result']:
app_ = SphinxTestAppWrapperForSkipBuilding(app_)
return app_
yield make
sys.path[:] = syspath
for app_ in apps:
app_.cleanup()
class SharedResult(object):
cache = {}
def store(self, key, app_):
if key in self.cache:
return
data = {
'status': app_._status.getvalue(),
'warning': app_._warning.getvalue(),
}
self.cache[key] = data
def restore(self, key):
if key not in self.cache:
return {}
data = self.cache[key]
return {
'status': StringIO(data['status']),
'warning': StringIO(data['warning']),
}
@pytest.fixture
def shared_result():
return SharedResult()
@pytest.fixture(scope='module', autouse=True)
def _shared_result_cache():
SharedResult.cache.clear()
@pytest.fixture
def if_graphviz_found(app):
"""
The test will be skipped when using 'if_graphviz_found' fixture and graphviz
dot command is not found.
"""
graphviz_dot = getattr(app.config, 'graphviz_dot', '')
try:
if graphviz_dot:
dot = subprocess.Popen([graphviz_dot, '-V'],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE) # show version
dot.communicate()
return
except OSError: # No such file or directory
pass
pytest.skip('graphviz "dot" is not available')
@pytest.fixture
def tempdir(tmpdir):
"""
temporary directory that wrapped with `path` class.
this fixture is for compat with old test implementation.
"""
return util.path(tmpdir)

View File

@ -13,7 +13,7 @@
# "raises" imported for usage by autodoc # "raises" imported for usage by autodoc
import six import six
import sys import sys
from util import SphinxTestApp, Struct from sphinx.testing.util import SphinxTestApp, Struct
import pytest import pytest
from six import StringIO from six import StringIO
@ -25,17 +25,19 @@ from sphinx.ext.autodoc import AutoDirective, add_documenter, \
app = None app = None
def setup_module(): @pytest.fixture(scope='module', autouse=True)
def setup_module(rootdir, sphinx_test_tempdir):
global app global app
app = SphinxTestApp() srcdir = sphinx_test_tempdir / 'autodoc-root'
if not srcdir.exists():
(rootdir/'test-root').copytree(srcdir)
app = SphinxTestApp(srcdir=srcdir)
app.builder.env.app = app app.builder.env.app = app
app.builder.env.temp_data['docname'] = 'dummy' app.builder.env.temp_data['docname'] = 'dummy'
app.connect('autodoc-process-docstring', process_docstring) app.connect('autodoc-process-docstring', process_docstring)
app.connect('autodoc-process-signature', process_signature) app.connect('autodoc-process-signature', process_signature)
app.connect('autodoc-skip-member', skip_member) app.connect('autodoc-skip-member', skip_member)
yield
def teardown_module():
app.cleanup() app.cleanup()

View File

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 65 KiB

View File

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View File

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 65 KiB

View File

Before

Width:  |  Height:  |  Size: 120 B

After

Width:  |  Height:  |  Size: 120 B

View File

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 65 KiB

View File

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 65 KiB

View File

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

View File

Before

Width:  |  Height:  |  Size: 120 B

After

Width:  |  Height:  |  Size: 120 B

View File

@ -15,8 +15,7 @@ import os
import sys import sys
import warnings import warnings
import traceback import traceback
import shutil
from path import path
testroot = os.path.dirname(__file__) or '.' testroot = os.path.dirname(__file__) or '.'
sys.path.insert(0, os.path.abspath(os.path.join(testroot, os.path.pardir))) sys.path.insert(0, os.path.abspath(os.path.join(testroot, os.path.pardir)))
@ -46,19 +45,20 @@ os.environ['SPHINX_TEST_TEMPDIR'] = \
os.path.abspath(os.path.join(testroot, 'build')) \ os.path.abspath(os.path.join(testroot, 'build')) \
if 'SPHINX_TEST_TEMPDIR' not in os.environ \ if 'SPHINX_TEST_TEMPDIR' not in os.environ \
else os.path.abspath(os.environ['SPHINX_TEST_TEMPDIR']) else os.path.abspath(os.environ['SPHINX_TEST_TEMPDIR'])
tempdir = path(os.environ['SPHINX_TEST_TEMPDIR'])
tempdir = os.environ['SPHINX_TEST_TEMPDIR']
print('Temporary files will be placed in %s.' % tempdir) print('Temporary files will be placed in %s.' % tempdir)
if tempdir.exists(): if os.path.exists(tempdir):
tempdir.rmtree() shutil.rmtree(tempdir)
tempdir.makedirs() os.makedirs(tempdir)
print('Running Sphinx test suite (with Python %s)...' % sys.version.split()[0]) print('Running Sphinx test suite (with Python %s)...' % sys.version.split()[0])
sys.stdout.flush() sys.stdout.flush()
# exclude 'root' and 'roots' dirs for pytest test collector # exclude 'roots' dirs for pytest test collector
ignore_paths = [ ignore_paths = [
os.path.relpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), sub)) os.path.relpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), sub))
for sub in ('root', 'roots') for sub in ('roots',)
] ]
args = sys.argv[1:] args = sys.argv[1:]
for ignore_path in ignore_paths: for ignore_path in ignore_paths:

View File

@ -12,15 +12,14 @@
import sys import sys
import pytest import pytest
from util import rootdir
def setup_module(): @pytest.fixture(scope='module', autouse=True)
sys.path.insert(0, rootdir / 'roots' / 'test-api-set-translator') def setup_module(rootdir):
p = rootdir / 'test-api-set-translator'
sys.path.insert(0, p)
def teardown_module(): yield
sys.path.remove(rootdir / 'roots' / 'test-api-set-translator') sys.path.remove(p)
@pytest.mark.sphinx('html') @pytest.mark.sphinx('html')

View File

@ -17,13 +17,13 @@ import pytest
from sphinx.apidoc import main as apidoc_main from sphinx.apidoc import main as apidoc_main
from util import rootdir, remove_unicode_literals from sphinx.testing.util import remove_unicode_literals
@pytest.fixture() @pytest.fixture()
def apidoc(tempdir, apidoc_params): def apidoc(rootdir, tempdir, apidoc_params):
_, kwargs = apidoc_params _, kwargs = apidoc_params
coderoot = kwargs.get('coderoot', (rootdir / 'root')) coderoot = rootdir / kwargs.get('coderoot', 'test-root')
outdir = tempdir / 'out' outdir = tempdir / 'out'
args = ['sphinx-apidoc', '-o', outdir, '-F', coderoot] + kwargs.get('options', []) args = ['sphinx-apidoc', '-o', outdir, '-F', coderoot] + kwargs.get('options', [])
apidoc_main(args) apidoc_main(args)
@ -46,7 +46,7 @@ def apidoc_params(request):
return args, kwargs return args, kwargs
@pytest.mark.apidoc(coderoot=(rootdir / 'root')) @pytest.mark.apidoc(coderoot='test-root')
def test_simple(make_app, apidoc): def test_simple(make_app, apidoc):
outdir = apidoc.outdir outdir = apidoc.outdir
assert (outdir / 'conf.py').isfile() assert (outdir / 'conf.py').isfile()
@ -60,7 +60,7 @@ def test_simple(make_app, apidoc):
@pytest.mark.apidoc( @pytest.mark.apidoc(
coderoot=(rootdir / 'roots' / 'test-apidoc-pep420'), coderoot='test-apidoc-pep420',
options=["--implicit-namespaces"], options=["--implicit-namespaces"],
) )
def test_pep_0420_enabled(make_app, apidoc): def test_pep_0420_enabled(make_app, apidoc):
@ -97,7 +97,7 @@ def test_pep_0420_enabled(make_app, apidoc):
assert "a.b.x namespace\n" in txt assert "a.b.x namespace\n" in txt
@pytest.mark.apidoc(coderoot=(rootdir / 'roots' / 'test-apidoc-pep420')) @pytest.mark.apidoc(coderoot='test-apidoc-pep420')
def test_pep_0420_disabled(make_app, apidoc): def test_pep_0420_disabled(make_app, apidoc):
outdir = apidoc.outdir outdir = apidoc.outdir
assert (outdir / 'conf.py').isfile() assert (outdir / 'conf.py').isfile()
@ -111,7 +111,7 @@ def test_pep_0420_disabled(make_app, apidoc):
@pytest.mark.apidoc( @pytest.mark.apidoc(
coderoot=(rootdir / 'roots' / 'test-apidoc-pep420' / 'a' / 'b')) coderoot='test-apidoc-pep420/a/b')
def test_pep_0420_disabled_top_level_verify(make_app, apidoc): def test_pep_0420_disabled_top_level_verify(make_app, apidoc):
outdir = apidoc.outdir outdir = apidoc.outdir
assert (outdir / 'conf.py').isfile() assert (outdir / 'conf.py').isfile()
@ -131,7 +131,7 @@ def test_pep_0420_disabled_top_level_verify(make_app, apidoc):
@pytest.mark.apidoc( @pytest.mark.apidoc(
coderoot=(rootdir / 'roots' / 'test-apidoc-trailing-underscore')) coderoot='test-apidoc-trailing-underscore')
def test_trailing_underscore(make_app, apidoc): def test_trailing_underscore(make_app, apidoc):
outdir = apidoc.outdir outdir = apidoc.outdir
assert (outdir / 'conf.py').isfile() assert (outdir / 'conf.py').isfile()
@ -150,7 +150,7 @@ def test_trailing_underscore(make_app, apidoc):
@pytest.mark.apidoc( @pytest.mark.apidoc(
coderoot=(rootdir / 'root'), coderoot='test-root',
options=[ options=[
'--doc-project', u'プロジェクト名'.encode('utf-8'), '--doc-project', u'プロジェクト名'.encode('utf-8'),
'--doc-author', u'著者名'.encode('utf-8'), '--doc-author', u'著者名'.encode('utf-8'),
@ -178,7 +178,7 @@ def test_multibyte_parameters(make_app, apidoc):
@pytest.mark.apidoc( @pytest.mark.apidoc(
coderoot=(rootdir / 'root'), coderoot='test-root',
options=['--ext-mathjax'], options=['--ext-mathjax'],
) )
def test_extension_parsed(make_app, apidoc): def test_extension_parsed(make_app, apidoc):

View File

@ -13,7 +13,7 @@ from docutils import nodes
from sphinx.application import ExtensionError from sphinx.application import ExtensionError
from sphinx.domains import Domain from sphinx.domains import Domain
from util import strip_escseq from sphinx.testing.util import strip_escseq
import pytest import pytest

View File

@ -12,7 +12,7 @@
from six import PY3 from six import PY3
from util import SphinxTestApp, Struct # NOQA from sphinx.testing.util import SphinxTestApp, Struct # NOQA
import pytest import pytest
import enum import enum
@ -25,17 +25,19 @@ from sphinx.ext.autodoc import AutoDirective, add_documenter, \
app = None app = None
def setup_module(): @pytest.fixture(scope='module', autouse=True)
def setup_module(rootdir, sphinx_test_tempdir):
global app global app
app = SphinxTestApp() srcdir = sphinx_test_tempdir / 'autodoc-root'
if not srcdir.exists():
(rootdir/'test-root').copytree(srcdir)
app = SphinxTestApp(srcdir=srcdir)
app.builder.env.app = app app.builder.env.app = app
app.builder.env.temp_data['docname'] = 'dummy' app.builder.env.temp_data['docname'] = 'dummy'
app.connect('autodoc-process-docstring', process_docstring) app.connect('autodoc-process-docstring', process_docstring)
app.connect('autodoc-process-signature', process_signature) app.connect('autodoc-process-signature', process_signature)
app.connect('autodoc-skip-member', skip_member) app.connect('autodoc-skip-member', skip_member)
yield
def teardown_module():
app.cleanup() app.cleanup()

View File

@ -16,7 +16,7 @@ import pytest
from textwrap import dedent from textwrap import dedent
from sphinx.errors import SphinxError from sphinx.errors import SphinxError
from util import rootdir, tempdir, path from sphinx.testing.path import path
def request_session_head(url, **kwargs): def request_session_head(url, **kwargs):
@ -27,14 +27,14 @@ def request_session_head(url, **kwargs):
@pytest.fixture @pytest.fixture
def nonascii_srcdir(request): def nonascii_srcdir(request, rootdir, sphinx_test_tempdir):
# If supported, build in a non-ASCII source dir # If supported, build in a non-ASCII source dir
test_name = u'\u65e5\u672c\u8a9e' test_name = u'\u65e5\u672c\u8a9e'
basedir = tempdir / request.node.originalname basedir = sphinx_test_tempdir / request.node.originalname
try: try:
srcdir = basedir / test_name srcdir = basedir / test_name
if not srcdir.exists(): if not srcdir.exists():
(rootdir / 'root').copytree(srcdir) (rootdir / 'test-root').copytree(srcdir)
except UnicodeEncodeError: except UnicodeEncodeError:
srcdir = basedir / 'all' srcdir = basedir / 'all'
else: else:

View File

@ -14,7 +14,7 @@
import plistlib import plistlib
import pytest import pytest
from path import path from sphinx.testing.path import path
# Use plistlib.load in 3.4 and above # Use plistlib.load in 3.4 and above
try: try:

View File

@ -17,7 +17,7 @@ from six import PY3
from sphinx import __display_version__ from sphinx import __display_version__
from sphinx.util.inventory import InventoryFile from sphinx.util.inventory import InventoryFile
from util import remove_unicode_literals, strip_escseq from sphinx.testing.util import remove_unicode_literals, strip_escseq
import xml.etree.cElementTree as ElementTree import xml.etree.cElementTree as ElementTree
from html5lib import getTreeBuilder, HTMLParser from html5lib import getTreeBuilder, HTMLParser
import pytest import pytest

View File

@ -21,7 +21,7 @@ from html5lib import getTreeBuilder, HTMLParser
from sphinx.util.docutils import is_html5_writer_available from sphinx.util.docutils import is_html5_writer_available
from util import skip_unless from sphinx.testing.util import skip_unless
from test_build_html import flat_dict, tail_check, check_xpath from test_build_html import flat_dict, tail_check, check_xpath
TREE_BUILDER = getTreeBuilder('etree', implementation=ElementTree) TREE_BUILDER = getTreeBuilder('etree', implementation=ElementTree)

View File

@ -24,7 +24,7 @@ from sphinx.util.osutil import cd, ensuredir
from sphinx.util import docutils from sphinx.util import docutils
from sphinx.writers.latex import LaTeXTranslator from sphinx.writers.latex import LaTeXTranslator
from util import SkipTest, remove_unicode_literals, strip_escseq, skip_if from sphinx.testing.util import SkipTest, remove_unicode_literals, strip_escseq, skip_if
from test_build_html import ENV_WARNINGS from test_build_html import ENV_WARNINGS

View File

@ -19,7 +19,7 @@ import pytest
from sphinx.writers.texinfo import TexinfoTranslator from sphinx.writers.texinfo import TexinfoTranslator
from util import SkipTest, remove_unicode_literals, strip_escseq from sphinx.testing.util import SkipTest, remove_unicode_literals, strip_escseq
from test_build_html import ENV_WARNINGS from test_build_html import ENV_WARNINGS

View File

@ -12,7 +12,7 @@
from docutils.utils import column_width from docutils.utils import column_width
from sphinx.writers.text import MAXWIDTH from sphinx.writers.text import MAXWIDTH
from util import with_app from sphinx.testing.util import with_app
def with_text_app(*args, **kw): def with_text_app(*args, **kw):

View File

@ -12,37 +12,36 @@ import shutil
import pytest import pytest
from util import find_files, rootdir, tempdir from sphinx.testing.util import find_files
root = tempdir / 'test-intl'
build_dir = root / '_build'
locale_dir = build_dir / 'locale'
@pytest.fixture @pytest.fixture
def setup_test(): def setup_test(app_params):
# delete remnants left over after failed build srcdir = app_params.kwargs['srcdir']
root.rmtree(True) locale_dir = srcdir / 'locale'
(rootdir / 'roots' / 'test-intl').copytree(root)
# copy all catalogs into locale layout directory # copy all catalogs into locale layout directory
for po in find_files(root, '.po'): for po in find_files(srcdir, '.po'):
copy_po = (locale_dir / 'en' / 'LC_MESSAGES' / po) copy_po = (locale_dir / 'en' / 'LC_MESSAGES' / po)
if not copy_po.parent.exists(): if not copy_po.parent.exists():
copy_po.parent.makedirs() copy_po.parent.makedirs()
shutil.copy(root / po, copy_po) shutil.copy(srcdir / po, copy_po)
yield yield
build_dir.rmtree(True) # delete remnants left over after failed build
locale_dir.rmtree(True)
(srcdir / '_build').rmtree(True)
@pytest.mark.usefixtures('setup_test') @pytest.mark.usefixtures('setup_test')
@pytest.mark.test_params(shared_result='test-catalogs')
@pytest.mark.sphinx( @pytest.mark.sphinx(
'html', testroot='intl', 'html', testroot='intl',
confoverrides={'language': 'en', 'locale_dirs': [locale_dir]}) confoverrides={'language': 'en', 'locale_dirs': ['./locale']})
def test_compile_all_catalogs(app, status, warning): def test_compile_all_catalogs(app, status, warning):
app.builder.compile_all_catalogs() app.builder.compile_all_catalogs()
locale_dir = app.srcdir / 'locale'
catalog_dir = locale_dir / app.config.language / 'LC_MESSAGES' catalog_dir = locale_dir / app.config.language / 'LC_MESSAGES'
expect = set([ expect = set([
x.replace('.po', '.mo') x.replace('.po', '.mo')
@ -54,10 +53,12 @@ def test_compile_all_catalogs(app, status, warning):
@pytest.mark.usefixtures('setup_test') @pytest.mark.usefixtures('setup_test')
@pytest.mark.test_params(shared_result='test-catalogs')
@pytest.mark.sphinx( @pytest.mark.sphinx(
'html', testroot='intl', 'html', testroot='intl',
confoverrides={'language': 'en', 'locale_dirs': [locale_dir]}) confoverrides={'language': 'en', 'locale_dirs': ['./locale']})
def test_compile_specific_catalogs(app, status, warning): def test_compile_specific_catalogs(app, status, warning):
locale_dir = app.srcdir / 'locale'
catalog_dir = locale_dir / app.config.language / 'LC_MESSAGES' catalog_dir = locale_dir / app.config.language / 'LC_MESSAGES'
def get_actual(): def get_actual():
@ -70,12 +71,14 @@ def test_compile_specific_catalogs(app, status, warning):
@pytest.mark.usefixtures('setup_test') @pytest.mark.usefixtures('setup_test')
@pytest.mark.test_params(shared_result='test-catalogs')
@pytest.mark.sphinx( @pytest.mark.sphinx(
'html', testroot='intl', 'html', testroot='intl',
confoverrides={'language': 'en', 'locale_dirs': [locale_dir]}) confoverrides={'language': 'en', 'locale_dirs': ['./locale']})
def test_compile_update_catalogs(app, status, warning): def test_compile_update_catalogs(app, status, warning):
app.builder.compile_update_catalogs() app.builder.compile_update_catalogs()
locale_dir = app.srcdir / 'locale'
catalog_dir = locale_dir / app.config.language / 'LC_MESSAGES' catalog_dir = locale_dir / app.config.language / 'LC_MESSAGES'
expect = set([ expect = set([
x.replace('.po', '.mo') x.replace('.po', '.mo')

View File

@ -16,6 +16,7 @@ import mock
import sphinx import sphinx
from sphinx.config import Config from sphinx.config import Config
from sphinx.errors import ExtensionError, ConfigError, VersionRequirementError from sphinx.errors import ExtensionError, ConfigError, VersionRequirementError
from sphinx.testing.path import path
@pytest.mark.sphinx(confoverrides={ @pytest.mark.sphinx(confoverrides={
@ -129,8 +130,19 @@ def test_errors_if_setup_is_not_callable(tempdir, make_app):
assert 'callable' in str(excinfo.value) assert 'callable' in str(excinfo.value)
@pytest.fixture
def make_app_with_empty_project(make_app, tempdir):
(tempdir / 'conf.py').write_text('')
def _make_app(*args, **kw):
kw.setdefault('srcdir', path(tempdir))
return make_app(*args, **kw)
return _make_app
@mock.patch.object(sphinx, '__display_version__', '1.3.4') @mock.patch.object(sphinx, '__display_version__', '1.3.4')
def test_needs_sphinx(make_app): def test_needs_sphinx(make_app_with_empty_project):
make_app = make_app_with_empty_project
# micro version # micro version
app = make_app(confoverrides={'needs_sphinx': '1.3.3'}) # OK: less app = make_app(confoverrides={'needs_sphinx': '1.3.3'}) # OK: less
app.cleanup() app.cleanup()

View File

@ -13,43 +13,52 @@ import pytest
from sphinx.config import Config from sphinx.config import Config
from sphinx.directives.code import LiteralIncludeReader from sphinx.directives.code import LiteralIncludeReader
from util import etree_parse, rootdir from sphinx.testing.util import etree_parse
TESTROOT_PATH = rootdir / 'roots' / 'test-directive-code'
LITERAL_INC_PATH = TESTROOT_PATH / 'literal.inc'
DUMMY_CONFIG = Config(None, None, {}, '') DUMMY_CONFIG = Config(None, None, {}, '')
def test_LiteralIncludeReader(): @pytest.fixture(scope='module')
def testroot(rootdir):
testroot_path = rootdir / 'test-directive-code'
return testroot_path
@pytest.fixture(scope='module')
def literal_inc_path(testroot):
return testroot / 'literal.inc'
def test_LiteralIncludeReader(literal_inc_path):
options = {'lineno-match': True} options = {'lineno-match': True}
reader = LiteralIncludeReader(LITERAL_INC_PATH, options, DUMMY_CONFIG) reader = LiteralIncludeReader(literal_inc_path, options, DUMMY_CONFIG)
content, lines = reader.read() content, lines = reader.read()
assert content == LITERAL_INC_PATH.text() assert content == literal_inc_path.text()
assert lines == 14 assert lines == 14
assert reader.lineno_start == 1 assert reader.lineno_start == 1
def test_LiteralIncludeReader_lineno_start(): def test_LiteralIncludeReader_lineno_start(literal_inc_path):
options = {'lineno-start': 5} options = {'lineno-start': 5}
reader = LiteralIncludeReader(LITERAL_INC_PATH, options, DUMMY_CONFIG) reader = LiteralIncludeReader(literal_inc_path, options, DUMMY_CONFIG)
content, lines = reader.read() content, lines = reader.read()
assert content == LITERAL_INC_PATH.text() assert content == literal_inc_path.text()
assert lines == 14 assert lines == 14
assert reader.lineno_start == 5 assert reader.lineno_start == 5
def test_LiteralIncludeReader_pyobject1(): def test_LiteralIncludeReader_pyobject1(literal_inc_path):
options = {'lineno-match': True, 'pyobject': 'Foo'} options = {'lineno-match': True, 'pyobject': 'Foo'}
reader = LiteralIncludeReader(LITERAL_INC_PATH, options, DUMMY_CONFIG) reader = LiteralIncludeReader(literal_inc_path, options, DUMMY_CONFIG)
content, lines = reader.read() content, lines = reader.read()
assert content == ("class Foo:\n" assert content == ("class Foo:\n"
" pass\n") " pass\n")
assert reader.lineno_start == 6 assert reader.lineno_start == 6
def test_LiteralIncludeReader_pyobject2(): def test_LiteralIncludeReader_pyobject2(literal_inc_path):
options = {'pyobject': 'Bar'} options = {'pyobject': 'Bar'}
reader = LiteralIncludeReader(LITERAL_INC_PATH, options, DUMMY_CONFIG) reader = LiteralIncludeReader(literal_inc_path, options, DUMMY_CONFIG)
content, lines = reader.read() content, lines = reader.read()
assert content == ("class Bar:\n" assert content == ("class Bar:\n"
" def baz():\n" " def baz():\n"
@ -57,25 +66,25 @@ def test_LiteralIncludeReader_pyobject2():
assert reader.lineno_start == 1 # no lineno-match assert reader.lineno_start == 1 # no lineno-match
def test_LiteralIncludeReader_pyobject3(): def test_LiteralIncludeReader_pyobject3(literal_inc_path):
options = {'pyobject': 'Bar.baz'} options = {'pyobject': 'Bar.baz'}
reader = LiteralIncludeReader(LITERAL_INC_PATH, options, DUMMY_CONFIG) reader = LiteralIncludeReader(literal_inc_path, options, DUMMY_CONFIG)
content, lines = reader.read() content, lines = reader.read()
assert content == (" def baz():\n" assert content == (" def baz():\n"
" pass\n") " pass\n")
def test_LiteralIncludeReader_pyobject_and_lines(): def test_LiteralIncludeReader_pyobject_and_lines(literal_inc_path):
options = {'pyobject': 'Bar', 'lines': '2-'} options = {'pyobject': 'Bar', 'lines': '2-'}
reader = LiteralIncludeReader(LITERAL_INC_PATH, options, DUMMY_CONFIG) reader = LiteralIncludeReader(literal_inc_path, options, DUMMY_CONFIG)
content, lines = reader.read() content, lines = reader.read()
assert content == (" def baz():\n" assert content == (" def baz():\n"
" pass\n") " pass\n")
def test_LiteralIncludeReader_lines1(): def test_LiteralIncludeReader_lines1(literal_inc_path):
options = {'lines': '1-4'} options = {'lines': '1-4'}
reader = LiteralIncludeReader(LITERAL_INC_PATH, options, DUMMY_CONFIG) reader = LiteralIncludeReader(literal_inc_path, options, DUMMY_CONFIG)
content, lines = reader.read() content, lines = reader.read()
assert content == (u"# Literally included file using Python highlighting\n" assert content == (u"# Literally included file using Python highlighting\n"
u"# -*- coding: utf-8 -*-\n" u"# -*- coding: utf-8 -*-\n"
@ -83,18 +92,18 @@ def test_LiteralIncludeReader_lines1():
u"foo = \"Including Unicode characters: üöä\"\n") u"foo = \"Including Unicode characters: üöä\"\n")
def test_LiteralIncludeReader_lines2(): def test_LiteralIncludeReader_lines2(literal_inc_path):
options = {'lines': '1,4,6'} options = {'lines': '1,4,6'}
reader = LiteralIncludeReader(LITERAL_INC_PATH, options, DUMMY_CONFIG) reader = LiteralIncludeReader(literal_inc_path, options, DUMMY_CONFIG)
content, lines = reader.read() content, lines = reader.read()
assert content == (u"# Literally included file using Python highlighting\n" assert content == (u"# Literally included file using Python highlighting\n"
u"foo = \"Including Unicode characters: üöä\"\n" u"foo = \"Including Unicode characters: üöä\"\n"
u"class Foo:\n") u"class Foo:\n")
def test_LiteralIncludeReader_lines_and_lineno_match1(): def test_LiteralIncludeReader_lines_and_lineno_match1(literal_inc_path):
options = {'lines': '4-6', 'lineno-match': True} options = {'lines': '4-6', 'lineno-match': True}
reader = LiteralIncludeReader(LITERAL_INC_PATH, options, DUMMY_CONFIG) reader = LiteralIncludeReader(literal_inc_path, options, DUMMY_CONFIG)
content, lines = reader.read() content, lines = reader.read()
assert content == (u"foo = \"Including Unicode characters: üöä\"\n" assert content == (u"foo = \"Including Unicode characters: üöä\"\n"
u"\n" u"\n"
@ -103,24 +112,24 @@ def test_LiteralIncludeReader_lines_and_lineno_match1():
@pytest.mark.sphinx() # init locale for errors @pytest.mark.sphinx() # init locale for errors
def test_LiteralIncludeReader_lines_and_lineno_match2(app, status, warning): def test_LiteralIncludeReader_lines_and_lineno_match2(literal_inc_path, app, status, warning):
options = {'lines': '1,4,6', 'lineno-match': True} options = {'lines': '1,4,6', 'lineno-match': True}
reader = LiteralIncludeReader(LITERAL_INC_PATH, options, DUMMY_CONFIG) reader = LiteralIncludeReader(literal_inc_path, options, DUMMY_CONFIG)
with pytest.raises(ValueError): with pytest.raises(ValueError):
content, lines = reader.read() content, lines = reader.read()
@pytest.mark.sphinx() # init locale for errors @pytest.mark.sphinx() # init locale for errors
def test_LiteralIncludeReader_lines_and_lineno_match3(app, status, warning): def test_LiteralIncludeReader_lines_and_lineno_match3(literal_inc_path, app, status, warning):
options = {'lines': '100-', 'lineno-match': True} options = {'lines': '100-', 'lineno-match': True}
reader = LiteralIncludeReader(LITERAL_INC_PATH, options, DUMMY_CONFIG) reader = LiteralIncludeReader(literal_inc_path, options, DUMMY_CONFIG)
with pytest.raises(ValueError): with pytest.raises(ValueError):
content, lines = reader.read() content, lines = reader.read()
def test_LiteralIncludeReader_start_at(): def test_LiteralIncludeReader_start_at(literal_inc_path):
options = {'lineno-match': True, 'start-at': 'Foo', 'end-at': 'Bar'} options = {'lineno-match': True, 'start-at': 'Foo', 'end-at': 'Bar'}
reader = LiteralIncludeReader(LITERAL_INC_PATH, options, DUMMY_CONFIG) reader = LiteralIncludeReader(literal_inc_path, options, DUMMY_CONFIG)
content, lines = reader.read() content, lines = reader.read()
assert content == ("class Foo:\n" assert content == ("class Foo:\n"
" pass\n" " pass\n"
@ -129,19 +138,19 @@ def test_LiteralIncludeReader_start_at():
assert reader.lineno_start == 6 assert reader.lineno_start == 6
def test_LiteralIncludeReader_start_after(): def test_LiteralIncludeReader_start_after(literal_inc_path):
options = {'lineno-match': True, 'start-after': 'Foo', 'end-before': 'Bar'} options = {'lineno-match': True, 'start-after': 'Foo', 'end-before': 'Bar'}
reader = LiteralIncludeReader(LITERAL_INC_PATH, options, DUMMY_CONFIG) reader = LiteralIncludeReader(literal_inc_path, options, DUMMY_CONFIG)
content, lines = reader.read() content, lines = reader.read()
assert content == (" pass\n" assert content == (" pass\n"
"\n") "\n")
assert reader.lineno_start == 7 assert reader.lineno_start == 7
def test_LiteralIncludeReader_start_after_and_lines(): def test_LiteralIncludeReader_start_after_and_lines(literal_inc_path):
options = {'lineno-match': True, 'lines': '6-', options = {'lineno-match': True, 'lines': '6-',
'start-after': 'coding', 'end-before': 'comment'} 'start-after': 'coding', 'end-before': 'comment'}
reader = LiteralIncludeReader(LITERAL_INC_PATH, options, DUMMY_CONFIG) reader = LiteralIncludeReader(literal_inc_path, options, DUMMY_CONFIG)
content, lines = reader.read() content, lines = reader.read()
assert content == ("\n" assert content == ("\n"
"class Bar:\n" "class Bar:\n"
@ -151,9 +160,9 @@ def test_LiteralIncludeReader_start_after_and_lines():
assert reader.lineno_start == 8 assert reader.lineno_start == 8
def test_LiteralIncludeReader_start_at_and_lines(): def test_LiteralIncludeReader_start_at_and_lines(literal_inc_path):
options = {'lines': '2, 3, 5', 'start-at': 'foo', 'end-before': '#'} options = {'lines': '2, 3, 5', 'start-at': 'foo', 'end-before': '#'}
reader = LiteralIncludeReader(LITERAL_INC_PATH, options, DUMMY_CONFIG) reader = LiteralIncludeReader(literal_inc_path, options, DUMMY_CONFIG)
content, lines = reader.read() content, lines = reader.read()
assert content == ("\n" assert content == ("\n"
"class Foo:\n" "class Foo:\n"
@ -161,41 +170,41 @@ def test_LiteralIncludeReader_start_at_and_lines():
assert reader.lineno_start == 1 assert reader.lineno_start == 1
def test_LiteralIncludeReader_missing_start_and_end(): def test_LiteralIncludeReader_missing_start_and_end(literal_inc_path):
options = {'start-at': 'NOTHING'} options = {'start-at': 'NOTHING'}
reader = LiteralIncludeReader(LITERAL_INC_PATH, options, DUMMY_CONFIG) reader = LiteralIncludeReader(literal_inc_path, options, DUMMY_CONFIG)
with pytest.raises(ValueError): with pytest.raises(ValueError):
content, lines = reader.read() content, lines = reader.read()
options = {'end-at': 'NOTHING'} options = {'end-at': 'NOTHING'}
reader = LiteralIncludeReader(LITERAL_INC_PATH, options, DUMMY_CONFIG) reader = LiteralIncludeReader(literal_inc_path, options, DUMMY_CONFIG)
with pytest.raises(ValueError): with pytest.raises(ValueError):
content, lines = reader.read() content, lines = reader.read()
options = {'start-after': 'NOTHING'} options = {'start-after': 'NOTHING'}
reader = LiteralIncludeReader(LITERAL_INC_PATH, options, DUMMY_CONFIG) reader = LiteralIncludeReader(literal_inc_path, options, DUMMY_CONFIG)
with pytest.raises(ValueError): with pytest.raises(ValueError):
content, lines = reader.read() content, lines = reader.read()
options = {'end-before': 'NOTHING'} options = {'end-before': 'NOTHING'}
reader = LiteralIncludeReader(LITERAL_INC_PATH, options, DUMMY_CONFIG) reader = LiteralIncludeReader(literal_inc_path, options, DUMMY_CONFIG)
with pytest.raises(ValueError): with pytest.raises(ValueError):
content, lines = reader.read() content, lines = reader.read()
def test_LiteralIncludeReader_prepend(): def test_LiteralIncludeReader_prepend(literal_inc_path):
options = {'lines': '1', 'prepend': 'Hello', 'append': 'Sphinx'} options = {'lines': '1', 'prepend': 'Hello', 'append': 'Sphinx'}
reader = LiteralIncludeReader(LITERAL_INC_PATH, options, DUMMY_CONFIG) reader = LiteralIncludeReader(literal_inc_path, options, DUMMY_CONFIG)
content, lines = reader.read() content, lines = reader.read()
assert content == ("Hello\n" assert content == ("Hello\n"
"# Literally included file using Python highlighting\n" "# Literally included file using Python highlighting\n"
"Sphinx\n") "Sphinx\n")
def test_LiteralIncludeReader_dedent(): def test_LiteralIncludeReader_dedent(literal_inc_path):
# dedent: 2 # dedent: 2
options = {'lines': '10-12', 'dedent': 2} options = {'lines': '10-12', 'dedent': 2}
reader = LiteralIncludeReader(LITERAL_INC_PATH, options, DUMMY_CONFIG) reader = LiteralIncludeReader(literal_inc_path, options, DUMMY_CONFIG)
content, lines = reader.read() content, lines = reader.read()
assert content == (" def baz():\n" assert content == (" def baz():\n"
" pass\n" " pass\n"
@ -203,7 +212,7 @@ def test_LiteralIncludeReader_dedent():
# dedent: 4 # dedent: 4
options = {'lines': '10-12', 'dedent': 4} options = {'lines': '10-12', 'dedent': 4}
reader = LiteralIncludeReader(LITERAL_INC_PATH, options, DUMMY_CONFIG) reader = LiteralIncludeReader(literal_inc_path, options, DUMMY_CONFIG)
content, lines = reader.read() content, lines = reader.read()
assert content == ("def baz():\n" assert content == ("def baz():\n"
" pass\n" " pass\n"
@ -211,17 +220,17 @@ def test_LiteralIncludeReader_dedent():
# dedent: 6 # dedent: 6
options = {'lines': '10-12', 'dedent': 6} options = {'lines': '10-12', 'dedent': 6}
reader = LiteralIncludeReader(LITERAL_INC_PATH, options, DUMMY_CONFIG) reader = LiteralIncludeReader(literal_inc_path, options, DUMMY_CONFIG)
content, lines = reader.read() content, lines = reader.read()
assert content == ("f baz():\n" assert content == ("f baz():\n"
" pass\n" " pass\n"
"\n") "\n")
def test_LiteralIncludeReader_tabwidth(): def test_LiteralIncludeReader_tabwidth(testroot):
# tab-width: 4 # tab-width: 4
options = {'tab-width': 4, 'pyobject': 'Qux'} options = {'tab-width': 4, 'pyobject': 'Qux'}
reader = LiteralIncludeReader(TESTROOT_PATH / 'target.py', options, DUMMY_CONFIG) reader = LiteralIncludeReader(testroot / 'target.py', options, DUMMY_CONFIG)
content, lines = reader.read() content, lines = reader.read()
assert content == ("class Qux:\n" assert content == ("class Qux:\n"
" def quux(self):\n" " def quux(self):\n"
@ -229,27 +238,27 @@ def test_LiteralIncludeReader_tabwidth():
# tab-width: 8 # tab-width: 8
options = {'tab-width': 8, 'pyobject': 'Qux'} options = {'tab-width': 8, 'pyobject': 'Qux'}
reader = LiteralIncludeReader(TESTROOT_PATH / 'target.py', options, DUMMY_CONFIG) reader = LiteralIncludeReader(testroot / 'target.py', options, DUMMY_CONFIG)
content, lines = reader.read() content, lines = reader.read()
assert content == ("class Qux:\n" assert content == ("class Qux:\n"
" def quux(self):\n" " def quux(self):\n"
" pass\n") " pass\n")
def test_LiteralIncludeReader_tabwidth_dedent(): def test_LiteralIncludeReader_tabwidth_dedent(testroot):
options = {'tab-width': 4, 'dedent': 4, 'pyobject': 'Qux.quux'} options = {'tab-width': 4, 'dedent': 4, 'pyobject': 'Qux.quux'}
reader = LiteralIncludeReader(TESTROOT_PATH / 'target.py', options, DUMMY_CONFIG) reader = LiteralIncludeReader(testroot / 'target.py', options, DUMMY_CONFIG)
content, lines = reader.read() content, lines = reader.read()
assert content == ("def quux(self):\n" assert content == ("def quux(self):\n"
" pass\n") " pass\n")
def test_LiteralIncludeReader_diff(): def test_LiteralIncludeReader_diff(testroot, literal_inc_path):
options = {'diff': TESTROOT_PATH / 'literal-diff.inc'} options = {'diff': testroot / 'literal-diff.inc'}
reader = LiteralIncludeReader(LITERAL_INC_PATH, options, DUMMY_CONFIG) reader = LiteralIncludeReader(literal_inc_path, options, DUMMY_CONFIG)
content, lines = reader.read() content, lines = reader.read()
assert content == ("--- " + TESTROOT_PATH + "/literal-diff.inc\n" assert content == ("--- " + testroot + "/literal-diff.inc\n"
"+++ " + TESTROOT_PATH + "/literal.inc\n" "+++ " + testroot + "/literal.inc\n"
"@@ -7,8 +7,8 @@\n" "@@ -7,8 +7,8 @@\n"
" pass\n" " pass\n"
" \n" " \n"

View File

@ -12,7 +12,8 @@
import re import re
import pytest import pytest
from util import path, SkipTest from sphinx.testing.path import path
from sphinx.testing.util import SkipTest
def regex_count(expr, result): def regex_count(expr, result):
@ -77,7 +78,7 @@ def test_docutils_source_link_with_nonascii_file(app, status, warning):
try: try:
(srcdir / (mb_name + '.txt')).write_text('') (srcdir / (mb_name + '.txt')).write_text('')
except UnicodeEncodeError: except UnicodeEncodeError:
from path import FILESYSTEMENCODING from sphinx.testing.path import FILESYSTEMENCODING
raise SkipTest( raise SkipTest(
'nonascii filename not supported on this filesystem encoding: ' 'nonascii filename not supported on this filesystem encoding: '
'%s', FILESYSTEMENCODING) '%s', FILESYSTEMENCODING)

View File

@ -16,7 +16,7 @@ from docutils import nodes
from sphinx import addnodes from sphinx import addnodes
from sphinx.domains.javascript import JavaScriptDomain from sphinx.domains.javascript import JavaScriptDomain
from util import assert_node from sphinx.testing.util import assert_node
@pytest.mark.sphinx('dummy', testroot='domain-js') @pytest.mark.sphinx('dummy', testroot='domain-js')

View File

@ -17,7 +17,7 @@ from docutils import nodes
from sphinx import addnodes from sphinx import addnodes
from sphinx.domains.python import py_sig_re, _pseudo_parse_arglist, PythonDomain from sphinx.domains.python import py_sig_re, _pseudo_parse_arglist, PythonDomain
from util import assert_node from sphinx.testing.util import assert_node
def parse(sig): def parse(sig):

View File

@ -8,22 +8,24 @@
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
import pytest
from util import SphinxTestApp, path from sphinx.testing.util import SphinxTestApp, path
from sphinx.builders.html import StandaloneHTMLBuilder from sphinx.builders.html import StandaloneHTMLBuilder
from sphinx.builders.latex import LaTeXBuilder from sphinx.builders.latex import LaTeXBuilder
app = env = None app = env = None
def setup_module(): @pytest.fixture(scope='module', autouse=True)
def setup_module(rootdir, sphinx_test_tempdir):
global app, env global app, env
app = SphinxTestApp(srcdir='root-envtest') srcdir = sphinx_test_tempdir / 'root-envtest'
if not srcdir.exists():
(rootdir/'test-root').copytree(srcdir)
app = SphinxTestApp(srcdir=srcdir)
env = app.env env = app.env
yield
def teardown_module():
app.cleanup() app.cleanup()

View File

@ -16,7 +16,7 @@ from sphinx.addnodes import compact_paragraph, only
from sphinx.builders.html import StandaloneHTMLBuilder from sphinx.builders.html import StandaloneHTMLBuilder
import pytest import pytest
from util import assert_node from sphinx.testing.util import assert_node
@pytest.mark.sphinx('xml', testroot='toctree') @pytest.mark.sphinx('xml', testroot='toctree')

View File

@ -13,7 +13,7 @@ from six import iteritems, StringIO
from sphinx.ext.autosummary import mangle_signature from sphinx.ext.autosummary import mangle_signature
from util import etree_parse from sphinx.testing.util import etree_parse
import pytest import pytest

View File

@ -11,7 +11,6 @@
import re import re
import sys import sys
from util import rootdir
from sphinx.ext.inheritance_diagram import InheritanceException, import_classes from sphinx.ext.inheritance_diagram import InheritanceException, import_classes
import pytest import pytest
@ -44,12 +43,12 @@ def test_inheritance_diagram_latex(app, status, warning):
assert re.search(pattern, content, re.M) assert re.search(pattern, content, re.M)
def test_import_classes(): def test_import_classes(rootdir):
from sphinx.application import Sphinx, TemplateBridge from sphinx.application import Sphinx, TemplateBridge
from sphinx.util.i18n import CatalogInfo from sphinx.util.i18n import CatalogInfo
try: try:
sys.path.append(rootdir / 'roots/test-ext-inheritance_diagram') sys.path.append(rootdir / 'test-ext-inheritance_diagram')
from example.sphinx import DummyClass from example.sphinx import DummyClass
# got exception for unknown class or module # got exception for unknown class or module

View File

@ -12,7 +12,7 @@
import re import re
import pytest import pytest
from util import SkipTest from sphinx.testing.util import SkipTest
@pytest.mark.sphinx( @pytest.mark.sphinx(

View File

@ -20,7 +20,7 @@ from babel.messages import pofile, mofile
from six import string_types from six import string_types
import pytest import pytest
from util import ( from sphinx.testing.util import (
path, etree_parse, strip_escseq, path, etree_parse, strip_escseq,
assert_re_search, assert_not_re_search, assert_startswith, assert_node assert_re_search, assert_not_re_search, assert_startswith, assert_node
) )
@ -494,15 +494,15 @@ def test_gettext_buildr_ignores_only_directive(app):
@sphinx_intl @sphinx_intl
# use individual shared_result directory to avoid "incompatible doctree" error
@pytest.mark.test_params(shared_result='test_gettext_dont_rebuild_mo')
def test_gettext_dont_rebuild_mo(make_app, app_params, build_mo): def test_gettext_dont_rebuild_mo(make_app, app_params, build_mo):
# --- don't rebuild by .mo mtime # --- don't rebuild by .mo mtime
def get_number_of_update_targets(app_): def get_number_of_update_targets(app_):
updated = app_.env.update(app_.config, app_.srcdir, app_.doctreedir) updated = app_.env.update(app_.config, app_.srcdir, app_.doctreedir)
return len(updated) return len(updated)
# setup new directory
args, kwargs = app_params args, kwargs = app_params
kwargs['srcdir'] = 'test_gettext_dont_rebuild_mo'
# phase1: build document with non-gettext builder and generate mo file in srcdir # phase1: build document with non-gettext builder and generate mo file in srcdir
app0 = make_app('dummy', *args, **kwargs) app0 = make_app('dummy', *args, **kwargs)

View File

@ -23,7 +23,7 @@ from sphinx.writers.html import HTMLWriter, HTMLTranslator
from sphinx.writers.latex import LaTeXWriter, LaTeXTranslator from sphinx.writers.latex import LaTeXWriter, LaTeXTranslator
import pytest import pytest
from util import assert_node from sphinx.testing.util import assert_node
@pytest.fixture @pytest.fixture

View File

@ -16,7 +16,7 @@ from six import PY2, text_type, StringIO
from six.moves import input from six.moves import input
import pytest import pytest
from util import SkipTest from sphinx.testing.util import SkipTest
from sphinx import application from sphinx import application
from sphinx import quickstart as qs from sphinx import quickstart as qs

View File

@ -18,19 +18,11 @@ import sphinx
import pytest import pytest
from sphinx.util.osutil import cd from sphinx.util.osutil import cd
from util import rootdir, tempdir
from textwrap import dedent from textwrap import dedent
root = tempdir / 'test-setup'
def setup_module():
if not root.exists():
(rootdir / 'roots' / 'test-setup').copytree(root)
@pytest.fixture @pytest.fixture
def setup_command(request, tempdir): def setup_command(request, tempdir, rootdir):
""" """
Run `setup.py build_sphinx` with args and kwargs, Run `setup.py build_sphinx` with args and kwargs,
pass it to the test and clean up properly. pass it to the test and clean up properly.
@ -38,8 +30,8 @@ def setup_command(request, tempdir):
marker = request.node.get_marker('setup_command') marker = request.node.get_marker('setup_command')
args = marker.args if marker else [] args = marker.args if marker else []
pkgrootdir = tempdir / 'root' pkgrootdir = tempdir / 'test-setup'
root.copytree(pkgrootdir) (rootdir / 'test-setup').copytree(pkgrootdir)
with cd(pkgrootdir): with cd(pkgrootdir):
pythonpath = os.path.dirname(os.path.dirname(sphinx.__file__)) pythonpath = os.path.dirname(os.path.dirname(sphinx.__file__))
@ -89,7 +81,7 @@ def nonascii_srcdir(request, setup_command):
try: try:
(srcdir / mb_name).makedirs() (srcdir / mb_name).makedirs()
except UnicodeEncodeError: except UnicodeEncodeError:
from path import FILESYSTEMENCODING from sphinx.testing.path import FILESYSTEMENCODING
pytest.skip( pytest.skip(
'non-ASCII filename not supported on this filesystem encoding: ' 'non-ASCII filename not supported on this filesystem encoding: '
'%s' % FILESYSTEMENCODING) '%s' % FILESYSTEMENCODING)

View File

@ -17,7 +17,7 @@ from sphinx.util import (
display_chunk, encode_uri, parselinenos, split_docinfo, status_iterator display_chunk, encode_uri, parselinenos, split_docinfo, status_iterator
) )
from util import strip_escseq from sphinx.testing.util import strip_escseq
def test_encode_uri(): def test_encode_uri():

View File

@ -16,23 +16,25 @@ from sphinx.util.images import (
get_image_size, guess_mimetype, get_image_extension, parse_data_uri get_image_size, guess_mimetype, get_image_extension, parse_data_uri
) )
from util import rootdir GIF_FILENAME = 'img.gif'
PNG_FILENAME = 'img.png'
PDF_FILENAME = 'img.pdf'
TXT_FILENAME = 'contents.txt'
GIF_FILENAME = rootdir / 'root' / 'img.gif' @pytest.fixture(scope='module')
PNG_FILENAME = rootdir / 'root' / 'img.png' def testroot(rootdir):
PDF_FILENAME = rootdir / 'root' / 'img.pdf' return rootdir / 'test-root'
TXT_FILENAME = rootdir / 'root' / 'contents.txt'
def test_get_image_size(): def test_get_image_size(testroot):
assert get_image_size(GIF_FILENAME) == (200, 181) assert get_image_size(testroot / GIF_FILENAME) == (200, 181)
assert get_image_size(PNG_FILENAME) == (200, 181) assert get_image_size(testroot / PNG_FILENAME) == (200, 181)
assert get_image_size(PDF_FILENAME) is None assert get_image_size(testroot / PDF_FILENAME) is None
assert get_image_size(TXT_FILENAME) is None assert get_image_size(testroot / TXT_FILENAME) is None
def test_guess_mimetype(): def test_guess_mimetype(testroot):
# guess by filename # guess by filename
assert guess_mimetype('img.png') == 'image/png' assert guess_mimetype('img.png') == 'image/png'
assert guess_mimetype('img.jpg') == 'image/jpeg' assert guess_mimetype('img.jpg') == 'image/jpeg'
@ -42,21 +44,22 @@ def test_guess_mimetype():
assert guess_mimetype('IMG.PNG') == 'image/png' assert guess_mimetype('IMG.PNG') == 'image/png'
# guess by content # guess by content
assert guess_mimetype(content=GIF_FILENAME.bytes()) == 'image/gif' assert guess_mimetype(content=(testroot/GIF_FILENAME).bytes()) == 'image/gif'
assert guess_mimetype(content=PNG_FILENAME.bytes()) == 'image/png' assert guess_mimetype(content=(testroot/PNG_FILENAME).bytes()) == 'image/png'
assert guess_mimetype(content=PDF_FILENAME.bytes()) is None assert guess_mimetype(content=(testroot/PDF_FILENAME).bytes()) is None
assert guess_mimetype(content=TXT_FILENAME.bytes()) is None assert guess_mimetype(content=(testroot/TXT_FILENAME).bytes()) is None
assert guess_mimetype(content=TXT_FILENAME.bytes(), default='text/plain') == 'text/plain' assert guess_mimetype(content=(testroot/TXT_FILENAME).bytes(),
default='text/plain') == 'text/plain'
# the priority of params: filename > content > default # the priority of params: filename > content > default
assert guess_mimetype('img.png', assert guess_mimetype('img.png',
content=GIF_FILENAME.bytes(), content=(testroot/GIF_FILENAME).bytes(),
default='text/plain') == 'image/png' default='text/plain') == 'image/png'
assert guess_mimetype('no_extension', assert guess_mimetype('no_extension',
content=GIF_FILENAME.bytes(), content=(testroot/GIF_FILENAME).bytes(),
default='text/plain') == 'image/gif' default='text/plain') == 'image/gif'
assert guess_mimetype('no_extension', assert guess_mimetype('no_extension',
content=TXT_FILENAME.bytes(), content=(testroot/TXT_FILENAME).bytes(),
default='text/plain') == 'text/plain' default='text/plain') == 'text/plain'

View File

@ -20,7 +20,7 @@ from sphinx.util.logging import is_suppressed_warning
from sphinx.util.parallel import ParallelTasks from sphinx.util.parallel import ParallelTasks
import pytest import pytest
from util import strip_escseq from sphinx.testing.util import strip_escseq
def test_info_and_warning(app, status, warning): def test_info_and_warning(app, status, warning):

View File

@ -11,28 +11,31 @@
import pickle import pickle
import pytest
from docutils.parsers.rst.directives.html import MetaBody from docutils.parsers.rst.directives.html import MetaBody
from sphinx import addnodes from sphinx import addnodes
from sphinx.versioning import add_uids, merge_doctrees, get_ratio from sphinx.versioning import add_uids, merge_doctrees, get_ratio
from util import SphinxTestApp from sphinx.testing.util import SphinxTestApp
app = original = original_uids = None app = original = original_uids = None
def setup_module(): @pytest.fixture(scope='module', autouse=True)
def setup_module(rootdir, sphinx_test_tempdir):
global app, original, original_uids global app, original, original_uids
app = SphinxTestApp(testroot='versioning') srcdir = sphinx_test_tempdir / 'test-versioning'
if not srcdir.exists():
(rootdir/'test-versioning').copytree(srcdir)
app = SphinxTestApp(srcdir=srcdir)
app.builder.env.app = app app.builder.env.app = app
app.connect('doctree-resolved', on_doctree_resolved) app.connect('doctree-resolved', on_doctree_resolved)
app.build() app.build()
original = doctrees['original'] original = doctrees['original']
original_uids = [n.uid for n in add_uids(original, is_paragraph)] original_uids = [n.uid for n in add_uids(original, is_paragraph)]
yield
def teardown_module():
app.cleanup() app.cleanup()

View File

@ -16,17 +16,16 @@ except ImportError:
sqlalchemy_missing = True sqlalchemy_missing = True
import pytest import pytest
from util import rootdir, tempdir
@pytest.mark.skipif(sqlalchemy_missing, reason='needs sqlalchemy') @pytest.mark.skipif(sqlalchemy_missing, reason='needs sqlalchemy')
def test_build(request): def test_build(request, rootdir, sphinx_test_tempdir):
settings = { settings = {
'srcdir': rootdir / 'roots' / 'test-basic', 'srcdir': rootdir / 'test-basic',
# to use same directory for 'builddir' in each 'support' fixture, using # to use same directory for 'builddir' in each 'support' fixture, using
# 'tempdir' (static) value instead of 'tempdir' fixture value. # 'sphinx_test_tempdir' (static) value instead of 'tempdir' fixture value.
# each test expect result of db value at previous test case. # each test expect result of db value at previous test case.
'builddir': tempdir / 'websupport' 'builddir': sphinx_test_tempdir / 'websupport'
} }
marker = request.node.get_marker('support') marker = request.node.get_marker('support')
if marker: if marker: