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
97 changed files with 535 additions and 452 deletions

View File

@@ -1,230 +1,20 @@
# -*- coding: utf-8 -*-
from __future__ import print_function
"""
pytest config for sphinx/tests
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
import sys
import subprocess
from collections import namedtuple
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
import os
import pytest
from six import StringIO, string_types
from sphinx.testing.path import path
import util
pytest_plugins = 'sphinx.testing.fixtures'
@pytest.fixture
def app_params(request, test_params, shared_result):
"""
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)
@pytest.fixture(scope='session')
def rootdir():
return path(os.path.dirname(__file__) or '.').abspath() / 'roots'

View File

@@ -1,207 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
path
~~~~
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
import os
import sys
import shutil
from io import open
from six import PY2, text_type
FILESYSTEMENCODING = sys.getfilesystemencoding() or sys.getdefaultencoding()
class path(text_type):
"""
Represents a path which behaves like a string.
"""
if PY2:
def __new__(cls, s, encoding=FILESYSTEMENCODING, errors='strict'):
if isinstance(s, str):
s = s.decode(encoding, errors)
return text_type.__new__(cls, s)
return text_type.__new__(cls, s)
@property
def parent(self):
"""
The name of the directory the file or directory is in.
"""
return self.__class__(os.path.dirname(self))
def basename(self):
return os.path.basename(self)
def abspath(self):
"""
Returns the absolute path.
"""
return self.__class__(os.path.abspath(self))
def isabs(self):
"""
Returns ``True`` if the path is absolute.
"""
return os.path.isabs(self)
def isdir(self):
"""
Returns ``True`` if the path is a directory.
"""
return os.path.isdir(self)
def isfile(self):
"""
Returns ``True`` if the path is a file.
"""
return os.path.isfile(self)
def islink(self):
"""
Returns ``True`` if the path is a symbolic link.
"""
return os.path.islink(self)
def ismount(self):
"""
Returns ``True`` if the path is a mount point.
"""
return os.path.ismount(self)
def rmtree(self, ignore_errors=False, onerror=None):
"""
Removes the file or directory and any files or directories it may
contain.
:param ignore_errors:
If ``True`` errors are silently ignored, otherwise an exception
is raised in case an error occurs.
:param onerror:
A callback which gets called with the arguments `func`, `path` and
`exc_info`. `func` is one of :func:`os.listdir`, :func:`os.remove`
or :func:`os.rmdir`. `path` is the argument to the function which
caused it to fail and `exc_info` is a tuple as returned by
:func:`sys.exc_info`.
"""
shutil.rmtree(self, ignore_errors=ignore_errors, onerror=onerror)
def copytree(self, destination, symlinks=False):
"""
Recursively copy a directory to the given `destination`. If the given
`destination` does not exist it will be created.
:param symlinks:
If ``True`` symbolic links in the source tree result in symbolic
links in the destination tree otherwise the contents of the files
pointed to by the symbolic links are copied.
"""
shutil.copytree(self, destination, symlinks=symlinks)
def movetree(self, destination):
"""
Recursively move the file or directory to the given `destination`
similar to the Unix "mv" command.
If the `destination` is a file it may be overwritten depending on the
:func:`os.rename` semantics.
"""
shutil.move(self, destination)
move = movetree
def unlink(self):
"""
Removes a file.
"""
os.unlink(self)
def stat(self):
"""
Returns a stat of the file.
"""
return os.stat(self)
def utime(self, arg):
os.utime(self, arg)
def open(self, mode='r', **kwargs):
return open(self, mode, **kwargs)
def write_text(self, text, encoding='utf-8', **kwargs):
"""
Writes the given `text` to the file.
"""
if isinstance(text, bytes):
text = text.decode(encoding)
with open(self, 'w', encoding=encoding, **kwargs) as f:
f.write(text)
def text(self, encoding='utf-8', **kwargs):
"""
Returns the text in the file.
"""
mode = 'rU' if PY2 else 'r'
with open(self, mode=mode, encoding=encoding, **kwargs) as f:
return f.read()
def bytes(self):
"""
Returns the bytes in the file.
"""
with open(self, mode='rb') as f:
return f.read()
def write_bytes(self, bytes, append=False):
"""
Writes the given `bytes` to the file.
:param append:
If ``True`` given `bytes` are added at the end of the file.
"""
if append:
mode = 'ab'
else:
mode = 'wb'
with open(self, mode=mode) as f:
f.write(bytes)
def exists(self):
"""
Returns ``True`` if the path exist.
"""
return os.path.exists(self)
def lexists(self):
"""
Returns ``True`` if the path exists unless it is a broken symbolic
link.
"""
return os.path.lexists(self)
def makedirs(self, mode=0o777):
"""
Recursively create directories.
"""
os.makedirs(self, mode)
def joinpath(self, *args):
"""
Joins the path with the argument given and returns the result.
"""
return self.__class__(os.path.join(self, *map(self.__class__, args)))
def listdir(self):
return os.listdir(self)
__div__ = __truediv__ = joinpath
def __repr__(self):
return '%s(%s)' % (self.__class__.__name__, text_type.__repr__(self))

View File

@@ -13,7 +13,7 @@
# "raises" imported for usage by autodoc
import six
import sys
from util import SphinxTestApp, Struct
from sphinx.testing.util import SphinxTestApp, Struct
import pytest
from six import StringIO
@@ -25,17 +25,19 @@ from sphinx.ext.autodoc import AutoDirective, add_documenter, \
app = None
def setup_module():
@pytest.fixture(scope='module', autouse=True)
def setup_module(rootdir, sphinx_test_tempdir):
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.temp_data['docname'] = 'dummy'
app.connect('autodoc-process-docstring', process_docstring)
app.connect('autodoc-process-signature', process_signature)
app.connect('autodoc-skip-member', skip_member)
def teardown_module():
yield
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 warnings
import traceback
from path import path
import shutil
testroot = os.path.dirname(__file__) or '.'
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')) \
if 'SPHINX_TEST_TEMPDIR' not in os.environ \
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)
if tempdir.exists():
tempdir.rmtree()
tempdir.makedirs()
if os.path.exists(tempdir):
shutil.rmtree(tempdir)
os.makedirs(tempdir)
print('Running Sphinx test suite (with Python %s)...' % sys.version.split()[0])
sys.stdout.flush()
# exclude 'root' and 'roots' dirs for pytest test collector
# exclude 'roots' dirs for pytest test collector
ignore_paths = [
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:]
for ignore_path in ignore_paths:

View File

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

View File

@@ -17,13 +17,13 @@ import pytest
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()
def apidoc(tempdir, apidoc_params):
def apidoc(rootdir, tempdir, apidoc_params):
_, kwargs = apidoc_params
coderoot = kwargs.get('coderoot', (rootdir / 'root'))
coderoot = rootdir / kwargs.get('coderoot', 'test-root')
outdir = tempdir / 'out'
args = ['sphinx-apidoc', '-o', outdir, '-F', coderoot] + kwargs.get('options', [])
apidoc_main(args)
@@ -46,7 +46,7 @@ def apidoc_params(request):
return args, kwargs
@pytest.mark.apidoc(coderoot=(rootdir / 'root'))
@pytest.mark.apidoc(coderoot='test-root')
def test_simple(make_app, apidoc):
outdir = apidoc.outdir
assert (outdir / 'conf.py').isfile()
@@ -60,7 +60,7 @@ def test_simple(make_app, apidoc):
@pytest.mark.apidoc(
coderoot=(rootdir / 'roots' / 'test-apidoc-pep420'),
coderoot='test-apidoc-pep420',
options=["--implicit-namespaces"],
)
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
@pytest.mark.apidoc(coderoot=(rootdir / 'roots' / 'test-apidoc-pep420'))
@pytest.mark.apidoc(coderoot='test-apidoc-pep420')
def test_pep_0420_disabled(make_app, apidoc):
outdir = apidoc.outdir
assert (outdir / 'conf.py').isfile()
@@ -111,7 +111,7 @@ def test_pep_0420_disabled(make_app, 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):
outdir = apidoc.outdir
assert (outdir / 'conf.py').isfile()
@@ -131,7 +131,7 @@ def test_pep_0420_disabled_top_level_verify(make_app, apidoc):
@pytest.mark.apidoc(
coderoot=(rootdir / 'roots' / 'test-apidoc-trailing-underscore'))
coderoot='test-apidoc-trailing-underscore')
def test_trailing_underscore(make_app, apidoc):
outdir = apidoc.outdir
assert (outdir / 'conf.py').isfile()
@@ -150,7 +150,7 @@ def test_trailing_underscore(make_app, apidoc):
@pytest.mark.apidoc(
coderoot=(rootdir / 'root'),
coderoot='test-root',
options=[
'--doc-project', u'プロジェクト名'.encode('utf-8'),
'--doc-author', u'著者名'.encode('utf-8'),
@@ -178,7 +178,7 @@ def test_multibyte_parameters(make_app, apidoc):
@pytest.mark.apidoc(
coderoot=(rootdir / 'root'),
coderoot='test-root',
options=['--ext-mathjax'],
)
def test_extension_parsed(make_app, apidoc):

View File

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

View File

@@ -12,7 +12,7 @@
from six import PY3
from util import SphinxTestApp, Struct # NOQA
from sphinx.testing.util import SphinxTestApp, Struct # NOQA
import pytest
import enum
@@ -25,17 +25,19 @@ from sphinx.ext.autodoc import AutoDirective, add_documenter, \
app = None
def setup_module():
@pytest.fixture(scope='module', autouse=True)
def setup_module(rootdir, sphinx_test_tempdir):
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.temp_data['docname'] = 'dummy'
app.connect('autodoc-process-docstring', process_docstring)
app.connect('autodoc-process-signature', process_signature)
app.connect('autodoc-skip-member', skip_member)
def teardown_module():
yield
app.cleanup()

View File

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

View File

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

View File

@@ -17,7 +17,7 @@ from six import PY3
from sphinx import __display_version__
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
from html5lib import getTreeBuilder, HTMLParser
import pytest

View File

@@ -21,7 +21,7 @@ from html5lib import getTreeBuilder, HTMLParser
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
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.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

View File

@@ -19,7 +19,7 @@ import pytest
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

View File

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

View File

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

View File

@@ -16,6 +16,7 @@ import mock
import sphinx
from sphinx.config import Config
from sphinx.errors import ExtensionError, ConfigError, VersionRequirementError
from sphinx.testing.path import path
@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)
@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')
def test_needs_sphinx(make_app):
def test_needs_sphinx(make_app_with_empty_project):
make_app = make_app_with_empty_project
# micro version
app = make_app(confoverrides={'needs_sphinx': '1.3.3'}) # OK: less
app.cleanup()

View File

@@ -13,43 +13,52 @@ import pytest
from sphinx.config import Config
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, {}, '')
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}
reader = LiteralIncludeReader(LITERAL_INC_PATH, options, DUMMY_CONFIG)
reader = LiteralIncludeReader(literal_inc_path, options, DUMMY_CONFIG)
content, lines = reader.read()
assert content == LITERAL_INC_PATH.text()
assert content == literal_inc_path.text()
assert lines == 14
assert reader.lineno_start == 1
def test_LiteralIncludeReader_lineno_start():
def test_LiteralIncludeReader_lineno_start(literal_inc_path):
options = {'lineno-start': 5}
reader = LiteralIncludeReader(LITERAL_INC_PATH, options, DUMMY_CONFIG)
reader = LiteralIncludeReader(literal_inc_path, options, DUMMY_CONFIG)
content, lines = reader.read()
assert content == LITERAL_INC_PATH.text()
assert content == literal_inc_path.text()
assert lines == 14
assert reader.lineno_start == 5
def test_LiteralIncludeReader_pyobject1():
def test_LiteralIncludeReader_pyobject1(literal_inc_path):
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()
assert content == ("class Foo:\n"
" pass\n")
assert reader.lineno_start == 6
def test_LiteralIncludeReader_pyobject2():
def test_LiteralIncludeReader_pyobject2(literal_inc_path):
options = {'pyobject': 'Bar'}
reader = LiteralIncludeReader(LITERAL_INC_PATH, options, DUMMY_CONFIG)
reader = LiteralIncludeReader(literal_inc_path, options, DUMMY_CONFIG)
content, lines = reader.read()
assert content == ("class Bar:\n"
" def baz():\n"
@@ -57,25 +66,25 @@ def test_LiteralIncludeReader_pyobject2():
assert reader.lineno_start == 1 # no lineno-match
def test_LiteralIncludeReader_pyobject3():
def test_LiteralIncludeReader_pyobject3(literal_inc_path):
options = {'pyobject': 'Bar.baz'}
reader = LiteralIncludeReader(LITERAL_INC_PATH, options, DUMMY_CONFIG)
reader = LiteralIncludeReader(literal_inc_path, options, DUMMY_CONFIG)
content, lines = reader.read()
assert content == (" def baz():\n"
" pass\n")
def test_LiteralIncludeReader_pyobject_and_lines():
def test_LiteralIncludeReader_pyobject_and_lines(literal_inc_path):
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()
assert content == (" def baz():\n"
" pass\n")
def test_LiteralIncludeReader_lines1():
def test_LiteralIncludeReader_lines1(literal_inc_path):
options = {'lines': '1-4'}
reader = LiteralIncludeReader(LITERAL_INC_PATH, options, DUMMY_CONFIG)
reader = LiteralIncludeReader(literal_inc_path, options, DUMMY_CONFIG)
content, lines = reader.read()
assert content == (u"# Literally included file using Python highlighting\n"
u"# -*- coding: utf-8 -*-\n"
@@ -83,18 +92,18 @@ def test_LiteralIncludeReader_lines1():
u"foo = \"Including Unicode characters: üöä\"\n")
def test_LiteralIncludeReader_lines2():
def test_LiteralIncludeReader_lines2(literal_inc_path):
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()
assert content == (u"# Literally included file using Python highlighting\n"
u"foo = \"Including Unicode characters: üöä\"\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}
reader = LiteralIncludeReader(LITERAL_INC_PATH, options, DUMMY_CONFIG)
reader = LiteralIncludeReader(literal_inc_path, options, DUMMY_CONFIG)
content, lines = reader.read()
assert content == (u"foo = \"Including Unicode characters: üöä\"\n"
u"\n"
@@ -103,24 +112,24 @@ def test_LiteralIncludeReader_lines_and_lineno_match1():
@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}
reader = LiteralIncludeReader(LITERAL_INC_PATH, options, DUMMY_CONFIG)
reader = LiteralIncludeReader(literal_inc_path, options, DUMMY_CONFIG)
with pytest.raises(ValueError):
content, lines = reader.read()
@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}
reader = LiteralIncludeReader(LITERAL_INC_PATH, options, DUMMY_CONFIG)
reader = LiteralIncludeReader(literal_inc_path, options, DUMMY_CONFIG)
with pytest.raises(ValueError):
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'}
reader = LiteralIncludeReader(LITERAL_INC_PATH, options, DUMMY_CONFIG)
reader = LiteralIncludeReader(literal_inc_path, options, DUMMY_CONFIG)
content, lines = reader.read()
assert content == ("class Foo:\n"
" pass\n"
@@ -129,19 +138,19 @@ def test_LiteralIncludeReader_start_at():
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'}
reader = LiteralIncludeReader(LITERAL_INC_PATH, options, DUMMY_CONFIG)
reader = LiteralIncludeReader(literal_inc_path, options, DUMMY_CONFIG)
content, lines = reader.read()
assert content == (" pass\n"
"\n")
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-',
'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()
assert content == ("\n"
"class Bar:\n"
@@ -151,9 +160,9 @@ def test_LiteralIncludeReader_start_after_and_lines():
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': '#'}
reader = LiteralIncludeReader(LITERAL_INC_PATH, options, DUMMY_CONFIG)
reader = LiteralIncludeReader(literal_inc_path, options, DUMMY_CONFIG)
content, lines = reader.read()
assert content == ("\n"
"class Foo:\n"
@@ -161,41 +170,41 @@ def test_LiteralIncludeReader_start_at_and_lines():
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'}
reader = LiteralIncludeReader(LITERAL_INC_PATH, options, DUMMY_CONFIG)
reader = LiteralIncludeReader(literal_inc_path, options, DUMMY_CONFIG)
with pytest.raises(ValueError):
content, lines = reader.read()
options = {'end-at': 'NOTHING'}
reader = LiteralIncludeReader(LITERAL_INC_PATH, options, DUMMY_CONFIG)
reader = LiteralIncludeReader(literal_inc_path, options, DUMMY_CONFIG)
with pytest.raises(ValueError):
content, lines = reader.read()
options = {'start-after': 'NOTHING'}
reader = LiteralIncludeReader(LITERAL_INC_PATH, options, DUMMY_CONFIG)
reader = LiteralIncludeReader(literal_inc_path, options, DUMMY_CONFIG)
with pytest.raises(ValueError):
content, lines = reader.read()
options = {'end-before': 'NOTHING'}
reader = LiteralIncludeReader(LITERAL_INC_PATH, options, DUMMY_CONFIG)
reader = LiteralIncludeReader(literal_inc_path, options, DUMMY_CONFIG)
with pytest.raises(ValueError):
content, lines = reader.read()
def test_LiteralIncludeReader_prepend():
def test_LiteralIncludeReader_prepend(literal_inc_path):
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()
assert content == ("Hello\n"
"# Literally included file using Python highlighting\n"
"Sphinx\n")
def test_LiteralIncludeReader_dedent():
def test_LiteralIncludeReader_dedent(literal_inc_path):
# 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()
assert content == (" def baz():\n"
" pass\n"
@@ -203,7 +212,7 @@ def test_LiteralIncludeReader_dedent():
# 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()
assert content == ("def baz():\n"
" pass\n"
@@ -211,17 +220,17 @@ def test_LiteralIncludeReader_dedent():
# 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()
assert content == ("f baz():\n"
" pass\n"
"\n")
def test_LiteralIncludeReader_tabwidth():
def test_LiteralIncludeReader_tabwidth(testroot):
# tab-width: 4
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()
assert content == ("class Qux:\n"
" def quux(self):\n"
@@ -229,27 +238,27 @@ def test_LiteralIncludeReader_tabwidth():
# tab-width: 8
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()
assert content == ("class Qux:\n"
" def quux(self):\n"
" pass\n")
def test_LiteralIncludeReader_tabwidth_dedent():
def test_LiteralIncludeReader_tabwidth_dedent(testroot):
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()
assert content == ("def quux(self):\n"
" pass\n")
def test_LiteralIncludeReader_diff():
options = {'diff': TESTROOT_PATH / 'literal-diff.inc'}
reader = LiteralIncludeReader(LITERAL_INC_PATH, options, DUMMY_CONFIG)
def test_LiteralIncludeReader_diff(testroot, literal_inc_path):
options = {'diff': testroot / 'literal-diff.inc'}
reader = LiteralIncludeReader(literal_inc_path, options, DUMMY_CONFIG)
content, lines = reader.read()
assert content == ("--- " + TESTROOT_PATH + "/literal-diff.inc\n"
"+++ " + TESTROOT_PATH + "/literal.inc\n"
assert content == ("--- " + testroot + "/literal-diff.inc\n"
"+++ " + testroot + "/literal.inc\n"
"@@ -7,8 +7,8 @@\n"
" pass\n"
" \n"

View File

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

View File

@@ -16,7 +16,7 @@ from docutils import nodes
from sphinx import addnodes
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')

View File

@@ -17,7 +17,7 @@ from docutils import nodes
from sphinx import addnodes
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):

View File

@@ -8,22 +8,24 @@
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
: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.latex import LaTeXBuilder
app = env = None
def setup_module():
@pytest.fixture(scope='module', autouse=True)
def setup_module(rootdir, sphinx_test_tempdir):
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
def teardown_module():
yield
app.cleanup()

View File

@@ -16,7 +16,7 @@ from sphinx.addnodes import compact_paragraph, only
from sphinx.builders.html import StandaloneHTMLBuilder
import pytest
from util import assert_node
from sphinx.testing.util import assert_node
@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 util import etree_parse
from sphinx.testing.util import etree_parse
import pytest

View File

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

View File

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

View File

@@ -20,7 +20,7 @@ from babel.messages import pofile, mofile
from six import string_types
import pytest
from util import (
from sphinx.testing.util import (
path, etree_parse, strip_escseq,
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
# 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):
# --- don't rebuild by .mo mtime
def get_number_of_update_targets(app_):
updated = app_.env.update(app_.config, app_.srcdir, app_.doctreedir)
return len(updated)
# setup new directory
args, kwargs = app_params
kwargs['srcdir'] = 'test_gettext_dont_rebuild_mo'
# phase1: build document with non-gettext builder and generate mo file in srcdir
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
import pytest
from util import assert_node
from sphinx.testing.util import assert_node
@pytest.fixture

View File

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

View File

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

View File

@@ -17,7 +17,7 @@ from sphinx.util import (
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():

View File

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

View File

@@ -11,28 +11,31 @@
import pickle
import pytest
from docutils.parsers.rst.directives.html import MetaBody
from sphinx import addnodes
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
def setup_module():
@pytest.fixture(scope='module', autouse=True)
def setup_module(rootdir, sphinx_test_tempdir):
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.connect('doctree-resolved', on_doctree_resolved)
app.build()
original = doctrees['original']
original_uids = [n.uid for n in add_uids(original, is_paragraph)]
def teardown_module():
yield
app.cleanup()

View File

@@ -16,17 +16,16 @@ except ImportError:
sqlalchemy_missing = True
import pytest
from util import rootdir, tempdir
@pytest.mark.skipif(sqlalchemy_missing, reason='needs sqlalchemy')
def test_build(request):
def test_build(request, rootdir, sphinx_test_tempdir):
settings = {
'srcdir': rootdir / 'roots' / 'test-basic',
'srcdir': rootdir / 'test-basic',
# 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.
'builddir': tempdir / 'websupport'
'builddir': sphinx_test_tempdir / 'websupport'
}
marker = request.node.get_marker('support')
if marker:

View File

@@ -1,360 +0,0 @@
# -*- coding: utf-8 -*-
"""
Sphinx test suite utilities
~~~~~~~~~~~~~~~~~~~~~~~~~~~
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
import os
import re
import sys
import warnings
from functools import wraps
from xml.etree import ElementTree
from six import string_types
from six import StringIO
import pytest
from docutils import nodes
from docutils.parsers.rst import directives, roles
from sphinx import application
from sphinx.builders.latex import LaTeXBuilder
from sphinx.ext.autodoc import AutoDirective
from sphinx.pycode import ModuleAnalyzer
from sphinx.deprecation import RemovedInSphinx17Warning
from path import path
__all__ = [
'rootdir', 'tempdir',
'skip_unless_importable', 'Struct',
'SphinxTestApp',
'path',
'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):
if not re.search(regex, text, flags):
assert False, '%r did not match %r' % (regex, text)
def assert_not_re_search(regex, text, flags=0):
if re.search(regex, text, flags):
assert False, '%r did match %r' % (regex, text)
def assert_startswith(thing, prefix):
if not thing.startswith(prefix):
assert False, '%r does not start with %r' % (thing, prefix)
def assert_node(node, cls=None, xpath="", **kwargs):
if cls:
if isinstance(cls, list):
assert_node(node, cls[0], xpath=xpath, **kwargs)
if cls[1:]:
if isinstance(cls[1], tuple):
assert_node(node, cls[1], xpath=xpath, **kwargs)
else:
assert len(node) == 1, \
'The node%s has %d child nodes, not one' % (xpath, len(node))
assert_node(node[0], cls[1:], xpath=xpath + "[0]", **kwargs)
elif isinstance(cls, tuple):
assert len(node) == len(cls), \
'The node%s has %d child nodes, not %r' % (xpath, len(node), len(cls))
for i, nodecls in enumerate(cls):
path = xpath + "[%d]" % i
assert_node(node[i], nodecls, xpath=path, **kwargs)
elif isinstance(cls, string_types):
assert node == cls, 'The node %r is not %r: %r' % (xpath, cls, node)
else:
assert isinstance(node, cls), \
'The node%s is not subclass of %r: %r' % (xpath, cls, node)
for key, value in kwargs.items():
assert key in node, 'The node%s does not have %r attribute: %r' % (xpath, key, node)
assert node[key] == value, \
'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):
with warnings.catch_warnings(record=False):
warnings.filterwarnings("ignore", category=DeprecationWarning)
return ElementTree.parse(path)
class Struct(object):
def __init__(self, **kwds):
self.__dict__.update(kwds)
class SphinxTestApp(application.Sphinx):
"""
A subclass of :class:`Sphinx` that runs on the test root, with some
better default values for the initialization parameters.
"""
def __init__(self, buildername='html', testroot=None, srcdir=None,
freshenv=False, confoverrides=None, status=None, warning=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:
(srcdir / 'docutils.conf').write_text(docutilsconf)
builddir = srcdir / '_build'
# if confdir is None:
confdir = srcdir
# if outdir is None:
outdir = builddir.joinpath(buildername)
if not outdir.isdir():
outdir.makedirs()
# if doctreedir is None:
doctreedir = builddir.joinpath('doctrees')
if not doctreedir.isdir():
doctreedir.makedirs()
if confoverrides is None:
confoverrides = {}
# if warningiserror is None:
warningiserror = False
self._saved_path = sys.path[:]
self._saved_directives = directives._directives.copy()
self._saved_roles = roles._roles.copy()
self._saved_nodeclasses = set(v for v in dir(nodes.GenericNodeVisitor)
if v.startswith('visit_'))
try:
application.Sphinx.__init__(self, srcdir, confdir, outdir, doctreedir,
buildername, confoverrides, status, warning,
freshenv, warningiserror, tags)
except:
self.cleanup()
raise
def cleanup(self, doctrees=False):
AutoDirective._registry.clear()
ModuleAnalyzer.cache.clear()
LaTeXBuilder.usepackages = []
sys.path[:] = self._saved_path
sys.modules.pop('autodoc_fodder', None)
directives._directives = self._saved_directives
roles._roles = self._saved_roles
for method in dir(nodes.GenericNodeVisitor):
if method.startswith('visit_') and \
method not in self._saved_nodeclasses:
delattr(nodes.GenericNodeVisitor, 'visit_' + method[6:])
delattr(nodes.GenericNodeVisitor, 'depart_' + method[6:])
def __repr__(self):
return '<%s buildername=%r>' % (self.__class__.__name__, self.builder.name)
_unicode_literals_re = re.compile(r'u(".*?")|u(\'.*?\')')
def remove_unicode_literals(s):
return _unicode_literals_re.sub(lambda x: x.group(1) or x.group(2), s)
def find_files(root, suffix=None):
for dirpath, dirs, files in os.walk(root, followlinks=True):
dirpath = path(dirpath)
for f in [f for f in files if not suffix or f.endswith(suffix)]:
fpath = dirpath / f
yield os.path.relpath(fpath, root)
def strip_escseq(text):
return re.sub('\x1b.*?m', '', text)
# #############################################
# DEPRECATED implementations
def gen_with_app(*args, **kwargs):
"""
**DEPRECATED**: use pytest.mark.parametrize instead.
Decorate a test generator to pass a SphinxTestApp as the first argument to
the test generator when it's executed.
"""
def generator(func):
@wraps(func)
def deco(*args2, **kwargs2):
status, warning = StringIO(), StringIO()
kwargs['status'] = status
kwargs['warning'] = warning
app = SphinxTestApp(*args, **kwargs)
try:
for item in func(app, status, warning, *args2, **kwargs2):
yield item
finally:
app.cleanup()
return deco
return generator
def skip_if(condition, msg=None):
"""
**DEPRECATED**: use pytest.mark.skipif instead.
Decorator to skip test if condition is true.
"""
return pytest.mark.skipif(condition, reason=(msg or 'conditional skip'))
def skip_unless(condition, msg=None):
"""
**DEPRECATED**: use pytest.mark.skipif instead.
Decorator to skip test if condition is false.
"""
return pytest.mark.skipif(not condition, reason=(msg or 'conditional skip'))
def with_tempdir(func):
"""
**DEPRECATED**: use tempdir fixture instead.
"""
return func
def raises(exc, func, *args, **kwds):
"""
**DEPRECATED**: use pytest.raises instead.
Raise AssertionError if ``func(*args, **kwds)`` does not raise *exc*.
"""
with pytest.raises(exc):
func(*args, **kwds)
def raises_msg(exc, msg, func, *args, **kwds):
"""
**DEPRECATED**: use pytest.raises instead.
Raise AssertionError if ``func(*args, **kwds)`` does not raise *exc*,
and check if the message contains *msg*.
"""
with pytest.raises(exc) as excinfo:
func(*args, **kwds)
assert msg in str(excinfo.value)
def assert_true(v1, msg=''):
"""
**DEPRECATED**: use assert instead.
"""
assert v1, msg
def assert_equal(v1, v2, msg=''):
"""
**DEPRECATED**: use assert instead.
"""
assert v1 == v2, msg
def assert_in(x, thing, msg=''):
"""
**DEPRECATED**: use assert instead.
"""
if x not in thing:
assert False, msg or '%r is not in %r' % (x, thing)
def assert_not_in(x, thing, msg=''):
"""
**DEPRECATED**: use assert instead.
"""
if x in thing:
assert False, msg or '%r is in %r' % (x, thing)
class ListOutput(object):
"""
File-like object that collects written text in a list.
"""
def __init__(self, name):
self.name = name
self.content = []
def reset(self):
del self.content[:]
def write(self, text):
self.content.append(text)
# **DEPRECATED**: use pytest.skip instead.
SkipTest = pytest.skip.Exception
class _DeprecationWrapper(object):
def __init__(self, mod, deprecated):
self._mod = mod
self._deprecated = deprecated
def __getattr__(self, attr):
if attr in self._deprecated:
obj, instead = self._deprecated[attr]
warnings.warn("tests/util.py::%s is deprecated and will be "
"removed in Sphinx 1.7, please use %s instead."
% (attr, instead),
RemovedInSphinx17Warning, stacklevel=2)
return obj
return getattr(self._mod, attr)
sys.modules[__name__] = _DeprecationWrapper(sys.modules[__name__], dict( # type: ignore
with_app=(pytest.mark.sphinx, 'pytest.mark.sphinx'),
TestApp=(SphinxTestApp, 'SphinxTestApp'),
gen_with_app=(gen_with_app, 'pytest.mark.parametrize'),
skip_if=(skip_if, 'pytest.skipif'),
skip_unless=(skip_unless, 'pytest.skipif'),
with_tempdir=(with_tempdir, 'tmpdir pytest fixture'),
raises=(raises, 'pytest.raises'),
raises_msg=(raises_msg, 'pytest.raises'),
assert_true=(assert_true, 'assert'),
assert_equal=(assert_equal, 'assert'),
assert_in=(assert_in, 'assert'),
assert_not_in=(assert_not_in, 'assert'),
ListOutput=(ListOutput, 'StringIO'),
SkipTest=(SkipTest, 'pytest.skip'),
))