Merge branch 'stable'

This commit is contained in:
shimizukawa 2017-01-07 02:13:50 +09:00
commit 4c22cd10ca
67 changed files with 1090 additions and 2113 deletions

View File

@ -12,7 +12,7 @@ python:
- "pypy" - "pypy"
env: env:
global: global:
- TEST='-v --with-timer --timer-top-n 25' - TEST='-v --durations 25'
- PYTHONFAULTHANDLER=x - PYTHONFAULTHANDLER=x
- PYTHONWARNINGS=all - PYTHONWARNINGS=all
matrix: matrix:

View File

@ -58,6 +58,7 @@ Features added
* #3241: emit latex warning if buggy titlesec (ref #3210) * #3241: emit latex warning if buggy titlesec (ref #3210)
* #3194: Refer the $MAKE environment variable to determine ``make`` command * #3194: Refer the $MAKE environment variable to determine ``make`` command
* Emit warning for nested numbered toctrees (refs: #3142)
Bugs fixed Bugs fixed
---------- ----------
@ -70,6 +71,9 @@ Bugs fixed
attributes of Enum class correctly. attributes of Enum class correctly.
* #3261: ``latex_use_parts`` makes sphinx crash * #3261: ``latex_use_parts`` makes sphinx crash
* The warning type ``misc.highlighting_failure`` does not work * The warning type ``misc.highlighting_failure`` does not work
* #3294: ``add_latex_package()`` make crashes non-LaTeX builders
* The caption of table are rendered as invalid HTML (refs: #3287)
Release 1.5.1 (released Dec 13, 2016) Release 1.5.1 (released Dec 13, 2016)
===================================== =====================================

View File

@ -75,14 +75,13 @@ reindent:
@$(PYTHON) utils/reindent.py -r -n . @$(PYTHON) utils/reindent.py -r -n .
test: test:
@cd tests; $(PYTHON) run.py -I py35 -d -m '^[tT]est' $(TEST) @cd tests; $(PYTHON) run.py --ignore py35 -v $(TEST)
test-async: test-async:
@cd tests; $(PYTHON) run.py -d -m '^[tT]est' $(TEST) @cd tests; $(PYTHON) run.py -v $(TEST)
covertest: covertest:
@cd tests; $(PYTHON) run.py -d -m '^[tT]est' --with-coverage \ @cd tests; $(PYTHON) run.py -v --cov=sphinx --junitxml=.junit.xml $(TEST)
--cover-package=sphinx $(TEST)
build: build:
@$(PYTHON) setup.py build @$(PYTHON) setup.py build

View File

@ -233,6 +233,7 @@ General configuration
* ref.citation * ref.citation
* ref.doc * ref.doc
* misc.highlighting_failure * misc.highlighting_failure
* toc.secnum
* epub.unknown_project_files * epub.unknown_project_files
You can choose from these types. You can choose from these types.

View File

@ -812,7 +812,8 @@ class Sphinx(object):
def add_latex_package(self, packagename, options=None): def add_latex_package(self, packagename, options=None):
# type: (unicode, unicode) -> None # type: (unicode, unicode) -> None
logger.debug('[app] adding latex package: %r', packagename) logger.debug('[app] adding latex package: %r', packagename)
self.builder.usepackages.append((packagename, options)) if hasattr(self.builder, 'usepackages'): # only for LaTeX builder
self.builder.usepackages.append((packagename, options))
def add_lexer(self, alias, lexer): def add_lexer(self, alias, lexer):
# type: (unicode, Any) -> None # type: (unicode, Any) -> None

View File

@ -483,10 +483,14 @@ class Toctree(EnvironmentManager):
if depth == 0: if depth == 0:
return return
for (title, ref) in toctreenode['entries']: for (title, ref) in toctreenode['entries']:
if url_re.match(ref) or ref == 'self' or ref in assigned: if url_re.match(ref) or ref == 'self':
# don't mess with those # don't mess with those
continue continue
if ref in self.tocs: elif ref in assigned:
logger.warning('%s is already assigned section numbers '
'(nested numbered toctree?)', ref,
location=toctreenode, type='toc', subtype='secnum')
elif ref in self.tocs:
secnums = self.toc_secnumbers[ref] = {} secnums = self.toc_secnumbers[ref] = {}
assigned.add(ref) assigned.add(ref)
_walk_toc(self.tocs[ref], secnums, depth, _walk_toc(self.tocs[ref], secnums, depth,

View File

@ -228,9 +228,10 @@ def save_traceback(app):
modfile = getattr(extmod, '__file__', 'unknown') modfile = getattr(extmod, '__file__', 'unknown')
if isinstance(modfile, bytes): if isinstance(modfile, bytes):
modfile = modfile.decode(fs_encoding, 'replace') modfile = modfile.decode(fs_encoding, 'replace')
os.write(fd, ('# %s (%s) from %s\n' % ( version = app._extension_metadata[extname]['version']
extname, app._extension_metadata[extname]['version'], if version != 'builtin':
modfile)).encode('utf-8')) os.write(fd, ('# %s (%s) from %s\n' %
(extname, version, modfile)).encode('utf-8'))
os.write(fd, exc_format.encode('utf-8')) os.write(fd, exc_format.encode('utf-8'))
os.close(fd) os.close(fd)
return path return path

View File

@ -344,6 +344,27 @@ class HTMLTranslator(BaseTranslator):
if isinstance(node.parent, nodes.table): if isinstance(node.parent, nodes.table):
self.body.append('<span class="caption-text">') self.body.append('<span class="caption-text">')
def depart_title(self, node):
close_tag = self.context[-1]
if (self.permalink_text and self.builder.add_permalinks and
node.parent.hasattr('ids') and node.parent['ids']):
# add permalink anchor
if close_tag.startswith('</h'):
self.add_permalink_ref(node.parent, _('Permalink to this headline'))
elif close_tag.startswith('</a></h'):
self.body.append(u'</a><a class="headerlink" href="#%s" ' %
node.parent['ids'][0] +
u'title="%s">%s' % (
_('Permalink to this headline'),
self.permalink_text))
elif isinstance(node.parent, nodes.table):
self.body.append('</span>')
self.add_permalink_ref(node.parent, _('Permalink to this table'))
elif isinstance(node.parent, nodes.table):
self.body.append('</span>')
BaseTranslator.depart_title(self, node)
# overwritten # overwritten
def visit_literal_block(self, node): def visit_literal_block(self, node):
if node.rawsource != node.astext(): if node.rawsource != node.astext():
@ -701,25 +722,6 @@ class HTMLTranslator(BaseTranslator):
def depart_manpage(self, node): def depart_manpage(self, node):
return self.depart_literal_emphasis(node) return self.depart_literal_emphasis(node)
def depart_title(self, node):
close_tag = self.context[-1]
if (self.permalink_text and self.builder.add_permalinks and
node.parent.hasattr('ids') and node.parent['ids']):
# add permalink anchor
if close_tag.startswith('</h'):
self.add_permalink_ref(node.parent, _('Permalink to this headline'))
elif close_tag.startswith('</a></h'):
self.body.append(u'</a><a class="headerlink" href="#%s" ' %
node.parent['ids'][0] +
u'title="%s">%s' % (
_('Permalink to this headline'),
self.permalink_text))
elif isinstance(node.parent, nodes.table):
self.body.append('</span>')
self.add_permalink_ref(node.parent, _('Permalink to this table'))
BaseTranslator.depart_title(self, node)
# overwritten to add even/odd classes # overwritten to add even/odd classes
def visit_table(self, node): def visit_table(self, node):

View File

@ -1,6 +1,6 @@
flake8 flake8
nose pytest>=3.0
nose-timer pytest-cov
mock mock
six>=1.4 six>=1.4
Jinja2>=2.3 Jinja2>=2.3

108
tests/conftest.py Normal file
View File

@ -0,0 +1,108 @@
# -*- coding: utf-8 -*-
import sys
import subprocess
import pytest
from six import StringIO
from util import SphinxTestApp, path
@pytest.fixture
def app_params(request):
"""
parameters that is specified by 'pytest.mark.sphinx' for
sphinx.application.Sphinx initialization
"""
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())]
return args, kwargs
@pytest.fixture(scope='function')
def app(app_params, make_app):
"""
provides sphinx.application.Sphinx object
"""
args, kwargs = app_params
app_ = make_app(*args, **kwargs)
return 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():
"""
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_ = SphinxTestApp(*args, **kwargs)
apps.append(app_)
return app_
yield make
sys.path[:] = syspath
for app_ in apps:
app_.cleanup()
@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 path(tmpdir)

File diff suppressed because it is too large Load Diff

View File

@ -12,7 +12,7 @@ import sys
import shutil import shutil
from io import open from io import open
from six import PY2, text_type, binary_type from six import PY2, text_type
FILESYSTEMENCODING = sys.getfilesystemencoding() or sys.getdefaultencoding() FILESYSTEMENCODING = sys.getfilesystemencoding() or sys.getdefaultencoding()
@ -144,9 +144,7 @@ class path(text_type):
""" """
mode = 'rU' if PY2 else 'r' mode = 'rU' if PY2 else 'r'
with open(self, mode=mode, encoding=encoding, **kwargs) as f: with open(self, mode=mode, encoding=encoding, **kwargs) as f:
text = f.read() return f.read()
contents = repr_as(text, '<%s contents>' % self.basename())
return contents
def bytes(self): def bytes(self):
""" """
@ -201,21 +199,3 @@ class path(text_type):
def __repr__(self): def __repr__(self):
return '%s(%s)' % (self.__class__.__name__, text_type.__repr__(self)) return '%s(%s)' % (self.__class__.__name__, text_type.__repr__(self))
# Lives here only to avoid circular references; use it from util.py!
class _repr_text(text_type):
def __repr__(self):
return self._repr
class _repr_bin(binary_type):
def __repr__(self):
return self._repr
def repr_as(string, repr_):
wrapper = _repr_text if isinstance(string, text_type) else _repr_bin
proxy = wrapper(string)
proxy._repr = repr_
return proxy

View File

@ -14,7 +14,7 @@
import six import six
import sys import sys
from util import TestApp, Struct, raises, SkipTest from util import TestApp, Struct, raises, SkipTest
from nose.tools import with_setup, eq_ import pytest
from six import StringIO from six import StringIO
from docutils.statemachine import ViewList from docutils.statemachine import ViewList
@ -42,6 +42,7 @@ def teardown_module():
directive = options = None directive = options = None
@pytest.fixture
def setup_test(): def setup_test():
global options, directive global options, directive
global processed_docstrings, processed_signatures, _warnings global processed_docstrings, processed_signatures, _warnings
@ -106,7 +107,7 @@ def skip_member(app, what, name, obj, skip, options):
return True return True
@with_setup(setup_test) @pytest.mark.usefixtures('setup_test')
def test_generate(): def test_generate():
def assert_warns(warn_str, objtype, name, **kw): def assert_warns(warn_str, objtype, name, **kw):
inst = AutoDirective._registry[objtype](directive, name) inst = AutoDirective._registry[objtype](directive, name)

View File

@ -4,7 +4,7 @@ import os
import sys import sys
sys.path.insert(0, os.path.abspath('.')) sys.path.insert(0, os.path.abspath('.'))
extensions = ['test_enumerable_node'] extensions = ['enumerable_node']
master_doc = 'index' master_doc = 'index'
numfig = True numfig = True

View File

@ -11,7 +11,7 @@ class DummyTestParser(Parser):
pass pass
extensions = ['test_source_parser'] extensions = ['source_parser']
source_suffix = ['.rst', '.test'] source_suffix = ['.rst', '.test']
source_parsers = { source_parsers = {
'.test': DummyTestParser '.test': DummyTestParser

View File

@ -11,7 +11,7 @@ class DummyMarkdownParser(Parser):
pass pass
extensions = ['test_source_parser'] extensions = ['source_parser']
source_suffix = ['.rst', '.md'] source_suffix = ['.rst', '.md']
source_parsers = { source_parsers = {
'.md': DummyMarkdownParser '.md': DummyMarkdownParser

View File

@ -17,14 +17,14 @@ import warnings
import traceback import traceback
from path import path from path import path
import nose import pytest
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)))
# check dependencies before testing # check dependencies before testing
print('Checking dependencies...') print('Checking dependencies...')
for modname in ('nose', 'mock', 'six', 'docutils', 'jinja2', 'pygments', for modname in ('pytest', 'mock', 'six', 'docutils', 'jinja2', 'pygments',
'snowballstemmer', 'babel', 'html5lib'): 'snowballstemmer', 'babel', 'html5lib'):
try: try:
__import__(modname) __import__(modname)
@ -50,7 +50,15 @@ print('Running Sphinx test suite (with Python %s)...' % sys.version.split()[0])
sys.stdout.flush() sys.stdout.flush()
# filter warnings of test dependencies # filter warnings of test dependencies
warnings.filterwarnings('ignore', category=DeprecationWarning, module='nose.util')
warnings.filterwarnings('ignore', category=DeprecationWarning, module='site') # virtualenv warnings.filterwarnings('ignore', category=DeprecationWarning, module='site') # virtualenv
nose.main(argv=sys.argv) # exclude 'root' and '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')
]
args = sys.argv[1:]
for path in ignore_paths:
args.extend(['--ignore', path])
sys.exit(pytest.main(args))

View File

@ -11,7 +11,8 @@
import sys import sys
from util import with_app, rootdir import pytest
from util import rootdir
def setup_module(): def setup_module():
@ -22,7 +23,7 @@ def teardown_module():
sys.path.remove(rootdir / 'roots' / 'test-api-set-translator') sys.path.remove(rootdir / 'roots' / 'test-api-set-translator')
@with_app('html') @pytest.mark.sphinx('html')
def test_html_translator(app, status, warning): def test_html_translator(app, status, warning):
# no set_translator() # no set_translator()
translator_class = app.builder.translator_class translator_class = app.builder.translator_class
@ -30,8 +31,8 @@ def test_html_translator(app, status, warning):
assert translator_class.__name__ == 'SmartyPantsHTMLTranslator' assert translator_class.__name__ == 'SmartyPantsHTMLTranslator'
@with_app('html', @pytest.mark.sphinx('html', confoverrides={
confoverrides={'html_use_smartypants': False}) 'html_use_smartypants': False})
def test_html_with_smartypants(app, status, warning): def test_html_with_smartypants(app, status, warning):
# no set_translator(), html_use_smartypants=False # no set_translator(), html_use_smartypants=False
translator_class = app.builder.translator_class translator_class = app.builder.translator_class
@ -39,7 +40,7 @@ def test_html_with_smartypants(app, status, warning):
assert translator_class.__name__ == 'HTMLTranslator' assert translator_class.__name__ == 'HTMLTranslator'
@with_app('html', testroot='api-set-translator') @pytest.mark.sphinx('html', testroot='api-set-translator')
def test_html_with_set_translator_for_html_(app, status, warning): def test_html_with_set_translator_for_html_(app, status, warning):
# use set_translator() # use set_translator()
translator_class = app.builder.translator_class translator_class = app.builder.translator_class
@ -48,7 +49,7 @@ def test_html_with_set_translator_for_html_(app, status, warning):
# this test break test_websupport.test_comments test. why? # this test break test_websupport.test_comments test. why?
# @with_app( # @pytest.mark.sphinx(
# buildername='dirhtml', # buildername='dirhtml',
# srcdir=(test_roots / 'test-api-set-translator'), # srcdir=(test_roots / 'test-api-set-translator'),
# ) # )
@ -58,63 +59,63 @@ def test_html_with_set_translator_for_html_(app, status, warning):
# assert translator_class.__name__ == 'ConfDirHTMLTranslator' # assert translator_class.__name__ == 'ConfDirHTMLTranslator'
@with_app('singlehtml', testroot='api-set-translator') @pytest.mark.sphinx('singlehtml', testroot='api-set-translator')
def test_singlehtml_set_translator_for_singlehtml(app, status, warning): def test_singlehtml_set_translator_for_singlehtml(app, status, warning):
translator_class = app.builder.translator_class translator_class = app.builder.translator_class
assert translator_class assert translator_class
assert translator_class.__name__ == 'ConfSingleHTMLTranslator' assert translator_class.__name__ == 'ConfSingleHTMLTranslator'
@with_app('pickle', testroot='api-set-translator') @pytest.mark.sphinx('pickle', testroot='api-set-translator')
def test_pickle_set_translator_for_pickle(app, status, warning): def test_pickle_set_translator_for_pickle(app, status, warning):
translator_class = app.builder.translator_class translator_class = app.builder.translator_class
assert translator_class assert translator_class
assert translator_class.__name__ == 'ConfPickleTranslator' assert translator_class.__name__ == 'ConfPickleTranslator'
@with_app('json', testroot='api-set-translator') @pytest.mark.sphinx('json', testroot='api-set-translator')
def test_json_set_translator_for_json(app, status, warning): def test_json_set_translator_for_json(app, status, warning):
translator_class = app.builder.translator_class translator_class = app.builder.translator_class
assert translator_class assert translator_class
assert translator_class.__name__ == 'ConfJsonTranslator' assert translator_class.__name__ == 'ConfJsonTranslator'
@with_app('latex', testroot='api-set-translator') @pytest.mark.sphinx('latex', testroot='api-set-translator')
def test_html_with_set_translator_for_latex(app, status, warning): def test_html_with_set_translator_for_latex(app, status, warning):
translator_class = app.builder.translator_class translator_class = app.builder.translator_class
assert translator_class assert translator_class
assert translator_class.__name__ == 'ConfLaTeXTranslator' assert translator_class.__name__ == 'ConfLaTeXTranslator'
@with_app('man', testroot='api-set-translator') @pytest.mark.sphinx('man', testroot='api-set-translator')
def test_html_with_set_translator_for_man(app, status, warning): def test_html_with_set_translator_for_man(app, status, warning):
translator_class = app.builder.translator_class translator_class = app.builder.translator_class
assert translator_class assert translator_class
assert translator_class.__name__ == 'ConfManualPageTranslator' assert translator_class.__name__ == 'ConfManualPageTranslator'
@with_app('texinfo', testroot='api-set-translator') @pytest.mark.sphinx('texinfo', testroot='api-set-translator')
def test_html_with_set_translator_for_texinfo(app, status, warning): def test_html_with_set_translator_for_texinfo(app, status, warning):
translator_class = app.builder.translator_class translator_class = app.builder.translator_class
assert translator_class assert translator_class
assert translator_class.__name__ == 'ConfTexinfoTranslator' assert translator_class.__name__ == 'ConfTexinfoTranslator'
@with_app('text', testroot='api-set-translator') @pytest.mark.sphinx('text', testroot='api-set-translator')
def test_html_with_set_translator_for_text(app, status, warning): def test_html_with_set_translator_for_text(app, status, warning):
translator_class = app.builder.translator_class translator_class = app.builder.translator_class
assert translator_class assert translator_class
assert translator_class.__name__ == 'ConfTextTranslator' assert translator_class.__name__ == 'ConfTextTranslator'
@with_app('xml', testroot='api-set-translator') @pytest.mark.sphinx('xml', testroot='api-set-translator')
def test_html_with_set_translator_for_xml(app, status, warning): def test_html_with_set_translator_for_xml(app, status, warning):
translator_class = app.builder.translator_class translator_class = app.builder.translator_class
assert translator_class assert translator_class
assert translator_class.__name__ == 'ConfXMLTranslator' assert translator_class.__name__ == 'ConfXMLTranslator'
@with_app('pseudoxml', testroot='api-set-translator') @pytest.mark.sphinx('pseudoxml', testroot='api-set-translator')
def test_html_with_set_translator_for_pseudoxml(app, status, warning): def test_html_with_set_translator_for_pseudoxml(app, status, warning):
translator_class = app.builder.translator_class translator_class = app.builder.translator_class
assert translator_class assert translator_class

View File

@ -11,45 +11,60 @@
from __future__ import print_function from __future__ import print_function
import sys from collections import namedtuple
from six import PY2
from sphinx import apidoc import pytest
from util import with_tempdir, with_app, rootdir from sphinx.apidoc import main as apidoc_main
from util import rootdir, remove_unicode_literals
@with_tempdir @pytest.fixture()
def test_simple(tempdir): def apidoc(tempdir, apidoc_params):
codedir = rootdir / 'root' _, kwargs = apidoc_params
coderoot = kwargs.get('coderoot', (rootdir / 'root'))
outdir = tempdir / 'out' outdir = tempdir / 'out'
args = ['sphinx-apidoc', '-o', outdir, '-F', codedir] args = ['sphinx-apidoc', '-o', outdir, '-F', coderoot] + kwargs.get('options', [])
apidoc.main(args) apidoc_main(args)
return namedtuple('apidoc', 'coderoot,outdir')(coderoot, outdir)
@pytest.fixture
def apidoc_params(request):
markers = request.node.get_marker("apidoc")
pargs = {}
kwargs = {}
if markers is not None:
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())]
return args, kwargs
@pytest.mark.apidoc(coderoot=(rootdir / 'root'))
def test_simple(make_app, apidoc):
outdir = apidoc.outdir
assert (outdir / 'conf.py').isfile() assert (outdir / 'conf.py').isfile()
assert (outdir / 'autodoc_fodder.rst').isfile() assert (outdir / 'autodoc_fodder.rst').isfile()
assert (outdir / 'index.rst').isfile() assert (outdir / 'index.rst').isfile()
@with_app('text', srcdir=outdir) app = make_app('text', srcdir=outdir)
def assert_build(app, status, warning): app.build()
app.build() print(app._status.getvalue())
print(status.getvalue()) print(app._warning.getvalue())
print(warning.getvalue())
sys.path.append(codedir)
try:
assert_build()
finally:
sys.path.remove(codedir)
@with_tempdir @pytest.mark.apidoc(
def test_pep_0420_enabled(tempdir): coderoot=(rootdir / 'root' / 'pep_0420'),
codedir = rootdir / 'root' / 'pep_0420' options=["--implicit-namespaces"],
outdir = tempdir / 'out' )
args = ['sphinx-apidoc', '-o', outdir, '-F', codedir, "--implicit-namespaces"] def test_pep_0420_enabled(make_app, apidoc):
apidoc.main(args) outdir = apidoc.outdir
assert (outdir / 'conf.py').isfile() assert (outdir / 'conf.py').isfile()
assert (outdir / 'a.b.c.rst').isfile() assert (outdir / 'a.b.c.rst').isfile()
assert (outdir / 'a.b.x.rst').isfile() assert (outdir / 'a.b.x.rst').isfile()
@ -66,49 +81,28 @@ def test_pep_0420_enabled(tempdir):
assert "automodule:: a.b.x.y\n" in rst assert "automodule:: a.b.x.y\n" in rst
assert "automodule:: a.b.x\n" not in rst assert "automodule:: a.b.x\n" not in rst
@with_app('text', srcdir=outdir) app = make_app('text', srcdir=outdir)
def assert_build(app, status, warning): app.build()
app.build() print(app._status.getvalue())
print(status.getvalue()) print(app._warning.getvalue())
print(warning.getvalue())
sys.path.append(codedir)
try:
assert_build()
finally:
sys.path.remove(codedir)
@with_tempdir @pytest.mark.apidoc(coderoot=(rootdir / 'root' / 'pep_0420'))
def test_pep_0420_disabled(tempdir): def test_pep_0420_disabled(make_app, apidoc):
codedir = rootdir / 'root' / 'pep_0420' outdir = apidoc.outdir
outdir = tempdir / 'out'
args = ['sphinx-apidoc', '-o', outdir, '-F', codedir]
apidoc.main(args)
assert (outdir / 'conf.py').isfile() assert (outdir / 'conf.py').isfile()
assert not (outdir / 'a.b.c.rst').exists() assert not (outdir / 'a.b.c.rst').exists()
assert not (outdir / 'a.b.x.rst').exists() assert not (outdir / 'a.b.x.rst').exists()
@with_app('text', srcdir=outdir) app = make_app('text', srcdir=outdir)
def assert_build(app, status, warning): app.build()
app.build() print(app._status.getvalue())
print(status.getvalue()) print(app._warning.getvalue())
print(warning.getvalue())
sys.path.append(codedir)
try:
assert_build()
finally:
sys.path.remove(codedir)
@with_tempdir
def test_pep_0420_disabled_top_level_verify(tempdir):
codedir = rootdir / 'root' / 'pep_0420' / 'a' / 'b'
outdir = tempdir / 'out'
args = ['sphinx-apidoc', '-o', outdir, '-F', codedir]
apidoc.main(args)
@pytest.mark.apidoc(coderoot=(rootdir / 'root' / 'pep_0420' / 'a' / 'b'))
def test_pep_0420_disabled_top_level_verify(make_app, apidoc):
outdir = apidoc.outdir
assert (outdir / 'conf.py').isfile() assert (outdir / 'conf.py').isfile()
assert (outdir / 'c.rst').isfile() assert (outdir / 'c.rst').isfile()
assert not (outdir / 'x.rst').exists() assert not (outdir / 'x.rst').exists()
@ -119,53 +113,35 @@ def test_pep_0420_disabled_top_level_verify(tempdir):
assert "automodule:: c.d\n" in rst assert "automodule:: c.d\n" in rst
assert "automodule:: c\n" in rst assert "automodule:: c\n" in rst
@with_app('text', srcdir=outdir) app = make_app('text', srcdir=outdir)
def assert_build(app, status, warning): app.build()
app.build() print(app._status.getvalue())
print(status.getvalue()) print(app._warning.getvalue())
print(warning.getvalue())
sys.path.append(codedir)
try:
assert_build()
finally:
sys.path.remove(codedir)
@with_tempdir
def test_multibyte_parameters(tempdir):
codedir = rootdir / 'root'
outdir = tempdir / 'out'
args = ['sphinx-apidoc', '-o', outdir, '-F', codedir,
'--doc-project', u'プロジェクト名'.encode('utf-8'),
'--doc-author', u'著者名'.encode('utf-8'),
'--doc-version', u'バージョン'.encode('utf-8'),
'--doc-release', u'リリース'.encode('utf-8')]
apidoc.main(args)
@pytest.mark.apidoc(
coderoot=(rootdir / 'root'),
options=[
'--doc-project', u'プロジェクト名'.encode('utf-8'),
'--doc-author', u'著者名'.encode('utf-8'),
'--doc-version', u'バージョン'.encode('utf-8'),
'--doc-release', u'リリース'.encode('utf-8'),
],
)
def test_multibyte_parameters(make_app, apidoc):
outdir = apidoc.outdir
assert (outdir / 'conf.py').isfile() assert (outdir / 'conf.py').isfile()
assert (outdir / 'autodoc_fodder.rst').isfile() assert (outdir / 'autodoc_fodder.rst').isfile()
assert (outdir / 'index.rst').isfile() assert (outdir / 'index.rst').isfile()
conf_py = (outdir / 'conf.py').text() conf_py = (outdir / 'conf.py').text()
if PY2: conf_py_ = remove_unicode_literals(conf_py)
assert u"project = u'プロジェクト名'" in conf_py assert u"project = 'プロジェクト名'" in conf_py_
assert u"author = u'著者名'" in conf_py assert u"author = '著者名'" in conf_py_
assert u"version = u'バージョン'" in conf_py assert u"version = 'バージョン'" in conf_py_
assert u"release = u'リリース'" in conf_py assert u"release = 'リリース'" in conf_py_
else:
assert u"project = 'プロジェクト名'" in conf_py
assert u"author = '著者名'" in conf_py
assert u"version = 'バージョン'" in conf_py
assert u"release = 'リリース'" in conf_py
@with_app('text', srcdir=outdir) app = make_app('text', srcdir=outdir)
def assert_build(app, status, warning): app.build()
app.build() print(app._status.getvalue())
print(status.getvalue()) print(app._warning.getvalue())
print(warning.getvalue())
sys.path.append(codedir)
try:
assert_build()
finally:
sys.path.remove(codedir)

View File

@ -8,25 +8,28 @@
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS. :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
import codecs
from docutils import nodes 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 with_app, raises_msg, strip_escseq from util import strip_escseq
import pytest
@with_app()
def test_events(app, status, warning): def test_events(app, status, warning):
def empty(): def empty():
pass pass
raises_msg(ExtensionError, "Unknown event name: invalid", with pytest.raises(ExtensionError) as excinfo:
app.connect, "invalid", empty) app.connect("invalid", empty)
assert "Unknown event name: invalid" in str(excinfo.value)
app.add_event("my_event") app.add_event("my_event")
raises_msg(ExtensionError, "Event 'my_event' already present", with pytest.raises(ExtensionError) as excinfo:
app.add_event, "my_event") app.add_event("my_event")
assert "Event 'my_event' already present" in str(excinfo.value)
def mock_callback(a_app, *args): def mock_callback(a_app, *args):
assert a_app is app assert a_app is app
@ -41,26 +44,22 @@ def test_events(app, status, warning):
"Callback called when disconnected" "Callback called when disconnected"
@with_app()
def test_emit_with_nonascii_name_node(app, status, warning): def test_emit_with_nonascii_name_node(app, status, warning):
node = nodes.section(names=[u'\u65e5\u672c\u8a9e']) node = nodes.section(names=[u'\u65e5\u672c\u8a9e'])
app.emit('my_event', node) app.emit('my_event', node)
@with_app()
def test_extensions(app, status, warning): def test_extensions(app, status, warning):
app.setup_extension('shutil') app.setup_extension('shutil')
assert strip_escseq(warning.getvalue()).startswith("WARNING: extension 'shutil'") assert strip_escseq(warning.getvalue()).startswith("WARNING: extension 'shutil'")
@with_app()
def test_extension_in_blacklist(app, status, warning): def test_extension_in_blacklist(app, status, warning):
app.setup_extension('sphinxjp.themecore') app.setup_extension('sphinxjp.themecore')
msg = strip_escseq(warning.getvalue()) msg = strip_escseq(warning.getvalue())
assert msg.startswith("WARNING: the extension 'sphinxjp.themecore' was") assert msg.startswith("WARNING: the extension 'sphinxjp.themecore' was")
@with_app()
def test_domain_override(app, status, warning): def test_domain_override(app, status, warning):
class A(Domain): class A(Domain):
name = 'foo' name = 'foo'
@ -72,15 +71,18 @@ def test_domain_override(app, status, warning):
name = 'foo' name = 'foo'
# No domain know named foo. # No domain know named foo.
raises_msg(ExtensionError, 'domain foo not yet registered', with pytest.raises(ExtensionError) as excinfo:
app.override_domain, A) app.override_domain(A)
assert 'domain foo not yet registered' in str(excinfo.value)
assert app.add_domain(A) is None assert app.add_domain(A) is None
assert app.override_domain(B) is None assert app.override_domain(B) is None
raises_msg(ExtensionError, 'new domain not a subclass of registered ' with pytest.raises(ExtensionError) as excinfo:
'foo domain', app.override_domain, C) app.override_domain(C)
assert 'new domain not a subclass of registered foo domain' in str(excinfo.value)
@with_app(testroot='add_source_parser') @pytest.mark.sphinx(testroot='add_source_parser')
def test_add_source_parser(app, status, warning): def test_add_source_parser(app, status, warning):
assert set(app.config.source_suffix) == set(['.rst', '.md', '.test']) assert set(app.config.source_suffix) == set(['.rst', '.md', '.test'])
assert set(app.config.source_parsers.keys()) == set(['.md', '.test']) assert set(app.config.source_parsers.keys()) == set(['.md', '.test'])
@ -88,7 +90,7 @@ def test_add_source_parser(app, status, warning):
assert app.config.source_parsers['.test'].__name__ == 'TestSourceParser' assert app.config.source_parsers['.test'].__name__ == 'TestSourceParser'
@with_app(testroot='add_source_parser-conflicts-with-users-setting') @pytest.mark.sphinx(testroot='add_source_parser-conflicts-with-users-setting')
def test_add_source_parser_conflicts_with_users_setting(app, status, warning): def test_add_source_parser_conflicts_with_users_setting(app, status, warning):
assert set(app.config.source_suffix) == set(['.rst', '.test']) assert set(app.config.source_suffix) == set(['.rst', '.test'])
assert set(app.config.source_parsers.keys()) == set(['.test']) assert set(app.config.source_parsers.keys()) == set(['.test'])

View File

@ -12,7 +12,7 @@
# "raises" imported for usage by autodoc # "raises" imported for usage by autodoc
from util import TestApp, Struct, raises, SkipTest # NOQA from util import TestApp, Struct, raises, SkipTest # NOQA
from nose.tools import with_setup, eq_ import pytest
import enum import enum
from six import StringIO, add_metaclass from six import StringIO, add_metaclass
@ -41,6 +41,7 @@ def teardown_module():
directive = options = None directive = options = None
@pytest.fixture
def setup_test(): def setup_test():
global options, directive global options, directive
global processed_docstrings, processed_signatures, _warnings global processed_docstrings, processed_signatures, _warnings
@ -74,6 +75,10 @@ def setup_test():
processed_signatures = [] processed_signatures = []
_warnings = [] _warnings = []
yield
AutoDirective._special_attrgetters.clear()
_warnings = [] _warnings = []
processed_docstrings = [] processed_docstrings = []
@ -105,7 +110,7 @@ def skip_member(app, what, name, obj, skip, options):
return True return True
@with_setup(setup_test) @pytest.mark.usefixtures('setup_test')
def test_parse_name(): def test_parse_name():
def verify(objtype, name, result): def verify(objtype, name, result):
inst = AutoDirective._registry[objtype](directive, name) inst = AutoDirective._registry[objtype](directive, name)
@ -147,7 +152,7 @@ def test_parse_name():
del directive.env.temp_data['autodoc:class'] del directive.env.temp_data['autodoc:class']
@with_setup(setup_test) @pytest.mark.usefixtures('setup_test')
def test_format_signature(): def test_format_signature():
def formatsig(objtype, name, obj, args, retann): def formatsig(objtype, name, obj, args, retann):
inst = AutoDirective._registry[objtype](directive, name) inst = AutoDirective._registry[objtype](directive, name)
@ -253,7 +258,7 @@ def test_format_signature():
'(b, c=42, *d, **e)' '(b, c=42, *d, **e)'
@with_setup(setup_test) @pytest.mark.usefixtures('setup_test')
def test_get_doc(): def test_get_doc():
def getdocl(objtype, obj, encoding=None): def getdocl(objtype, obj, encoding=None):
inst = AutoDirective._registry[objtype](directive, 'tmp') inst = AutoDirective._registry[objtype](directive, 'tmp')
@ -423,7 +428,7 @@ def test_get_doc():
assert getdocl('class', I) == ['Class docstring', '', 'New docstring'] assert getdocl('class', I) == ['Class docstring', '', 'New docstring']
@with_setup(setup_test) @pytest.mark.usefixtures('setup_test')
def test_docstring_processing(): def test_docstring_processing():
def process(objtype, name, obj): def process(objtype, name, obj):
inst = AutoDirective._registry[objtype](directive, name) inst = AutoDirective._registry[objtype](directive, name)
@ -478,7 +483,7 @@ def test_docstring_processing():
app.disconnect(lid) app.disconnect(lid)
@with_setup(setup_test) @pytest.mark.usefixtures('setup_test')
def test_docstring_property_processing(): def test_docstring_property_processing():
def genarate_docstring(objtype, name, **kw): def genarate_docstring(objtype, name, **kw):
del processed_docstrings[:] del processed_docstrings[:]
@ -515,7 +520,7 @@ def test_docstring_property_processing():
assert 'Second line of docstring' in docstrings assert 'Second line of docstring' in docstrings
@with_setup(setup_test) @pytest.mark.usefixtures('setup_test')
def test_new_documenter(): def test_new_documenter():
class MyDocumenter(ModuleLevelDocumenter): class MyDocumenter(ModuleLevelDocumenter):
objtype = 'integer' objtype = 'integer'
@ -543,7 +548,7 @@ def test_new_documenter():
assert_result_contains('.. py:data:: integer', 'module', 'test_autodoc') assert_result_contains('.. py:data:: integer', 'module', 'test_autodoc')
@with_setup(setup_test, AutoDirective._special_attrgetters.clear) @pytest.mark.usefixtures('setup_test')
def test_attrgetter_using(): def test_attrgetter_using():
def assert_getter_works(objtype, name, obj, attrs=[], **kw): def assert_getter_works(objtype, name, obj, attrs=[], **kw):
getattr_spy = [] getattr_spy = []
@ -575,7 +580,7 @@ def test_attrgetter_using():
assert_getter_works('class', 'test_autodoc.Class', Class, ['meth', 'inheritedmeth']) assert_getter_works('class', 'test_autodoc.Class', Class, ['meth', 'inheritedmeth'])
@with_setup(setup_test) @pytest.mark.usefixtures('setup_test')
def test_generate(): def test_generate():
def assert_warns(warn_str, objtype, name, **kw): def assert_warns(warn_str, objtype, name, **kw):
inst = AutoDirective._registry[objtype](directive, name) inst = AutoDirective._registry[objtype](directive, name)
@ -1084,7 +1089,7 @@ def test_type_hints():
raise SkipTest('Cannot import Python code with function annotations') raise SkipTest('Cannot import Python code with function annotations')
def verify_arg_spec(f, expected): def verify_arg_spec(f, expected):
eq_(formatargspec(f, *getargspec(f)), expected) assert formatargspec(f, *getargspec(f)) == expected
# Class annotations # Class annotations
verify_arg_spec(f0, '(x: int, y: numbers.Integral) -> None') verify_arg_spec(f0, '(x: int, y: numbers.Integral) -> None')

View File

@ -9,16 +9,15 @@
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
from six import BytesIO
import pickle import pickle
from docutils import nodes from docutils import nodes
import mock import mock
import pytest
from textwrap import dedent from textwrap import dedent
from sphinx.errors import SphinxError from sphinx.errors import SphinxError
import sphinx.builders.linkcheck import sphinx.builders.linkcheck
from util import with_app, with_tempdir, rootdir, tempdir, SkipTest, TestApp, path from util import rootdir, tempdir, SkipTest, TestApp, path
try: try:
from docutils.writers.manpage import Writer as ManWriter from docutils.writers.manpage import Writer as ManWriter
@ -77,13 +76,12 @@ def test_build_all():
yield verify_build, buildername, srcdir yield verify_build, buildername, srcdir
@with_tempdir def test_master_doc_not_found(tempdir):
def test_master_doc_not_found(tmpdir): (tempdir / 'conf.py').write_text('master_doc = "index"')
(tmpdir / 'conf.py').write_text('master_doc = "index"') assert tempdir.listdir() == ['conf.py']
assert tmpdir.listdir() == ['conf.py']
try: try:
app = TestApp(buildername='dummy', srcdir=tmpdir) app = TestApp(buildername='dummy', srcdir=tempdir)
app.builder.build_all() app.builder.build_all()
assert False # SphinxError not raised assert False # SphinxError not raised
except Exception as exc: except Exception as exc:
@ -92,7 +90,7 @@ def test_master_doc_not_found(tmpdir):
app.cleanup() app.cleanup()
@with_app(buildername='text', testroot='circular') @pytest.mark.sphinx(buildername='text', testroot='circular')
def test_circular_toctree(app, status, warning): def test_circular_toctree(app, status, warning):
app.builder.build_all() app.builder.build_all()
warnings = warning.getvalue() warnings = warning.getvalue()
@ -104,7 +102,7 @@ def test_circular_toctree(app, status, warning):
'contents <- sub <- contents') in warnings 'contents <- sub <- contents') in warnings
@with_app(buildername='text', testroot='numbered-circular') @pytest.mark.sphinx(buildername='text', testroot='numbered-circular')
def test_numbered_circular_toctree(app, status, warning): def test_numbered_circular_toctree(app, status, warning):
app.builder.build_all() app.builder.build_all()
warnings = warning.getvalue() warnings = warning.getvalue()
@ -116,7 +114,7 @@ def test_numbered_circular_toctree(app, status, warning):
'contents <- sub <- contents') in warnings 'contents <- sub <- contents') in warnings
@with_app(buildername='dummy', testroot='image-glob') @pytest.mark.sphinx(buildername='dummy', testroot='image-glob')
def test_image_glob(app, status, warning): def test_image_glob(app, status, warning):
app.builder.build_all() app.builder.build_all()

View File

@ -13,7 +13,7 @@
import plistlib import plistlib
from util import with_app import pytest
from path import path from path import path
# Use plistlib.load in 3.4 and above # Use plistlib.load in 3.4 and above
@ -43,9 +43,10 @@ def check_localization(outdir):
assert (lprojdir / 'localized.txt').isfile() assert (lprojdir / 'localized.txt').isfile()
@with_app(buildername='applehelp', testroot='basic', srcdir='applehelp_output', @pytest.mark.sphinx(
confoverrides={'applehelp_bundle_id': 'org.sphinx-doc.Sphinx.help', 'applehelp', testroot='basic', srcdir='applehelp_output',
'applehelp_disable_external_tools': True}) confoverrides={'applehelp_bundle_id': 'org.sphinx-doc.Sphinx.help',
'applehelp_disable_external_tools': True})
def test_applehelp_output(app, status, warning): def test_applehelp_output(app, status, warning):
(app.srcdir / 'en.lproj').makedirs() (app.srcdir / 'en.lproj').makedirs()
(app.srcdir / 'en.lproj' / 'localized.txt').write_text('') (app.srcdir / 'en.lproj' / 'localized.txt').write_text('')

View File

@ -15,9 +15,11 @@ import re
import gettext import gettext
from subprocess import Popen, PIPE from subprocess import Popen, PIPE
from nose.tools import assert_true, assert_equal import pytest
from util import with_app, gen_with_app, SkipTest, assert_in from util import (
gen_with_app, SkipTest, assert_in, assert_true, assert_equal
)
@gen_with_app('gettext', srcdir='root-gettext') @gen_with_app('gettext', srcdir='root-gettext')
@ -76,8 +78,9 @@ def test_all(app, status, warning):
yield assert_equal, _("Testing various markup"), u"Testing various markup" yield assert_equal, _("Testing various markup"), u"Testing various markup"
@with_app('gettext', testroot='intl', @pytest.mark.sphinx(
confoverrides={'gettext_compact': False}) 'gettext', testroot='intl', srcdir='gettext',
confoverrides={'gettext_compact': False})
def test_gettext_index_entries(app, status, warning): def test_gettext_index_entries(app, status, warning):
# regression test for #976 # regression test for #976
app.builder.build(['index_entries']) app.builder.build(['index_entries'])
@ -123,8 +126,9 @@ def test_gettext_index_entries(app, status, warning):
assert msgids == [] assert msgids == []
@with_app('gettext', testroot='intl', @pytest.mark.sphinx(
confoverrides={'gettext_compact': False, 'gettext_additional_targets': []}) 'gettext', testroot='intl', srcdir='gettext',
confoverrides={'gettext_compact': False, 'gettext_additional_targets': []})
def test_gettext_disable_index_entries(app, status, warning): def test_gettext_disable_index_entries(app, status, warning):
# regression test for #976 # regression test for #976
app.builder.build(['index_entries']) app.builder.build(['index_entries'])
@ -155,7 +159,7 @@ def test_gettext_disable_index_entries(app, status, warning):
assert msgids == [] assert msgids == []
@with_app(buildername='gettext', testroot='intl') @pytest.mark.sphinx('gettext', testroot='intl', srcdir='gettext')
def test_gettext_template(app, status, warning): def test_gettext_template(app, status, warning):
app.builder.build_all() app.builder.build_all()
assert (app.outdir / 'sphinx.pot').isfile() assert (app.outdir / 'sphinx.pot').isfile()

View File

@ -15,19 +15,17 @@ import re
from six import PY3, iteritems from six import PY3, iteritems
from sphinx import __display_version__ from sphinx import __display_version__
from util import remove_unicode_literals, gen_with_app, with_app, strip_escseq from util import remove_unicode_literals, gen_with_app, strip_escseq
from etree13 import ElementTree from etree13 import ElementTree
from html5lib import getTreeBuilder, HTMLParser from html5lib import getTreeBuilder, HTMLParser
import pytest
TREE_BUILDER = getTreeBuilder('etree', implementation=ElementTree) TREE_BUILDER = getTreeBuilder('etree', implementation=ElementTree)
HTML_PARSER = HTMLParser(TREE_BUILDER, namespaceHTMLElements=False) HTML_PARSER = HTMLParser(TREE_BUILDER, namespaceHTMLElements=False)
ENV_WARNINGS = """\ ENV_WARNINGS = """\
(%(root)s/autodoc_fodder.py:docstring of autodoc_fodder.MarkupError:\\d+: \ %(root)s/autodoc_fodder.py:docstring of autodoc_fodder.MarkupError:\\d+: \
WARNING: duplicate object description of autodoc_fodder.MarkupError, other \
instance in %(root)s/autodoc.rst, use :noindex: for one of them
)?%(root)s/autodoc_fodder.py:docstring of autodoc_fodder.MarkupError:\\d+: \
WARNING: Explicit markup ends without a blank line; unexpected unindent. WARNING: Explicit markup ends without a blank line; unexpected unindent.
%(root)s/index.rst:\\d+: WARNING: Encoding 'utf-8-sig' used for reading included \ %(root)s/index.rst:\\d+: WARNING: Encoding 'utf-8-sig' used for reading included \
file u'%(root)s/wrongenc.inc' seems to be wrong, try giving an :encoding: option file u'%(root)s/wrongenc.inc' seems to be wrong, try giving an :encoding: option
@ -36,7 +34,7 @@ file u'%(root)s/wrongenc.inc' seems to be wrong, try giving an :encoding: option
%(root)s/index.rst:\\d+: WARNING: download file not readable: %(root)s/nonexisting.png %(root)s/index.rst:\\d+: WARNING: download file not readable: %(root)s/nonexisting.png
%(root)s/index.rst:\\d+: WARNING: invalid single index entry u'' %(root)s/index.rst:\\d+: WARNING: invalid single index entry u''
%(root)s/undecodable.rst:\\d+: WARNING: undecodable source characters, replacing \ %(root)s/undecodable.rst:\\d+: WARNING: undecodable source characters, replacing \
with "\\?": b?'here: >>>(\\\\|/)xbb<<<' with "\\?": b?'here: >>>(\\\\|/)xbb<<<((\\\\|/)r)?'
""" """
HTML_WARNINGS = ENV_WARNINGS + """\ HTML_WARNINGS = ENV_WARNINGS + """\
@ -387,7 +385,7 @@ def check_extra_entries(outdir):
assert (outdir / 'robots.txt').isfile() assert (outdir / 'robots.txt').isfile()
@with_app(buildername='html', testroot='warnings', freshenv=True) @pytest.mark.sphinx('html', testroot='warnings', freshenv=True)
def test_html_warnings(app, status, warning): def test_html_warnings(app, status, warning):
app.builder.build_all() app.builder.build_all()
html_warnings = strip_escseq(warning.getvalue().replace(os.sep, '/')) html_warnings = strip_escseq(warning.getvalue().replace(os.sep, '/'))
@ -662,7 +660,7 @@ def test_numfig_without_numbered_toctree(app, status, warning):
yield check_xpath, etree, fname, xpath, check, be_found yield check_xpath, etree, fname, xpath, check, be_found
@gen_with_app(buildername='html', testroot='numfig', @gen_with_app(buildername='html', testroot='numfig', srcdir='test_build_html_numfig_on',
confoverrides={'numfig': True}) confoverrides={'numfig': True})
def test_numfig_with_numbered_toctree(app, status, warning): def test_numfig_with_numbered_toctree(app, status, warning):
app.builder.build_all() app.builder.build_all()
@ -763,6 +761,7 @@ def test_numfig_with_numbered_toctree(app, status, warning):
@gen_with_app(buildername='html', testroot='numfig', @gen_with_app(buildername='html', testroot='numfig',
srcdir='test_build_html_numfig_format_warn',
confoverrides={'numfig': True, confoverrides={'numfig': True,
'numfig_format': {'figure': 'Figure:%s', 'numfig_format': {'figure': 'Figure:%s',
'table': 'Tab_%s', 'table': 'Tab_%s',
@ -867,6 +866,7 @@ def test_numfig_with_prefix(app, status, warning):
@gen_with_app(buildername='html', testroot='numfig', @gen_with_app(buildername='html', testroot='numfig',
srcdir='test_build_html_numfig_depth_2',
confoverrides={'numfig': True, 'numfig_secnum_depth': 2}) confoverrides={'numfig': True, 'numfig_secnum_depth': 2})
def test_numfig_with_secnum_depth(app, status, warning): def test_numfig_with_secnum_depth(app, status, warning):
app.builder.build_all() app.builder.build_all()
@ -967,6 +967,7 @@ def test_numfig_with_secnum_depth(app, status, warning):
@gen_with_app(buildername='singlehtml', testroot='numfig', @gen_with_app(buildername='singlehtml', testroot='numfig',
srcdir='test_build_html_numfig_on',
confoverrides={'numfig': True}) confoverrides={'numfig': True})
def test_numfig_with_singlehtml(app, status, warning): def test_numfig_with_singlehtml(app, status, warning):
app.builder.build_all() app.builder.build_all()
@ -1084,7 +1085,7 @@ def test_enumerable_node(app, status, warning):
yield check_xpath, etree, fname, xpath, check, be_found yield check_xpath, etree, fname, xpath, check, be_found
@with_app(buildername='html', testroot='html_assets') @pytest.mark.sphinx('html', testroot='html_assets')
def test_html_assets(app, status, warning): def test_html_assets(app, status, warning):
app.builder.build_all() app.builder.build_all()
@ -1112,7 +1113,7 @@ def test_html_assets(app, status, warning):
assert not (app.outdir / 'subdir' / '.htpasswd').exists() assert not (app.outdir / 'subdir' / '.htpasswd').exists()
@with_app(buildername='html', confoverrides={'html_sourcelink_suffix': ''}) @pytest.mark.sphinx('html', confoverrides={'html_sourcelink_suffix': ''})
def test_html_sourcelink_suffix(app, status, warning): def test_html_sourcelink_suffix(app, status, warning):
app.builder.build_all() app.builder.build_all()
content_otherext = (app.outdir / 'otherext.html').text() content_otherext = (app.outdir / 'otherext.html').text()

View File

@ -12,17 +12,17 @@ from __future__ import print_function
import os import os
import re import re
from functools import wraps
from itertools import product from itertools import product
from subprocess import Popen, PIPE from subprocess import Popen, PIPE
from six import PY3 from six import PY3
import pytest
from sphinx.errors import SphinxError from sphinx.errors import SphinxError
from sphinx.util.osutil import cd, ensuredir from sphinx.util.osutil import cd, ensuredir
from sphinx.writers.latex import LaTeXTranslator from sphinx.writers.latex import LaTeXTranslator
from util import SkipTest, remove_unicode_literals, with_app, strip_escseq, skip_if from util import SkipTest, remove_unicode_literals, strip_escseq, skip_if
from test_build_html import ENV_WARNINGS from test_build_html import ENV_WARNINGS
@ -90,14 +90,13 @@ def skip_if_stylefiles_notfound(testfunc):
return testfunc return testfunc
def test_latex():
for engine, docclass in product(LATEX_ENGINES, DOCCLASSES):
yield build_latex_doc, engine, docclass
@skip_if_stylefiles_notfound @skip_if_stylefiles_notfound
@with_app(buildername='latex') @pytest.mark.parametrize(
def build_latex_doc(app, status, warning, engine, docclass): "engine,docclass",
product(LATEX_ENGINES, DOCCLASSES),
)
@pytest.mark.sphinx('latex')
def test_build_latex_doc(app, status, warning, engine, docclass):
app.config.latex_engine = engine app.config.latex_engine = engine
app.config.latex_documents[0] = app.config.latex_documents[0][:4] + (docclass,) app.config.latex_documents[0] = app.config.latex_documents[0][:4] + (docclass,)
@ -110,7 +109,7 @@ def build_latex_doc(app, status, warning, engine, docclass):
compile_latex_document(app) compile_latex_document(app)
@with_app(buildername='latex') @pytest.mark.sphinx('latex')
def test_writer(app, status, warning): def test_writer(app, status, warning):
app.builder.build_all() app.builder.build_all()
result = (app.outdir / 'SphinxTests.tex').text(encoding='utf8') result = (app.outdir / 'SphinxTests.tex').text(encoding='utf8')
@ -138,7 +137,7 @@ def test_writer(app, status, warning):
'\\end{wrapfigure}' in result) '\\end{wrapfigure}' in result)
@with_app(buildername='latex', testroot='warnings', freshenv=True) @pytest.mark.sphinx('latex', testroot='warnings', freshenv=True)
def test_latex_warnings(app, status, warning): def test_latex_warnings(app, status, warning):
app.builder.build_all() app.builder.build_all()
@ -151,7 +150,7 @@ def test_latex_warnings(app, status, warning):
'--- Got:\n' + warnings '--- Got:\n' + warnings
@with_app(buildername='latex', testroot='basic') @pytest.mark.sphinx('latex', testroot='basic')
def test_latex_title(app, status, warning): def test_latex_title(app, status, warning):
app.builder.build_all() app.builder.build_all()
result = (app.outdir / 'test.tex').text(encoding='utf8') result = (app.outdir / 'test.tex').text(encoding='utf8')
@ -161,7 +160,7 @@ def test_latex_title(app, status, warning):
assert '\\title{The basic Sphinx documentation for testing}' in result assert '\\title{The basic Sphinx documentation for testing}' in result
@with_app(buildername='latex', testroot='latex-title') @pytest.mark.sphinx('latex', testroot='latex-title')
def test_latex_title_after_admonitions(app, status, warning): def test_latex_title_after_admonitions(app, status, warning):
app.builder.build_all() app.builder.build_all()
result = (app.outdir / 'test.tex').text(encoding='utf8') result = (app.outdir / 'test.tex').text(encoding='utf8')
@ -171,7 +170,7 @@ def test_latex_title_after_admonitions(app, status, warning):
assert '\\title{test-latex-title}' in result assert '\\title{test-latex-title}' in result
@with_app(buildername='latex', testroot='numfig', @pytest.mark.sphinx('latex', testroot='numfig',
confoverrides={'numfig': True}) confoverrides={'numfig': True})
def test_numref(app, status, warning): def test_numref(app, status, warning):
app.builder.build_all() app.builder.build_all()
@ -204,12 +203,13 @@ def test_numref(app, status, warning):
'\\nameref{\\detokenize{foo:foo}}}') in result '\\nameref{\\detokenize{foo:foo}}}') in result
@with_app(buildername='latex', testroot='numfig', @pytest.mark.sphinx(
confoverrides={'numfig': True, 'latex', testroot='numfig',
'numfig_format': {'figure': 'Figure:%s', confoverrides={'numfig': True,
'table': 'Tab_%s', 'numfig_format': {'figure': 'Figure:%s',
'code-block': 'Code-%s', 'table': 'Tab_%s',
'section': 'SECTION-%s'}}) 'code-block': 'Code-%s',
'section': 'SECTION-%s'}})
def test_numref_with_prefix1(app, status, warning): def test_numref_with_prefix1(app, status, warning):
app.builder.build_all() app.builder.build_all()
result = (app.outdir / 'Python.tex').text(encoding='utf8') result = (app.outdir / 'Python.tex').text(encoding='utf8')
@ -247,12 +247,13 @@ def test_numref_with_prefix1(app, status, warning):
'\\nameref{\\detokenize{foo:foo}}}') in result '\\nameref{\\detokenize{foo:foo}}}') in result
@with_app(buildername='latex', testroot='numfig', @pytest.mark.sphinx(
confoverrides={'numfig': True, 'latex', testroot='numfig',
'numfig_format': {'figure': 'Figure:%s.', confoverrides={'numfig': True,
'table': 'Tab_%s:', 'numfig_format': {'figure': 'Figure:%s.',
'code-block': 'Code-%s | ', 'table': 'Tab_%s:',
'section': 'SECTION_%s_'}}) 'code-block': 'Code-%s | ',
'section': 'SECTION_%s_'}})
def test_numref_with_prefix2(app, status, warning): def test_numref_with_prefix2(app, status, warning):
app.builder.build_all() app.builder.build_all()
result = (app.outdir / 'Python.tex').text(encoding='utf8') result = (app.outdir / 'Python.tex').text(encoding='utf8')
@ -286,8 +287,9 @@ def test_numref_with_prefix2(app, status, warning):
'\\nameref{\\detokenize{foo:foo}}}') in result '\\nameref{\\detokenize{foo:foo}}}') in result
@with_app(buildername='latex', testroot='numfig', @pytest.mark.sphinx(
confoverrides={'numfig': True, 'language': 'ja'}) 'latex', testroot='numfig',
confoverrides={'numfig': True, 'language': 'ja'})
def test_numref_with_language_ja(app, status, warning): def test_numref_with_language_ja(app, status, warning):
app.builder.build_all() app.builder.build_all()
result = (app.outdir / 'Python.tex').text(encoding='utf8') result = (app.outdir / 'Python.tex').text(encoding='utf8')
@ -319,7 +321,7 @@ def test_numref_with_language_ja(app, status, warning):
'\\nameref{\\detokenize{foo:foo}}}') in result '\\nameref{\\detokenize{foo:foo}}}') in result
@with_app(buildername='latex') @pytest.mark.sphinx('latex')
def test_latex_add_latex_package(app, status, warning): def test_latex_add_latex_package(app, status, warning):
app.add_latex_package('foo') app.add_latex_package('foo')
app.add_latex_package('bar', 'baz') app.add_latex_package('bar', 'baz')
@ -329,7 +331,7 @@ def test_latex_add_latex_package(app, status, warning):
assert '\\usepackage[baz]{bar}' in result assert '\\usepackage[baz]{bar}' in result
@with_app(buildername='latex', testroot='latex-babel') @pytest.mark.sphinx('latex', testroot='latex-babel')
def test_babel_with_no_language_settings(app, status, warning): def test_babel_with_no_language_settings(app, status, warning):
app.builder.build_all() app.builder.build_all()
result = (app.outdir / 'Python.tex').text(encoding='utf8') result = (app.outdir / 'Python.tex').text(encoding='utf8')
@ -348,8 +350,9 @@ def test_babel_with_no_language_settings(app, status, warning):
assert '\\shorthandoff' not in result assert '\\shorthandoff' not in result
@with_app(buildername='latex', testroot='latex-babel', @pytest.mark.sphinx(
confoverrides={'language': 'de'}) 'latex', testroot='latex-babel',
confoverrides={'language': 'de'})
def test_babel_with_language_de(app, status, warning): def test_babel_with_language_de(app, status, warning):
app.builder.build_all() app.builder.build_all()
result = (app.outdir / 'Python.tex').text(encoding='utf8') result = (app.outdir / 'Python.tex').text(encoding='utf8')
@ -368,8 +371,9 @@ def test_babel_with_language_de(app, status, warning):
assert '\\shorthandoff{"}' in result assert '\\shorthandoff{"}' in result
@with_app(buildername='latex', testroot='latex-babel', @pytest.mark.sphinx(
confoverrides={'language': 'ru'}) 'latex', testroot='latex-babel',
confoverrides={'language': 'ru'})
def test_babel_with_language_ru(app, status, warning): def test_babel_with_language_ru(app, status, warning):
app.builder.build_all() app.builder.build_all()
result = (app.outdir / 'Python.tex').text(encoding='utf8') result = (app.outdir / 'Python.tex').text(encoding='utf8')
@ -389,8 +393,9 @@ def test_babel_with_language_ru(app, status, warning):
assert '\\shorthandoff' not in result assert '\\shorthandoff' not in result
@with_app(buildername='latex', testroot='latex-babel', @pytest.mark.sphinx(
confoverrides={'language': 'tr'}) 'latex', testroot='latex-babel',
confoverrides={'language': 'tr'})
def test_babel_with_language_tr(app, status, warning): def test_babel_with_language_tr(app, status, warning):
app.builder.build_all() app.builder.build_all()
result = (app.outdir / 'Python.tex').text(encoding='utf8') result = (app.outdir / 'Python.tex').text(encoding='utf8')
@ -409,8 +414,9 @@ def test_babel_with_language_tr(app, status, warning):
assert '\\shorthandoff{=}' in result assert '\\shorthandoff{=}' in result
@with_app(buildername='latex', testroot='latex-babel', @pytest.mark.sphinx(
confoverrides={'language': 'ja'}) 'latex', testroot='latex-babel',
confoverrides={'language': 'ja'})
def test_babel_with_language_ja(app, status, warning): def test_babel_with_language_ja(app, status, warning):
app.builder.build_all() app.builder.build_all()
result = (app.outdir / 'Python.tex').text(encoding='utf8') result = (app.outdir / 'Python.tex').text(encoding='utf8')
@ -428,8 +434,9 @@ def test_babel_with_language_ja(app, status, warning):
assert '\\shorthandoff' not in result assert '\\shorthandoff' not in result
@with_app(buildername='latex', testroot='latex-babel', @pytest.mark.sphinx(
confoverrides={'language': 'unknown'}) 'latex', testroot='latex-babel',
confoverrides={'language': 'unknown'})
def test_babel_with_unknown_language(app, status, warning): def test_babel_with_unknown_language(app, status, warning):
app.builder.build_all() app.builder.build_all()
result = (app.outdir / 'Python.tex').text(encoding='utf8') result = (app.outdir / 'Python.tex').text(encoding='utf8')
@ -450,7 +457,7 @@ def test_babel_with_unknown_language(app, status, warning):
assert "WARNING: no Babel option known for language 'unknown'" in warning.getvalue() assert "WARNING: no Babel option known for language 'unknown'" in warning.getvalue()
@with_app(buildername='latex') @pytest.mark.sphinx('latex')
def test_footnote(app, status, warning): def test_footnote(app, status, warning):
app.builder.build_all() app.builder.build_all()
result = (app.outdir / 'SphinxTests.tex').text(encoding='utf8') result = (app.outdir / 'SphinxTests.tex').text(encoding='utf8')
@ -480,7 +487,7 @@ def test_footnote(app, status, warning):
'footnotes in table\n%\n\\end{footnotetext}') in result 'footnotes in table\n%\n\\end{footnotetext}') in result
@with_app(buildername='latex', testroot='footnotes') @pytest.mark.sphinx('latex', testroot='footnotes')
def test_reference_in_caption_and_codeblock_in_footnote(app, status, warning): def test_reference_in_caption_and_codeblock_in_footnote(app, status, warning):
app.builder.build_all() app.builder.build_all()
result = (app.outdir / 'Python.tex').text(encoding='utf8') result = (app.outdir / 'Python.tex').text(encoding='utf8')
@ -517,8 +524,9 @@ def test_reference_in_caption_and_codeblock_in_footnote(app, status, warning):
assert '\\begin{sphinxVerbatim}[commandchars=\\\\\\{\\}]' in result assert '\\begin{sphinxVerbatim}[commandchars=\\\\\\{\\}]' in result
@with_app(buildername='latex', testroot='footnotes', @pytest.mark.sphinx(
confoverrides={'latex_show_urls': 'inline'}) 'latex', testroot='footnotes',
confoverrides={'latex_show_urls': 'inline'})
def test_latex_show_urls_is_inline(app, status, warning): def test_latex_show_urls_is_inline(app, status, warning):
app.builder.build_all() app.builder.build_all()
result = (app.outdir / 'Python.tex').text(encoding='utf8') result = (app.outdir / 'Python.tex').text(encoding='utf8')
@ -560,8 +568,9 @@ def test_latex_show_urls_is_inline(app, status, warning):
'{sphinx-dev@googlegroups.com}') in result '{sphinx-dev@googlegroups.com}') in result
@with_app(buildername='latex', testroot='footnotes', @pytest.mark.sphinx(
confoverrides={'latex_show_urls': 'footnote'}) 'latex', testroot='footnotes',
confoverrides={'latex_show_urls': 'footnote'})
def test_latex_show_urls_is_footnote(app, status, warning): def test_latex_show_urls_is_footnote(app, status, warning):
app.builder.build_all() app.builder.build_all()
result = (app.outdir / 'Python.tex').text(encoding='utf8') result = (app.outdir / 'Python.tex').text(encoding='utf8')
@ -611,8 +620,9 @@ def test_latex_show_urls_is_footnote(app, status, warning):
'{sphinx-dev@googlegroups.com}\n') in result '{sphinx-dev@googlegroups.com}\n') in result
@with_app(buildername='latex', testroot='footnotes', @pytest.mark.sphinx(
confoverrides={'latex_show_urls': 'no'}) 'latex', testroot='footnotes',
confoverrides={'latex_show_urls': 'no'})
def test_latex_show_urls_is_no(app, status, warning): def test_latex_show_urls_is_no(app, status, warning):
app.builder.build_all() app.builder.build_all()
result = (app.outdir / 'Python.tex').text(encoding='utf8') result = (app.outdir / 'Python.tex').text(encoding='utf8')
@ -652,7 +662,7 @@ def test_latex_show_urls_is_no(app, status, warning):
'{sphinx-dev@googlegroups.com}\n') in result '{sphinx-dev@googlegroups.com}\n') in result
@with_app(buildername='latex', testroot='image-in-section') @pytest.mark.sphinx('latex', testroot='image-in-section')
def test_image_in_section(app, status, warning): def test_image_in_section(app, status, warning):
app.builder.build_all() app.builder.build_all()
result = (app.outdir / 'Python.tex').text(encoding='utf8') result = (app.outdir / 'Python.tex').text(encoding='utf8')
@ -668,7 +678,7 @@ def test_image_in_section(app, status, warning):
assert ('\\chapter{Another section}' in result) assert ('\\chapter{Another section}' in result)
@with_app(buildername='latex', confoverrides={'latex_logo': 'notfound.jpg'}) @pytest.mark.sphinx('latex', confoverrides={'latex_logo': 'notfound.jpg'})
def test_latex_logo_if_not_found(app, status, warning): def test_latex_logo_if_not_found(app, status, warning):
try: try:
app.builder.build_all() app.builder.build_all()
@ -677,7 +687,7 @@ def test_latex_logo_if_not_found(app, status, warning):
assert isinstance(exc, SphinxError) assert isinstance(exc, SphinxError)
@with_app(buildername='latex', testroot='toctree-maxdepth', @pytest.mark.sphinx('latex', testroot='toctree-maxdepth',
confoverrides={'latex_documents': [ confoverrides={'latex_documents': [
('index', 'SphinxTests.tex', 'Sphinx Tests Documentation', ('index', 'SphinxTests.tex', 'Sphinx Tests Documentation',
'Georg Brandl', 'manual'), 'Georg Brandl', 'manual'),
@ -692,11 +702,12 @@ def test_toctree_maxdepth_manual(app, status, warning):
assert '\\setcounter{secnumdepth}' not in result assert '\\setcounter{secnumdepth}' not in result
@with_app(buildername='latex', testroot='toctree-maxdepth', @pytest.mark.sphinx(
confoverrides={'latex_documents': [ 'latex', testroot='toctree-maxdepth',
('index', 'SphinxTests.tex', 'Sphinx Tests Documentation', confoverrides={'latex_documents': [
'Georg Brandl', 'howto'), ('index', 'SphinxTests.tex', 'Sphinx Tests Documentation',
]}) 'Georg Brandl', 'howto'),
]})
def test_toctree_maxdepth_howto(app, status, warning): def test_toctree_maxdepth_howto(app, status, warning):
app.builder.build_all() app.builder.build_all()
result = (app.outdir / 'SphinxTests.tex').text(encoding='utf8') result = (app.outdir / 'SphinxTests.tex').text(encoding='utf8')
@ -707,8 +718,9 @@ def test_toctree_maxdepth_howto(app, status, warning):
assert '\\setcounter{secnumdepth}' not in result assert '\\setcounter{secnumdepth}' not in result
@with_app(buildername='latex', testroot='toctree-maxdepth', @pytest.mark.sphinx(
confoverrides={'master_doc': 'foo'}) 'latex', testroot='toctree-maxdepth',
confoverrides={'master_doc': 'foo'})
def test_toctree_not_found(app, status, warning): def test_toctree_not_found(app, status, warning):
app.builder.build_all() app.builder.build_all()
result = (app.outdir / 'Python.tex').text(encoding='utf8') result = (app.outdir / 'Python.tex').text(encoding='utf8')
@ -719,8 +731,9 @@ def test_toctree_not_found(app, status, warning):
assert '\\setcounter{secnumdepth}' not in result assert '\\setcounter{secnumdepth}' not in result
@with_app(buildername='latex', testroot='toctree-maxdepth', @pytest.mark.sphinx(
confoverrides={'master_doc': 'bar'}) 'latex', testroot='toctree-maxdepth',
confoverrides={'master_doc': 'bar'})
def test_toctree_without_maxdepth(app, status, warning): def test_toctree_without_maxdepth(app, status, warning):
app.builder.build_all() app.builder.build_all()
result = (app.outdir / 'Python.tex').text(encoding='utf8') result = (app.outdir / 'Python.tex').text(encoding='utf8')
@ -731,8 +744,9 @@ def test_toctree_without_maxdepth(app, status, warning):
assert '\\setcounter{secnumdepth}' not in result assert '\\setcounter{secnumdepth}' not in result
@with_app(buildername='latex', testroot='toctree-maxdepth', @pytest.mark.sphinx(
confoverrides={'master_doc': 'qux'}) 'latex', testroot='toctree-maxdepth',
confoverrides={'master_doc': 'qux'})
def test_toctree_with_deeper_maxdepth(app, status, warning): def test_toctree_with_deeper_maxdepth(app, status, warning):
app.builder.build_all() app.builder.build_all()
result = (app.outdir / 'Python.tex').text(encoding='utf8') result = (app.outdir / 'Python.tex').text(encoding='utf8')
@ -743,8 +757,9 @@ def test_toctree_with_deeper_maxdepth(app, status, warning):
assert '\\setcounter{secnumdepth}{3}' in result assert '\\setcounter{secnumdepth}{3}' in result
@with_app(buildername='latex', testroot='toctree-maxdepth', @pytest.mark.sphinx(
confoverrides={'latex_toplevel_sectioning': None}) 'latex', testroot='toctree-maxdepth',
confoverrides={'latex_toplevel_sectioning': None})
def test_latex_toplevel_sectioning_is_None(app, status, warning): def test_latex_toplevel_sectioning_is_None(app, status, warning):
app.builder.build_all() app.builder.build_all()
result = (app.outdir / 'Python.tex').text(encoding='utf8') result = (app.outdir / 'Python.tex').text(encoding='utf8')
@ -754,8 +769,9 @@ def test_latex_toplevel_sectioning_is_None(app, status, warning):
assert '\\chapter{Foo}' in result assert '\\chapter{Foo}' in result
@with_app(buildername='latex', testroot='toctree-maxdepth', @pytest.mark.sphinx(
confoverrides={'latex_toplevel_sectioning': 'part'}) 'latex', testroot='toctree-maxdepth',
confoverrides={'latex_toplevel_sectioning': 'part'})
def test_latex_toplevel_sectioning_is_part(app, status, warning): def test_latex_toplevel_sectioning_is_part(app, status, warning):
app.builder.build_all() app.builder.build_all()
result = (app.outdir / 'Python.tex').text(encoding='utf8') result = (app.outdir / 'Python.tex').text(encoding='utf8')
@ -765,8 +781,9 @@ def test_latex_toplevel_sectioning_is_part(app, status, warning):
assert '\\part{Foo}' in result assert '\\part{Foo}' in result
@with_app(buildername='latex', testroot='toctree-maxdepth', @pytest.mark.sphinx(
confoverrides={'latex_toplevel_sectioning': 'chapter'}) 'latex', testroot='toctree-maxdepth',
confoverrides={'latex_toplevel_sectioning': 'chapter'})
def test_latex_toplevel_sectioning_is_chapter(app, status, warning): def test_latex_toplevel_sectioning_is_chapter(app, status, warning):
app.builder.build_all() app.builder.build_all()
result = (app.outdir / 'Python.tex').text(encoding='utf8') result = (app.outdir / 'Python.tex').text(encoding='utf8')
@ -776,8 +793,9 @@ def test_latex_toplevel_sectioning_is_chapter(app, status, warning):
assert '\\chapter{Foo}' in result assert '\\chapter{Foo}' in result
@with_app(buildername='latex', testroot='toctree-maxdepth', @pytest.mark.sphinx(
confoverrides={'latex_toplevel_sectioning': 'section'}) 'latex', testroot='toctree-maxdepth',
confoverrides={'latex_toplevel_sectioning': 'section'})
def test_latex_toplevel_sectioning_is_section(app, status, warning): def test_latex_toplevel_sectioning_is_section(app, status, warning):
app.builder.build_all() app.builder.build_all()
result = (app.outdir / 'Python.tex').text(encoding='utf8') result = (app.outdir / 'Python.tex').text(encoding='utf8')
@ -787,7 +805,7 @@ def test_latex_toplevel_sectioning_is_section(app, status, warning):
assert '\\section{Foo}' in result assert '\\section{Foo}' in result
@skip_if_stylefiles_notfound @skip_if_stylefiles_notfound
@with_app(buildername='latex', testroot='maxlistdepth') @pytest.mark.sphinx('latex', testroot='maxlistdepth')
def test_maxlistdepth_at_ten(app, status, warning): def test_maxlistdepth_at_ten(app, status, warning):
app.builder.build_all() app.builder.build_all()
result = (app.outdir / 'SphinxTests.tex').text(encoding='utf8') result = (app.outdir / 'SphinxTests.tex').text(encoding='utf8')

View File

@ -10,10 +10,10 @@
""" """
from __future__ import print_function from __future__ import print_function
from util import with_app import pytest
@with_app('linkcheck', testroot='linkcheck', freshenv=True) @pytest.mark.sphinx('linkcheck', testroot='linkcheck', freshenv=True)
def test_defaults(app, status, warning): def test_defaults(app, status, warning):
app.builder.build_all() app.builder.build_all()
@ -26,8 +26,9 @@ def test_defaults(app, status, warning):
assert len(content.splitlines()) == 1 assert len(content.splitlines()) == 1
@with_app('linkcheck', testroot='linkcheck', freshenv=True, @pytest.mark.sphinx(
confoverrides={'linkcheck_anchors_ignore': ["^!", "^top$"]}) 'linkcheck', testroot='linkcheck', freshenv=True,
confoverrides={'linkcheck_anchors_ignore': ["^!", "^top$"]})
def test_anchors_ignored(app, status, warning): def test_anchors_ignored(app, status, warning):
app.builder.build_all() app.builder.build_all()

View File

@ -10,10 +10,10 @@
""" """
from __future__ import print_function from __future__ import print_function
from util import with_app import pytest
@with_app(buildername='man') @pytest.mark.sphinx('man')
def test_all(app, status, warning): def test_all(app, status, warning):
app.builder.build_all() app.builder.build_all()
assert (app.outdir / 'SphinxTests.1').exists() assert (app.outdir / 'SphinxTests.1').exists()

View File

@ -15,10 +15,11 @@ import re
from subprocess import Popen, PIPE from subprocess import Popen, PIPE
from six import PY3 from six import PY3
import pytest
from sphinx.writers.texinfo import TexinfoTranslator from sphinx.writers.texinfo import TexinfoTranslator
from util import SkipTest, remove_unicode_literals, with_app, strip_escseq from util import SkipTest, remove_unicode_literals, strip_escseq
from test_build_html import ENV_WARNINGS from test_build_html import ENV_WARNINGS
@ -33,7 +34,7 @@ if PY3:
TEXINFO_WARNINGS = remove_unicode_literals(TEXINFO_WARNINGS) TEXINFO_WARNINGS = remove_unicode_literals(TEXINFO_WARNINGS)
@with_app(buildername='texinfo', testroot='warnings', freshenv=True) @pytest.mark.sphinx('texinfo', testroot='warnings', freshenv=True)
def test_texinfo_warnings(app, status, warning): def test_texinfo_warnings(app, status, warning):
app.builder.build_all() app.builder.build_all()
warnings = strip_escseq(warning.getvalue().replace(os.sep, '/')) warnings = strip_escseq(warning.getvalue().replace(os.sep, '/'))
@ -45,7 +46,7 @@ def test_texinfo_warnings(app, status, warning):
'--- Got:\n' + warnings '--- Got:\n' + warnings
@with_app(buildername='texinfo') @pytest.mark.sphinx('texinfo')
def test_texinfo(app, status, warning): def test_texinfo(app, status, warning):
TexinfoTranslator.ignore_missing_images = True TexinfoTranslator.ignore_missing_images = True
app.builder.build_all() app.builder.build_all()

View File

@ -10,15 +10,16 @@
""" """
import shutil import shutil
from nose.tools import with_setup import pytest
from util import with_app, find_files, rootdir, tempdir from util import find_files, rootdir, tempdir
root = tempdir / 'test-intl' root = tempdir / 'test-intl'
build_dir = root / '_build' build_dir = root / '_build'
locale_dir = build_dir / 'locale' locale_dir = build_dir / 'locale'
@pytest.fixture
def setup_test(): def setup_test():
# delete remnants left over after failed build # delete remnants left over after failed build
root.rmtree(True) root.rmtree(True)
@ -30,14 +31,15 @@ def setup_test():
copy_po.parent.makedirs() copy_po.parent.makedirs()
shutil.copy(root / po, copy_po) shutil.copy(root / po, copy_po)
yield
def teardown_test():
build_dir.rmtree(True) build_dir.rmtree(True)
@with_setup(setup_test, teardown_test) @pytest.mark.usefixtures('setup_test')
@with_app(buildername='html', testroot='intl', @pytest.mark.sphinx(
confoverrides={'language': 'en', 'locale_dirs': [locale_dir]}) 'html', testroot='intl',
confoverrides={'language': 'en', 'locale_dirs': [locale_dir]})
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()
@ -51,9 +53,10 @@ def test_compile_all_catalogs(app, status, warning):
assert actual == expect assert actual == expect
@with_setup(setup_test, teardown_test) @pytest.mark.usefixtures('setup_test')
@with_app(buildername='html', testroot='intl', @pytest.mark.sphinx(
confoverrides={'language': 'en', 'locale_dirs': [locale_dir]}) 'html', testroot='intl',
confoverrides={'language': 'en', 'locale_dirs': [locale_dir]})
def test_compile_specific_catalogs(app, status, warning): def test_compile_specific_catalogs(app, status, warning):
catalog_dir = locale_dir / app.config.language / 'LC_MESSAGES' catalog_dir = locale_dir / app.config.language / 'LC_MESSAGES'
@ -66,9 +69,10 @@ def test_compile_specific_catalogs(app, status, warning):
assert actual == set(['admonitions.mo']) assert actual == set(['admonitions.mo'])
@with_setup(setup_test, teardown_test) @pytest.mark.usefixtures('setup_test')
@with_app(buildername='html', testroot='intl', @pytest.mark.sphinx(
confoverrides={'language': 'en', 'locale_dirs': [locale_dir]}) 'html', testroot='intl',
confoverrides={'language': 'en', 'locale_dirs': [locale_dir]})
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()

View File

@ -10,19 +10,22 @@
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
from six import PY3, iteritems from six import PY3, iteritems
import pytest
import mock import mock
from util import TestApp, with_app, gen_with_app, with_tempdir, \ from util import TestApp, gen_with_app, \
raises, raises_msg, assert_in, assert_not_in assert_in, assert_not_in
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
@with_app(confoverrides={'master_doc': 'master', 'nonexisting_value': 'True', @pytest.mark.sphinx(confoverrides={
'latex_elements.docclass': 'scrartcl', 'master_doc': 'master',
'modindex_common_prefix': 'path1,path2'}) 'nonexisting_value': 'True',
'latex_elements.docclass': 'scrartcl',
'modindex_common_prefix': 'path1,path2'})
def test_core_config(app, status, warning): def test_core_config(app, status, warning):
cfg = app.config cfg = app.config
@ -55,11 +58,14 @@ def test_core_config(app, status, warning):
assert 'nonexisting_value' not in cfg assert 'nonexisting_value' not in cfg
# invalid values # invalid values
raises(AttributeError, getattr, cfg, '_value') with pytest.raises(AttributeError):
raises(AttributeError, getattr, cfg, 'nonexisting_value') getattr(cfg, '_value')
with pytest.raises(AttributeError):
getattr(cfg, 'nonexisting_value')
# non-value attributes are deleted from the namespace # non-value attributes are deleted from the namespace
raises(AttributeError, getattr, cfg, 'sys') with pytest.raises(AttributeError):
getattr(cfg, 'sys')
# setting attributes # setting attributes
cfg.project = 'Foo' cfg.project = 'Foo'
@ -70,7 +76,7 @@ def test_core_config(app, status, warning):
assert cfg['project'] == cfg.project == 'Sphinx Tests' assert cfg['project'] == cfg.project == 'Sphinx Tests'
@with_app() @pytest.mark.sphinx()
def test_extension_values(app, status, warning): def test_extension_values(app, status, warning):
cfg = app.config cfg = app.config
@ -80,24 +86,27 @@ def test_extension_values(app, status, warning):
assert cfg.value_from_conf_py == 84 assert cfg.value_from_conf_py == 84
# no duplicate values allowed # no duplicate values allowed
raises_msg(ExtensionError, 'already present', app.add_config_value, with pytest.raises(ExtensionError) as excinfo:
'html_title', 'x', True) app.add_config_value('html_title', 'x', True)
raises_msg(ExtensionError, 'already present', app.add_config_value, assert 'already present' in str(excinfo.value)
'value_from_ext', 'x', True) with pytest.raises(ExtensionError) as excinfo:
app.add_config_value('value_from_ext', 'x', True)
assert 'already present' in str(excinfo.value)
@with_tempdir
@mock.patch("sphinx.config.logger") @mock.patch("sphinx.config.logger")
def test_errors_warnings(dir, logger): def test_errors_warnings(logger, tempdir):
# test the error for syntax errors in the config file # test the error for syntax errors in the config file
(dir / 'conf.py').write_text(u'project = \n', encoding='ascii') (tempdir / 'conf.py').write_text(u'project = \n', encoding='ascii')
raises_msg(ConfigError, 'conf.py', Config, dir, 'conf.py', {}, None) with pytest.raises(ConfigError) as excinfo:
Config(tempdir, 'conf.py', {}, None)
assert 'conf.py' in str(excinfo.value)
# test the automatic conversion of 2.x only code in configs # test the automatic conversion of 2.x only code in configs
(dir / 'conf.py').write_text( (tempdir / 'conf.py').write_text(
u'# -*- coding: utf-8\n\nproject = u"Jägermeister"\n', u'# -*- coding: utf-8\n\nproject = u"Jägermeister"\n',
encoding='utf-8') encoding='utf-8')
cfg = Config(dir, 'conf.py', {}, None) cfg = Config(tempdir, 'conf.py', {}, None)
cfg.init_values() cfg.init_values()
assert cfg.project == u'Jägermeister' assert cfg.project == u'Jägermeister'
assert logger.called is False assert logger.called is False
@ -107,20 +116,21 @@ def test_errors_warnings(dir, logger):
# skip the test there # skip the test there
if PY3: if PY3:
return return
(dir / 'conf.py').write_text( (tempdir / 'conf.py').write_text(
u'# -*- coding: latin-1\nproject = "fooä"\n', encoding='latin-1') u'# -*- coding: latin-1\nproject = "fooä"\n', encoding='latin-1')
cfg = Config(dir, 'conf.py', {}, None) cfg = Config(tempdir, 'conf.py', {}, None)
assert logger.warning.called is False assert logger.warning.called is False
cfg.check_unicode() cfg.check_unicode()
assert logger.warning.called is True assert logger.warning.called is True
@with_tempdir def test_errors_if_setup_is_not_callable(tempdir):
def test_errors_if_setup_is_not_callable(dir):
# test the error to call setup() in the config file # test the error to call setup() in the config file
(dir / 'conf.py').write_text(u'setup = 1') (tempdir / 'conf.py').write_text(u'setup = 1')
raises_msg(ConfigError, 'callable', TestApp, srcdir=dir) with pytest.raises(ConfigError) as excinfo:
TestApp(srcdir=tempdir)
assert 'callable' in str(excinfo.value)
@mock.patch.object(sphinx, '__display_version__', '1.3.4') @mock.patch.object(sphinx, '__display_version__', '1.3.4')
@ -130,40 +140,39 @@ def test_needs_sphinx():
app.cleanup() app.cleanup()
app = TestApp(confoverrides={'needs_sphinx': '1.3.4'}) # OK: equals app = TestApp(confoverrides={'needs_sphinx': '1.3.4'}) # OK: equals
app.cleanup() app.cleanup()
raises(VersionRequirementError, TestApp, with pytest.raises(VersionRequirementError):
confoverrides={'needs_sphinx': '1.3.5'}) # NG: greater TestApp(confoverrides={'needs_sphinx': '1.3.5'}) # NG: greater
# minor version # minor version
app = TestApp(confoverrides={'needs_sphinx': '1.2'}) # OK: less app = TestApp(confoverrides={'needs_sphinx': '1.2'}) # OK: less
app.cleanup() app.cleanup()
app = TestApp(confoverrides={'needs_sphinx': '1.3'}) # OK: equals app = TestApp(confoverrides={'needs_sphinx': '1.3'}) # OK: equals
app.cleanup() app.cleanup()
raises(VersionRequirementError, TestApp, with pytest.raises(VersionRequirementError):
confoverrides={'needs_sphinx': '1.4'}) # NG: greater TestApp(confoverrides={'needs_sphinx': '1.4'}) # NG: greater
# major version # major version
app = TestApp(confoverrides={'needs_sphinx': '0'}) # OK: less app = TestApp(confoverrides={'needs_sphinx': '0'}) # OK: less
app.cleanup() app.cleanup()
app = TestApp(confoverrides={'needs_sphinx': '1'}) # OK: equals app = TestApp(confoverrides={'needs_sphinx': '1'}) # OK: equals
app.cleanup() app.cleanup()
raises(VersionRequirementError, TestApp, with pytest.raises(VersionRequirementError):
confoverrides={'needs_sphinx': '2'}) # NG: greater TestApp(confoverrides={'needs_sphinx': '2'}) # NG: greater
@with_tempdir
@mock.patch("sphinx.config.logger") @mock.patch("sphinx.config.logger")
def test_config_eol(tmpdir, logger): def test_config_eol(logger, tempdir):
# test config file's eol patterns: LF, CRLF # test config file's eol patterns: LF, CRLF
configfile = tmpdir / 'conf.py' configfile = tempdir / 'conf.py'
for eol in (b'\n', b'\r\n'): for eol in (b'\n', b'\r\n'):
configfile.write_bytes(b'project = "spam"' + eol) configfile.write_bytes(b'project = "spam"' + eol)
cfg = Config(tmpdir, 'conf.py', {}, None) cfg = Config(tempdir, 'conf.py', {}, None)
cfg.init_values() cfg.init_values()
assert cfg.project == u'spam' assert cfg.project == u'spam'
assert logger.called is False assert logger.called is False
@with_app(confoverrides={'master_doc': 123, @pytest.mark.sphinx(confoverrides={'master_doc': 123,
'language': 'foo', 'language': 'foo',
'primary_domain': None}) 'primary_domain': None})
def test_builtin_conf(app, status, warning): def test_builtin_conf(app, status, warning):
@ -209,13 +218,13 @@ def test_gen_check_types(app, status, warning):
) )
@with_app(testroot='config') @pytest.mark.sphinx(testroot='config')
def test_check_enum(app, status, warning): def test_check_enum(app, status, warning):
assert "The config value `value17` has to be a one of ('default', 'one', 'two'), " \ assert "The config value `value17` has to be a one of ('default', 'one', 'two'), " \
not in warning.getvalue() not in warning.getvalue()
@with_app(testroot='config', confoverrides={'value17': 'invalid'}) @pytest.mark.sphinx(testroot='config', confoverrides={'value17': 'invalid'})
def test_check_enum_failed(app, status, warning): def test_check_enum_failed(app, status, warning):
assert "The config value `value17` has to be a one of ('default', 'one', 'two'), " \ assert "The config value `value17` has to be a one of ('default', 'one', 'two'), " \
"but `invalid` is given." in warning.getvalue() "but `invalid` is given." in warning.getvalue()

View File

@ -9,10 +9,12 @@
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
from util import with_app, etree_parse import pytest
from util import etree_parse
@with_app('xml', testroot='directive-code') @pytest.mark.sphinx('xml', testroot='directive-code')
def test_code_block(app, status, warning): def test_code_block(app, status, warning):
app.builder.build('index') app.builder.build('index')
et = etree_parse(app.outdir / 'index.xml') et = etree_parse(app.outdir / 'index.xml')
@ -28,7 +30,7 @@ def test_code_block(app, status, warning):
assert actual == expect assert actual == expect
@with_app('xml', testroot='directive-code') @pytest.mark.sphinx('xml', testroot='directive-code')
def test_code_block_dedent(app, status, warning): def test_code_block_dedent(app, status, warning):
app.builder.build(['dedent_code']) app.builder.build(['dedent_code'])
et = etree_parse(app.outdir / 'dedent_code.xml') et = etree_parse(app.outdir / 'dedent_code.xml')
@ -47,7 +49,7 @@ def test_code_block_dedent(app, status, warning):
assert blocks[5].text == '\n\n' # dedent: 1000 assert blocks[5].text == '\n\n' # dedent: 1000
@with_app('html', testroot='directive-code') @pytest.mark.sphinx('html', testroot='directive-code')
def test_code_block_caption_html(app, status, warning): def test_code_block_caption_html(app, status, warning):
app.builder.build(['caption']) app.builder.build(['caption'])
html = (app.outdir / 'caption.html').text(encoding='utf-8') html = (app.outdir / 'caption.html').text(encoding='utf-8')
@ -59,7 +61,7 @@ def test_code_block_caption_html(app, status, warning):
assert caption in html assert caption in html
@with_app('latex', testroot='directive-code') @pytest.mark.sphinx('latex', testroot='directive-code')
def test_code_block_caption_latex(app, status, warning): def test_code_block_caption_latex(app, status, warning):
app.builder.build_all() app.builder.build_all()
latex = (app.outdir / 'Python.tex').text(encoding='utf-8') latex = (app.outdir / 'Python.tex').text(encoding='utf-8')
@ -72,7 +74,7 @@ def test_code_block_caption_latex(app, status, warning):
assert link in latex assert link in latex
@with_app('latex', testroot='directive-code') @pytest.mark.sphinx('latex', testroot='directive-code')
def test_code_block_namedlink_latex(app, status, warning): def test_code_block_namedlink_latex(app, status, warning):
app.builder.build_all() app.builder.build_all()
latex = (app.outdir / 'Python.tex').text(encoding='utf-8') latex = (app.outdir / 'Python.tex').text(encoding='utf-8')
@ -89,7 +91,7 @@ def test_code_block_namedlink_latex(app, status, warning):
assert link2 in latex assert link2 in latex
@with_app('xml', testroot='directive-code') @pytest.mark.sphinx('xml', testroot='directive-code')
def test_literal_include(app, status, warning): def test_literal_include(app, status, warning):
app.builder.build(['index']) app.builder.build(['index'])
et = etree_parse(app.outdir / 'index.xml') et = etree_parse(app.outdir / 'index.xml')
@ -101,7 +103,7 @@ def test_literal_include(app, status, warning):
assert actual == literal_src assert actual == literal_src
@with_app('xml', testroot='directive-code') @pytest.mark.sphinx('xml', testroot='directive-code')
def test_literal_include_dedent(app, status, warning): def test_literal_include_dedent(app, status, warning):
literal_src = (app.srcdir / 'literal.inc').text(encoding='utf-8') literal_src = (app.srcdir / 'literal.inc').text(encoding='utf-8')
literal_lines = [l[4:] for l in literal_src.split('\n')[9:11]] literal_lines = [l[4:] for l in literal_src.split('\n')[9:11]]
@ -119,7 +121,7 @@ def test_literal_include_dedent(app, status, warning):
assert blocks[5].text == '\n\n' # dedent: 1000 assert blocks[5].text == '\n\n' # dedent: 1000
@with_app('xml', testroot='directive-code') @pytest.mark.sphinx('xml', testroot='directive-code')
def test_literal_include_block_start_with_comment_or_brank(app, status, warning): def test_literal_include_block_start_with_comment_or_brank(app, status, warning):
app.builder.build(['python']) app.builder.build(['python'])
et = etree_parse(app.outdir / 'python.xml') et = etree_parse(app.outdir / 'python.xml')
@ -143,7 +145,7 @@ def test_literal_include_block_start_with_comment_or_brank(app, status, warning)
assert actual == expect assert actual == expect
@with_app('html', testroot='directive-code') @pytest.mark.sphinx('html', testroot='directive-code')
def test_literal_include_linenos(app, status, warning): def test_literal_include_linenos(app, status, warning):
app.builder.build(['linenos']) app.builder.build(['linenos'])
html = (app.outdir / 'linenos.html').text(encoding='utf-8') html = (app.outdir / 'linenos.html').text(encoding='utf-8')
@ -166,7 +168,7 @@ def test_literal_include_linenos(app, status, warning):
assert linenos in html assert linenos in html
@with_app('html', testroot='directive-code') @pytest.mark.sphinx('html', testroot='directive-code')
def test_literal_include_lineno_start(app, status, warning): def test_literal_include_lineno_start(app, status, warning):
app.builder.build(['lineno_start']) app.builder.build(['lineno_start'])
html = (app.outdir / 'lineno_start.html').text(encoding='utf-8') html = (app.outdir / 'lineno_start.html').text(encoding='utf-8')
@ -189,7 +191,7 @@ def test_literal_include_lineno_start(app, status, warning):
assert linenos in html assert linenos in html
@with_app('html', testroot='directive-code') @pytest.mark.sphinx('html', testroot='directive-code')
def test_literal_include_lineno_match(app, status, warning): def test_literal_include_lineno_match(app, status, warning):
app.builder.build(['lineno_match']) app.builder.build(['lineno_match'])
html = (app.outdir / 'lineno_match.html').text(encoding='utf-8') html = (app.outdir / 'lineno_match.html').text(encoding='utf-8')
@ -229,7 +231,7 @@ def test_literal_include_lineno_match(app, status, warning):
assert start_at_end_at in html assert start_at_end_at in html
@with_app('latex', testroot='directive-code') @pytest.mark.sphinx('latex', testroot='directive-code')
def test_literalinclude_file_whole_of_emptyline(app, status, warning): def test_literalinclude_file_whole_of_emptyline(app, status, warning):
app.builder.build_all() app.builder.build_all()
latex = (app.outdir / 'Python.tex').text(encoding='utf-8').replace('\r\n', '\n') latex = (app.outdir / 'Python.tex').text(encoding='utf-8').replace('\r\n', '\n')
@ -243,7 +245,7 @@ def test_literalinclude_file_whole_of_emptyline(app, status, warning):
assert includes in latex assert includes in latex
@with_app('html', testroot='directive-code') @pytest.mark.sphinx('html', testroot='directive-code')
def test_literalinclude_caption_html(app, status, warning): def test_literalinclude_caption_html(app, status, warning):
app.builder.build('index') app.builder.build('index')
html = (app.outdir / 'caption.html').text(encoding='utf-8') html = (app.outdir / 'caption.html').text(encoding='utf-8')
@ -255,7 +257,7 @@ def test_literalinclude_caption_html(app, status, warning):
assert caption in html assert caption in html
@with_app('latex', testroot='directive-code') @pytest.mark.sphinx('latex', testroot='directive-code')
def test_literalinclude_caption_latex(app, status, warning): def test_literalinclude_caption_latex(app, status, warning):
app.builder.build('index') app.builder.build('index')
latex = (app.outdir / 'Python.tex').text(encoding='utf-8') latex = (app.outdir / 'Python.tex').text(encoding='utf-8')
@ -268,7 +270,7 @@ def test_literalinclude_caption_latex(app, status, warning):
assert link in latex assert link in latex
@with_app('latex', testroot='directive-code') @pytest.mark.sphinx('latex', testroot='directive-code')
def test_literalinclude_namedlink_latex(app, status, warning): def test_literalinclude_namedlink_latex(app, status, warning):
app.builder.build('index') app.builder.build('index')
latex = (app.outdir / 'Python.tex').text(encoding='utf-8') latex = (app.outdir / 'Python.tex').text(encoding='utf-8')
@ -285,7 +287,7 @@ def test_literalinclude_namedlink_latex(app, status, warning):
assert link2 in latex assert link2 in latex
@with_app('xml', testroot='directive-code') @pytest.mark.sphinx('xml', testroot='directive-code')
def test_literalinclude_classes(app, status, warning): def test_literalinclude_classes(app, status, warning):
app.builder.build(['classes']) app.builder.build(['classes'])
et = etree_parse(app.outdir / 'classes.xml') et = etree_parse(app.outdir / 'classes.xml')

View File

@ -13,11 +13,10 @@ import re
from docutils import nodes from docutils import nodes
from sphinx.util.nodes import process_only_nodes from sphinx.util.nodes import process_only_nodes
import pytest
from util import with_app
@with_app('text', testroot='directive-only') @pytest.mark.sphinx('text', testroot='directive-only')
def test_sectioning(app, status, warning): def test_sectioning(app, status, warning):
def getsects(section): def getsects(section):

View File

@ -11,14 +11,15 @@
import re import re
from util import with_app, path, SkipTest import pytest
from util import path, SkipTest
def regex_count(expr, result): def regex_count(expr, result):
return len(re.findall(expr, result)) return len(re.findall(expr, result))
@with_app('html', testroot='docutilsconf', freshenv=True, docutilsconf='') @pytest.mark.sphinx('html', testroot='docutilsconf', freshenv=True, docutilsconf='')
def test_html_with_default_docutilsconf(app, status, warning): def test_html_with_default_docutilsconf(app, status, warning):
app.builder.build(['contents']) app.builder.build(['contents'])
result = (app.outdir / 'contents.html').text(encoding='utf-8') result = (app.outdir / 'contents.html').text(encoding='utf-8')
@ -29,7 +30,7 @@ def test_html_with_default_docutilsconf(app, status, warning):
assert regex_count(r'<td class="option-group" colspan="2">', result) == 1 assert regex_count(r'<td class="option-group" colspan="2">', result) == 1
@with_app('html', testroot='docutilsconf', freshenv=True, docutilsconf=( @pytest.mark.sphinx('html', testroot='docutilsconf', freshenv=True, docutilsconf=(
'\n[html4css1 writer]' '\n[html4css1 writer]'
'\noption-limit:1' '\noption-limit:1'
'\nfield-name-limit:1' '\nfield-name-limit:1'
@ -45,31 +46,31 @@ def test_html_with_docutilsconf(app, status, warning):
assert regex_count(r'<td class="option-group" colspan="2">', result) == 2 assert regex_count(r'<td class="option-group" colspan="2">', result) == 2
@with_app('html', testroot='docutilsconf') @pytest.mark.sphinx('html', testroot='docutilsconf')
def test_html(app, status, warning): def test_html(app, status, warning):
app.builder.build(['contents']) app.builder.build(['contents'])
assert warning.getvalue() == '' assert warning.getvalue() == ''
@with_app('latex', testroot='docutilsconf') @pytest.mark.sphinx('latex', testroot='docutilsconf')
def test_latex(app, status, warning): def test_latex(app, status, warning):
app.builder.build(['contents']) app.builder.build(['contents'])
assert warning.getvalue() == '' assert warning.getvalue() == ''
@with_app('man', testroot='docutilsconf') @pytest.mark.sphinx('man', testroot='docutilsconf')
def test_man(app, status, warning): def test_man(app, status, warning):
app.builder.build(['contents']) app.builder.build(['contents'])
assert warning.getvalue() == '' assert warning.getvalue() == ''
@with_app('texinfo', testroot='docutilsconf') @pytest.mark.sphinx('texinfo', testroot='docutilsconf')
def test_texinfo(app, status, warning): def test_texinfo(app, status, warning):
app.builder.build(['contents']) app.builder.build(['contents'])
@with_app('html', testroot='docutilsconf', @pytest.mark.sphinx('html', testroot='docutilsconf',
docutilsconf='[general]\nsource_link=true\n') docutilsconf='[general]\nsource_link=true\n')
def test_docutils_source_link_with_nonascii_file(app, status, warning): def test_docutils_source_link_with_nonascii_file(app, status, warning):
srcdir = path(app.srcdir) srcdir = path(app.srcdir)
mb_name = u'\u65e5\u672c\u8a9e' mb_name = u'\u65e5\u672c\u8a9e'

View File

@ -12,8 +12,7 @@
import re import re
from six import text_type from six import text_type
import pytest
from util import raises, with_app
from sphinx import addnodes from sphinx import addnodes
from sphinx.domains.cpp import DefinitionParser, DefinitionError, NoOldIdError from sphinx.domains.cpp import DefinitionParser, DefinitionError, NoOldIdError
@ -150,9 +149,10 @@ def test_concept_definitions():
None, 'I0EN1A1B7ConceptE') None, 'I0EN1A1B7ConceptE')
check('concept', 'template<typename A, typename B, typename ...C> Foo()', check('concept', 'template<typename A, typename B, typename ...C> Foo()',
None, 'I00DpE3Foo') None, 'I00DpE3Foo')
raises(DefinitionError, parse, 'concept', 'Foo') with pytest.raises(DefinitionError):
raises(DefinitionError, parse, 'concept', parse('concept', 'Foo')
'template<typename T> template<typename U> Foo') with pytest.raises(DefinitionError):
parse('concept', 'template<typename T> template<typename U> Foo')
def test_member_definitions(): def test_member_definitions():
@ -259,9 +259,12 @@ def test_function_definitions():
'int foo(Foo f = Foo(double(), std::make_pair(int(2), double(3.4))))', 'int foo(Foo f = Foo(double(), std::make_pair(int(2), double(3.4))))',
"foo__Foo", "3foo3Foo") "foo__Foo", "3foo3Foo")
check('function', 'int foo(A a = x(a))', "foo__A", "3foo1A") check('function', 'int foo(A a = x(a))', "foo__A", "3foo1A")
raises(DefinitionError, parse, 'function', 'int foo(B b=x(a)') with pytest.raises(DefinitionError):
raises(DefinitionError, parse, 'function', 'int foo)C c=x(a))') parse('function', 'int foo(B b=x(a)')
raises(DefinitionError, parse, 'function', 'int foo(D d=x(a') with pytest.raises(DefinitionError):
parse('function', 'int foo)C c=x(a))')
with pytest.raises(DefinitionError):
parse('function', 'int foo(D d=x(a')
check('function', 'int foo(const A&... a)', "foo__ACRDp", "3fooDpRK1A") check('function', 'int foo(const A&... a)', "foo__ACRDp", "3fooDpRK1A")
check('function', 'virtual void f()', "f", "1fv") check('function', 'virtual void f()', "f", "1fv")
# test for ::nestedName, from issue 1738 # test for ::nestedName, from issue 1738
@ -382,8 +385,10 @@ def test_templates():
check('function', "template<> void A()", None, "IE1Av") check('function', "template<> void A()", None, "IE1Av")
check('member', "template<> A a", None, "IE1a") check('member', "template<> A a", None, "IE1a")
check('type', "template<> a = A", None, "IE1a") check('type', "template<> a = A", None, "IE1a")
raises(DefinitionError, parse, 'enum', "template<> A") with pytest.raises(DefinitionError):
raises(DefinitionError, parse, 'enumerator', "template<> A") parse('enum', "template<> A")
with pytest.raises(DefinitionError):
parse('enumerator', "template<> A")
# then all the real tests # then all the real tests
check('class', "template<typename T1, typename T2> A", None, "I00E1A") check('class', "template<typename T1, typename T2> A", None, "I00E1A")
check('type', "template<> a", None, "IE1a") check('type', "template<> a", None, "IE1a")
@ -419,8 +424,10 @@ def test_templates():
"RK18c_string_view_baseIK4Char6TraitsE") "RK18c_string_view_baseIK4Char6TraitsE")
# template introductions # template introductions
raises(DefinitionError, parse, 'enum', 'abc::ns::foo{id_0, id_1, id_2} A') with pytest.raises(DefinitionError):
raises(DefinitionError, parse, 'enumerator', 'abc::ns::foo{id_0, id_1, id_2} A') parse('enum', 'abc::ns::foo{id_0, id_1, id_2} A')
with pytest.raises(DefinitionError):
parse('enumerator', 'abc::ns::foo{id_0, id_1, id_2} A')
check('class', 'abc::ns::foo{id_0, id_1, id_2} xyz::bar', check('class', 'abc::ns::foo{id_0, id_1, id_2} xyz::bar',
None, 'I000EXN3abc2ns3fooEI4id_04id_14id_2EEN3xyz3barE') None, 'I000EXN3abc2ns3fooEI4id_04id_14id_2EEN3xyz3barE')
check('class', 'abc::ns::foo{id_0, id_1, ...id_2} xyz::bar', check('class', 'abc::ns::foo{id_0, id_1, ...id_2} xyz::bar',
@ -469,12 +476,18 @@ def test_attributes():
check('member', 'paren_attr(a) int f', 'f__i', '1f') check('member', 'paren_attr(a) int f', 'f__i', '1f')
check('member', 'paren_attr("") int f', 'f__i', '1f') check('member', 'paren_attr("") int f', 'f__i', '1f')
check('member', 'paren_attr(()[{}][]{}) int f', 'f__i', '1f') check('member', 'paren_attr(()[{}][]{}) int f', 'f__i', '1f')
raises(DefinitionError, parse, 'member', 'paren_attr(() int f') with pytest.raises(DefinitionError):
raises(DefinitionError, parse, 'member', 'paren_attr([) int f') parse('member', 'paren_attr(() int f')
raises(DefinitionError, parse, 'member', 'paren_attr({) int f') with pytest.raises(DefinitionError):
raises(DefinitionError, parse, 'member', 'paren_attr([)]) int f') parse('member', 'paren_attr([) int f')
raises(DefinitionError, parse, 'member', 'paren_attr((])) int f') with pytest.raises(DefinitionError):
raises(DefinitionError, parse, 'member', 'paren_attr({]}) int f') parse('member', 'paren_attr({) int f')
with pytest.raises(DefinitionError):
parse('member', 'paren_attr([)]) int f')
with pytest.raises(DefinitionError):
parse('member', 'paren_attr((])) int f')
with pytest.raises(DefinitionError):
parse('member', 'paren_attr({]}) int f')
# position: decl specs # position: decl specs
check('function', 'static inline __attribute__(()) void f()', check('function', 'static inline __attribute__(()) void f()',
@ -490,7 +503,7 @@ def test_attributes():
# raise DefinitionError("") # raise DefinitionError("")
@with_app(testroot='domain-cpp', confoverrides={'add_function_parentheses': True}) @pytest.mark.sphinx(testroot='domain-cpp', confoverrides={'add_function_parentheses': True})
def test_build_domain_cpp_with_add_function_parentheses_is_True(app, status, warning): def test_build_domain_cpp_with_add_function_parentheses_is_True(app, status, warning):
app.builder.build_all() app.builder.build_all()
@ -527,7 +540,8 @@ def test_build_domain_cpp_with_add_function_parentheses_is_True(app, status, war
check(s, t, f) check(s, t, f)
@with_app(testroot='domain-cpp', confoverrides={'add_function_parentheses': False}) @pytest.mark.sphinx(testroot='domain-cpp', confoverrides={
'add_function_parentheses': False})
def test_build_domain_cpp_with_add_function_parentheses_is_False(app, status, warning): def test_build_domain_cpp_with_add_function_parentheses_is_False(app, status, warning):
app.builder.build_all() app.builder.build_all()

View File

@ -14,8 +14,9 @@ from docutils.nodes import bullet_list, list_item, caption, comment, reference
from sphinx import addnodes from sphinx import addnodes
from sphinx.addnodes import compact_paragraph, only from sphinx.addnodes import compact_paragraph, only
from sphinx.builders.html import StandaloneHTMLBuilder from sphinx.builders.html import StandaloneHTMLBuilder
import pytest
from util import with_app, gen_with_app, assert_node from util import gen_with_app, assert_node
@gen_with_app('xml', testroot='toctree') @gen_with_app('xml', testroot='toctree')
@ -97,7 +98,7 @@ def _test_process_doc(app):
assert 'qux' not in app.env.toctree_includes assert 'qux' not in app.env.toctree_includes
@with_app('dummy', testroot='toctree-glob') @pytest.mark.sphinx('dummy', testroot='toctree-glob')
def test_glob(app, status, warning): def test_glob(app, status, warning):
includefiles = ['foo', 'bar/index', 'bar/bar_1', 'bar/bar_2', includefiles = ['foo', 'bar/index', 'bar/bar_1', 'bar/bar_2',
'bar/bar_3', 'baz', 'qux/index'] 'bar/bar_3', 'baz', 'qux/index']

View File

@ -10,12 +10,11 @@
""" """
import pickle import pickle
from docutils import nodes import pytest
from sphinx import addnodes from sphinx import addnodes
from util import with_app
@with_app(buildername='dummy', testroot='ext-autodoc') @pytest.mark.sphinx('dummy', testroot='ext-autodoc')
def test_autodoc(app, status, warning): def test_autodoc(app, status, warning):
app.builder.build_all() app.builder.build_all()

View File

@ -11,10 +11,10 @@
import re import re
from util import with_app import pytest
@with_app('html', testroot='ext-autosectionlabel') @pytest.mark.sphinx('html', testroot='ext-autosectionlabel')
def test_autosectionlabel_html(app, status, warning): def test_autosectionlabel_html(app, status, warning):
app.builder.build_all() app.builder.build_all()

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 with_app import pytest
html_warnfile = StringIO() html_warnfile = StringIO()
@ -54,7 +54,7 @@ def test_mangle_signature():
assert res == outp, (u"'%s' -> '%s' != '%s'" % (inp, res, outp)) assert res == outp, (u"'%s' -> '%s' != '%s'" % (inp, res, outp))
@with_app(buildername='dummy', **default_kw) @pytest.mark.sphinx('dummy', **default_kw)
def test_get_items_summary(app, status, warning): def test_get_items_summary(app, status, warning):
# monkey-patch Autosummary.get_items so we can easily get access to it's # monkey-patch Autosummary.get_items so we can easily get access to it's
# results.. # results..

View File

@ -11,10 +11,10 @@
import pickle import pickle
from util import with_app import pytest
@with_app(buildername='coverage') @pytest.mark.sphinx('coverage')
def test_build(app, status, warning): def test_build(app, status, warning):
app.builder.build_all() app.builder.build_all()

View File

@ -8,13 +8,12 @@
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS. :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
import pytest
from util import with_app
cleanup_called = 0 cleanup_called = 0
@with_app(buildername='doctest', testroot='doctest') @pytest.mark.sphinx('doctest', testroot='doctest')
def test_build(app, status, warning): def test_build(app, status, warning):
global cleanup_called global cleanup_called
cleanup_called = 0 cleanup_called = 0

View File

@ -9,10 +9,10 @@
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
from util import with_app import pytest
@with_app('html', testroot='ext-githubpages') @pytest.mark.sphinx('html', testroot='ext-githubpages')
def test_githubpages(app, status, warning): def test_githubpages(app, status, warning):
app.builder.build_all() app.builder.build_all()
assert (app.outdir / '.nojekyll').exists() assert (app.outdir / '.nojekyll').exists()

View File

@ -10,37 +10,12 @@
""" """
import re import re
import subprocess
from functools import wraps
from util import with_app, SkipTest import pytest
def skip_if_graphviz_not_found(fn): @pytest.mark.sphinx('html', testroot='ext-graphviz')
@wraps(fn) @pytest.mark.usefixtures('if_graphviz_found')
def decorator(app, *args, **kwargs):
found = False
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()
found = True
except OSError: # No such file or directory
pass
if not found:
raise SkipTest('graphviz "dot" is not available')
return fn(app, *args, **kwargs)
return decorator
@with_app('html', testroot='ext-graphviz')
@skip_if_graphviz_not_found
def test_graphviz_html(app, status, warning): def test_graphviz_html(app, status, warning):
app.builder.build_all() app.builder.build_all()
@ -60,8 +35,8 @@ def test_graphviz_html(app, status, warning):
assert re.search(html, content, re.S) assert re.search(html, content, re.S)
@with_app('latex', testroot='ext-graphviz') @pytest.mark.sphinx('latex', testroot='ext-graphviz')
@skip_if_graphviz_not_found @pytest.mark.usefixtures('if_graphviz_found')
def test_graphviz_latex(app, status, warning): def test_graphviz_latex(app, status, warning):
app.builder.build_all() app.builder.build_all()
@ -80,8 +55,8 @@ def test_graphviz_latex(app, status, warning):
assert re.search(macro, content, re.S) assert re.search(macro, content, re.S)
@with_app('html', testroot='ext-graphviz', confoverrides={'language': 'xx'}) @pytest.mark.sphinx('html', testroot='ext-graphviz', confoverrides={'language': 'xx'})
@skip_if_graphviz_not_found @pytest.mark.usefixtures('if_graphviz_found')
def test_graphviz_i18n(app, status, warning): def test_graphviz_i18n(app, status, warning):
app.builder.build_all() app.builder.build_all()

View File

@ -9,10 +9,10 @@
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
from util import with_app import pytest
@with_app(buildername='text', testroot='ext-ifconfig') @pytest.mark.sphinx('text', testroot='ext-ifconfig')
def test_ifconfig(app, status, warning): def test_ifconfig(app, status, warning):
app.builder.build_all() app.builder.build_all()
result = (app.outdir / 'index.txt').text() result = (app.outdir / 'index.txt').text()

View File

@ -11,13 +11,13 @@
import re import re
import sys import sys
from util import with_app, rootdir, raises from util import rootdir
from test_ext_graphviz import skip_if_graphviz_not_found
from sphinx.ext.inheritance_diagram import InheritanceException, import_classes from sphinx.ext.inheritance_diagram import InheritanceException, import_classes
import pytest
@with_app('html', testroot='ext-inheritance_diagram') @pytest.mark.sphinx('html', testroot='ext-inheritance_diagram')
@skip_if_graphviz_not_found @pytest.mark.usefixtures('if_graphviz_found')
def test_inheritance_diagram_html(app, status, warning): def test_inheritance_diagram_html(app, status, warning):
app.builder.build_all() app.builder.build_all()
@ -31,8 +31,8 @@ def test_inheritance_diagram_html(app, status, warning):
assert re.search(pattern, content, re.M) assert re.search(pattern, content, re.M)
@with_app('latex', testroot='ext-inheritance_diagram') @pytest.mark.sphinx('latex', testroot='ext-inheritance_diagram')
@skip_if_graphviz_not_found @pytest.mark.usefixtures('if_graphviz_found')
def test_inheritance_diagram_latex(app, status, warning): def test_inheritance_diagram_latex(app, status, warning):
app.builder.build_all() app.builder.build_all()
@ -53,8 +53,10 @@ def test_import_classes():
from example.sphinx import DummyClass from example.sphinx import DummyClass
# got exception for unknown class or module # got exception for unknown class or module
raises(InheritanceException, import_classes, 'unknown', None) with pytest.raises(InheritanceException):
raises(InheritanceException, import_classes, 'unknown.Unknown', None) import_classes('unknown', None)
with pytest.raises(InheritanceException):
import_classes('unknown.Unknown', None)
# a module having no classes # a module having no classes
classes = import_classes('sphinx', None) classes = import_classes('sphinx', None)
@ -80,7 +82,8 @@ def test_import_classes():
assert classes == [CatalogInfo] assert classes == [CatalogInfo]
# got exception for functions # got exception for functions
raises(InheritanceException, import_classes, 'encode_uri', 'sphinx.util') with pytest.raises(InheritanceException):
import_classes('encode_uri', 'sphinx.util')
# import submodule on current module (refs: #3164) # import submodule on current module (refs: #3164)
classes = import_classes('sphinx', 'example') classes = import_classes('sphinx', 'example')

View File

@ -23,8 +23,6 @@ from sphinx.ext.intersphinx import read_inventory, \
load_mappings, missing_reference, _strip_basic_auth, _read_from_url, \ load_mappings, missing_reference, _strip_basic_auth, _read_from_url, \
_get_safe_url, fetch_inventory, INVENTORY_FILENAME _get_safe_url, fetch_inventory, INVENTORY_FILENAME
from util import with_app, with_tempdir
inventory_v1 = '''\ inventory_v1 = '''\
# Sphinx inventory version 1 # Sphinx inventory version 1
@ -82,10 +80,9 @@ def test_read_inventory_v2():
'/util/glossary.html#term-a-term-including-colon' '/util/glossary.html#term-a-term-including-colon'
@with_app()
@mock.patch('sphinx.ext.intersphinx.read_inventory') @mock.patch('sphinx.ext.intersphinx.read_inventory')
@mock.patch('sphinx.ext.intersphinx._read_from_url') @mock.patch('sphinx.ext.intersphinx._read_from_url')
def test_fetch_inventory_redirection(app, status, warning, _read_from_url, read_inventory): def test_fetch_inventory_redirection(_read_from_url, read_inventory, app, status, warning):
intersphinx_setup(app) intersphinx_setup(app)
_read_from_url().readline.return_value = '# Sphinx inventory version 2'.encode('utf-8') _read_from_url().readline.return_value = '# Sphinx inventory version 2'.encode('utf-8')
@ -127,8 +124,6 @@ def test_fetch_inventory_redirection(app, status, warning, _read_from_url, read_
assert read_inventory.call_args[0][1] == 'http://hostname/' assert read_inventory.call_args[0][1] == 'http://hostname/'
@with_app()
@with_tempdir
def test_missing_reference(tempdir, app, status, warning): def test_missing_reference(tempdir, app, status, warning):
inv_file = tempdir / 'inventory' inv_file = tempdir / 'inventory'
inv_file.write_bytes(inventory_v2) inv_file.write_bytes(inventory_v2)
@ -218,8 +213,6 @@ def test_missing_reference(tempdir, app, status, warning):
assert rn['refuri'] == '../../../../py3k/foo.html#module-module1' assert rn['refuri'] == '../../../../py3k/foo.html#module-module1'
@with_app()
@with_tempdir
def test_load_mappings_warnings(tempdir, app, status, warning): def test_load_mappings_warnings(tempdir, app, status, warning):
""" """
load_mappings issues a warning if new-style mapping load_mappings issues a warning if new-style mapping

View File

@ -11,11 +11,13 @@
import re import re
from util import with_app, SkipTest import pytest
from util import SkipTest
@with_app(buildername='html', testroot='ext-math', @pytest.mark.sphinx(
confoverrides = {'extensions': ['sphinx.ext.jsmath'], 'jsmath_path': 'dummy.js'}) 'html', testroot='ext-math',
confoverrides = {'extensions': ['sphinx.ext.jsmath'], 'jsmath_path': 'dummy.js'})
def test_jsmath(app, status, warning): def test_jsmath(app, status, warning):
app.builder.build_all() app.builder.build_all()
content = (app.outdir / 'math.html').text() content = (app.outdir / 'math.html').text()
@ -33,7 +35,7 @@ def test_jsmath(app, status, warning):
assert '<div class="math">\na + 1 &lt; b</div>' in content assert '<div class="math">\na + 1 &lt; b</div>' in content
@with_app('html', testroot='ext-math-simple', @pytest.mark.sphinx('html', testroot='ext-math-simple',
confoverrides = {'extensions': ['sphinx.ext.imgmath']}) confoverrides = {'extensions': ['sphinx.ext.imgmath']})
def test_imgmath_png(app, status, warning): def test_imgmath_png(app, status, warning):
app.builder.build_all() app.builder.build_all()
@ -48,7 +50,7 @@ def test_imgmath_png(app, status, warning):
assert re.search(html, content, re.S) assert re.search(html, content, re.S)
@with_app('html', testroot='ext-math-simple', @pytest.mark.sphinx('html', testroot='ext-math-simple',
confoverrides={'extensions': ['sphinx.ext.imgmath'], confoverrides={'extensions': ['sphinx.ext.imgmath'],
'imgmath_image_format': 'svg'}) 'imgmath_image_format': 'svg'})
def test_imgmath_svg(app, status, warning): def test_imgmath_svg(app, status, warning):
@ -64,7 +66,7 @@ def test_imgmath_svg(app, status, warning):
assert re.search(html, content, re.S) assert re.search(html, content, re.S)
@with_app('html', testroot='ext-math', @pytest.mark.sphinx('html', testroot='ext-math',
confoverrides={'extensions': ['sphinx.ext.mathjax']}) confoverrides={'extensions': ['sphinx.ext.mathjax']})
def test_mathjax_align(app, status, warning): def test_mathjax_align(app, status, warning):
app.builder.build_all() app.builder.build_all()
@ -76,7 +78,7 @@ def test_mathjax_align(app, status, warning):
assert re.search(html, content, re.S) assert re.search(html, content, re.S)
@with_app('html', testroot='ext-math', @pytest.mark.sphinx('html', testroot='ext-math',
confoverrides={'math_number_all': True, confoverrides={'math_number_all': True,
'extensions': ['sphinx.ext.mathjax']}) 'extensions': ['sphinx.ext.mathjax']})
def test_math_number_all_mathjax(app, status, warning): def test_math_number_all_mathjax(app, status, warning):
@ -88,7 +90,7 @@ def test_math_number_all_mathjax(app, status, warning):
assert re.search(html, content, re.S) assert re.search(html, content, re.S)
@with_app('latex', testroot='ext-math', @pytest.mark.sphinx('latex', testroot='ext-math',
confoverrides={'extensions': ['sphinx.ext.mathjax']}) confoverrides={'extensions': ['sphinx.ext.mathjax']})
def test_math_number_all_latex(app, status, warning): def test_math_number_all_latex(app, status, warning):
app.builder.build_all() app.builder.build_all()

View File

@ -10,10 +10,11 @@
""" """
import re import re
from util import with_app
import pytest
@with_app('html', testroot='ext-todo', freshenv=True, @pytest.mark.sphinx('html', testroot='ext-todo', freshenv=True,
confoverrides={'todo_include_todos': True, 'todo_emit_warnings': True}) confoverrides={'todo_include_todos': True, 'todo_emit_warnings': True})
def test_todo(app, status, warning): def test_todo(app, status, warning):
todos = [] todos = []
@ -49,7 +50,7 @@ def test_todo(app, status, warning):
assert set(todo[1].astext() for todo in todos) == set(['todo in foo', 'todo in bar']) assert set(todo[1].astext() for todo in todos) == set(['todo in foo', 'todo in bar'])
@with_app('html', testroot='ext-todo', freshenv=True, @pytest.mark.sphinx('html', testroot='ext-todo', freshenv=True,
confoverrides={'todo_include_todos': False, 'todo_emit_warnings': True}) confoverrides={'todo_include_todos': False, 'todo_emit_warnings': True})
def test_todo_not_included(app, status, warning): def test_todo_not_included(app, status, warning):
todos = [] todos = []

View File

@ -11,10 +11,10 @@
import re import re
from util import with_app import pytest
@with_app(testroot='ext-viewcode') @pytest.mark.sphinx(testroot='ext-viewcode')
def test_viewcode(app, status, warning): def test_viewcode(app, status, warning):
app.builder.build_all() app.builder.build_all()
@ -32,7 +32,7 @@ def test_viewcode(app, status, warning):
assert result.count('href="_modules/spam/mod2.html#Class2"') == 2 assert result.count('href="_modules/spam/mod2.html#Class2"') == 2
@with_app(testroot='ext-viewcode', tags=['test_linkcode']) @pytest.mark.sphinx(testroot='ext-viewcode', tags=['test_linkcode'])
def test_linkcode(app, status, warning): def test_linkcode(app, status, warning):
app.builder.build(['objects']) app.builder.build(['objects'])

View File

@ -16,8 +16,6 @@ from pygments.formatters.html import HtmlFormatter
from sphinx.highlighting import PygmentsBridge from sphinx.highlighting import PygmentsBridge
from util import with_app
class MyLexer(RegexLexer): class MyLexer(RegexLexer):
name = 'testlexer' name = 'testlexer'
@ -41,7 +39,6 @@ class ComplainOnUnhighlighted(PygmentsBridge):
raise AssertionError("should highlight %r" % source) raise AssertionError("should highlight %r" % source)
@with_app()
def test_add_lexer(app, status, warning): def test_add_lexer(app, status, warning):
app.add_lexer('test', MyLexer()) app.add_lexer('test', MyLexer())

View File

@ -18,12 +18,12 @@ from docutils import nodes
from subprocess import Popen, PIPE from subprocess import Popen, PIPE
from babel.messages import pofile from babel.messages import pofile
from nose.tools import assert_equal
from six import string_types from six import string_types
import pytest
from util import tempdir, rootdir, path, gen_with_app, with_app, SkipTest, \ from util import tempdir, rootdir, path, gen_with_app, SkipTest, \
assert_re_search, assert_not_re_search, assert_in, assert_not_in, \ assert_re_search, assert_not_re_search, assert_in, assert_not_in, \
assert_startswith, assert_node, repr_as, etree_parse, strip_escseq assert_startswith, assert_node, etree_parse, strip_escseq, assert_equal
root = tempdir / 'test-intl' root = tempdir / 'test-intl'
@ -846,7 +846,7 @@ def test_references(app, status, warning):
yield assert_count(warning_expr, warnings, 0) yield assert_count(warning_expr, warnings, 0)
@with_app(buildername='dummy', testroot='image-glob', confoverrides={'language': 'xx'}) @pytest.mark.sphinx('dummy', testroot='image-glob', confoverrides={'language': 'xx'})
def test_image_glob_intl(app, status, warning): def test_image_glob_intl(app, status, warning):
app.builder.build_all() app.builder.build_all()
@ -887,7 +887,7 @@ def test_image_glob_intl(app, status, warning):
'image/svg+xml': 'subdir/svgimg.xx.svg'}) 'image/svg+xml': 'subdir/svgimg.xx.svg'})
@with_app(buildername='dummy', testroot='image-glob', @pytest.mark.sphinx('dummy', testroot='image-glob',
confoverrides={'language': 'xx', confoverrides={'language': 'xx',
'figure_language_filename': u'{root}{ext}.{language}'}) 'figure_language_filename': u'{root}{ext}.{language}'})
def test_image_glob_intl_using_figure_language_filename(app, status, warning): def test_image_glob_intl_using_figure_language_filename(app, status, warning):
@ -931,4 +931,4 @@ def test_image_glob_intl_using_figure_language_filename(app, status, warning):
def getwarning(warnings): def getwarning(warnings):
return repr_as(strip_escseq(warnings.getvalue().replace(os.sep, '/')), '<warnings>') return strip_escseq(warnings.getvalue().replace(os.sep, '/'))

View File

@ -20,8 +20,9 @@ from sphinx.util import texescape
from sphinx.util.docutils import sphinx_domains from sphinx.util.docutils import sphinx_domains
from sphinx.writers.html import HTMLWriter, SmartyPantsHTMLTranslator from sphinx.writers.html import HTMLWriter, SmartyPantsHTMLTranslator
from sphinx.writers.latex import LaTeXWriter, LaTeXTranslator from sphinx.writers.latex import LaTeXWriter, LaTeXTranslator
import pytest
from util import TestApp, with_app, assert_node from util import TestApp, assert_node
app = settings = parser = domain_context = None app = settings = parser = domain_context = None
@ -152,7 +153,7 @@ def test_latex_escaping():
r'\\href{http://example.com/~me/}{test}.*') r'\\href{http://example.com/~me/}{test}.*')
@with_app(buildername='dummy', testroot='prolog') @pytest.mark.sphinx('dummy', testroot='prolog')
def test_rst_prolog(app, status, warning): def test_rst_prolog(app, status, warning):
app.builder.build_all() app.builder.build_all()
rst = pickle.loads((app.doctreedir / 'restructuredtext.doctree').bytes()) rst = pickle.loads((app.doctreedir / 'restructuredtext.doctree').bytes())
@ -176,7 +177,7 @@ def test_rst_prolog(app, status, warning):
assert not md.rawsource.endswith('*Good-bye world*.\n') assert not md.rawsource.endswith('*Good-bye world*.\n')
@with_app(buildername='dummy', testroot='keep_warnings') @pytest.mark.sphinx('dummy', testroot='keep_warnings')
def test_keep_warnings_is_True(app, status, warning): def test_keep_warnings_is_True(app, status, warning):
app.builder.build_all() app.builder.build_all()
doctree = pickle.loads((app.doctreedir / 'index.doctree').bytes()) doctree = pickle.loads((app.doctreedir / 'index.doctree').bytes())
@ -185,7 +186,7 @@ def test_keep_warnings_is_True(app, status, warning):
assert_node(doctree[0][1], nodes.system_message) assert_node(doctree[0][1], nodes.system_message)
@with_app(buildername='dummy', testroot='keep_warnings', @pytest.mark.sphinx('dummy', testroot='keep_warnings',
confoverrides={'keep_warnings': False}) confoverrides={'keep_warnings': False})
def test_keep_warnings_is_False(app, status, warning): def test_keep_warnings_is_False(app, status, warning):
app.builder.build_all() app.builder.build_all()
@ -194,7 +195,7 @@ def test_keep_warnings_is_False(app, status, warning):
assert len(doctree[0]) == 1 assert len(doctree[0]) == 1
@with_app(buildername='dummy', testroot='refonly_bullet_list') @pytest.mark.sphinx('dummy', testroot='refonly_bullet_list')
def test_compact_refonly_bullet_list(app, status, warning): def test_compact_refonly_bullet_list(app, status, warning):
app.builder.build_all() app.builder.build_all()
doctree = pickle.loads((app.doctreedir / 'index.doctree').bytes()) doctree = pickle.loads((app.doctreedir / 'index.doctree').bytes())

View File

@ -12,12 +12,10 @@
# adapted from an example of bibliographic metadata at # adapted from an example of bibliographic metadata at
# http://docutils.sourceforge.net/docs/user/rst/demo.txt # http://docutils.sourceforge.net/docs/user/rst/demo.txt
from util import with_app import pytest
from nose.tools import assert_equal
@with_app('pseudoxml') @pytest.mark.sphinx('pseudoxml')
def test_docinfo(app, status, warning): def test_docinfo(app, status, warning):
""" """
Inspect the 'docinfo' metadata stored in the first node of the document. Inspect the 'docinfo' metadata stored in the first node of the document.
@ -53,8 +51,4 @@ def test_docinfo(app, status, warning):
'orphan': u'', 'orphan': u'',
'nocomments': u'', 'nocomments': u'',
} }
# I like this way of comparing dicts - easier to see the error. assert exampledocinfo == expecteddocinfo
for key in exampledocinfo:
yield assert_equal, exampledocinfo.get(key), expecteddocinfo.get(key)
# but then we still have to check for missing keys
yield assert_equal, set(expecteddocinfo.keys()), set(exampledocinfo.keys())

View File

@ -14,8 +14,9 @@ import time
from six import PY2, text_type, StringIO from six import PY2, text_type, StringIO
from six.moves import input from six.moves import input
import pytest
from util import raises, with_tempdir, SkipTest from util import SkipTest
from sphinx import application from sphinx import application
from sphinx import quickstart as qs from sphinx import quickstart as qs
@ -107,7 +108,8 @@ def test_do_prompt():
assert d['k4'] is True assert d['k4'] is True
qs.do_prompt(d, 'k5', 'Q5', validator=qs.boolean) qs.do_prompt(d, 'k5', 'Q5', validator=qs.boolean)
assert d['k5'] is False assert d['k5'] is False
raises(AssertionError, qs.do_prompt, d, 'k6', 'Q6', validator=qs.boolean) with pytest.raises(AssertionError):
qs.do_prompt(d, 'k6', 'Q6', validator=qs.boolean)
def test_do_prompt_with_nonascii(): def test_do_prompt_with_nonascii():
@ -125,7 +127,6 @@ def test_do_prompt_with_nonascii():
assert d['k1'] == u'\u30c9\u30a4\u30c4' assert d['k1'] == u'\u30c9\u30a4\u30c4'
@with_tempdir
def test_quickstart_defaults(tempdir): def test_quickstart_defaults(tempdir):
answers = { answers = {
'Root path': tempdir, 'Root path': tempdir,
@ -163,7 +164,6 @@ def test_quickstart_defaults(tempdir):
assert (tempdir / 'make.bat').isfile() assert (tempdir / 'make.bat').isfile()
@with_tempdir
def test_quickstart_all_answers(tempdir): def test_quickstart_all_answers(tempdir):
answers = { answers = {
'Root path': tempdir, 'Root path': tempdir,
@ -231,7 +231,6 @@ def test_quickstart_all_answers(tempdir):
assert (tempdir / 'source' / 'contents.txt').isfile() assert (tempdir / 'source' / 'contents.txt').isfile()
@with_tempdir
def test_generated_files_eol(tempdir): def test_generated_files_eol(tempdir):
answers = { answers = {
'Root path': tempdir, 'Root path': tempdir,
@ -252,7 +251,6 @@ def test_generated_files_eol(tempdir):
assert_eol(tempdir / 'Makefile', '\n') assert_eol(tempdir / 'Makefile', '\n')
@with_tempdir
def test_quickstart_and_build(tempdir): def test_quickstart_and_build(tempdir):
answers = { answers = {
'Root path': tempdir, 'Root path': tempdir,
@ -278,7 +276,6 @@ def test_quickstart_and_build(tempdir):
assert not warnings assert not warnings
@with_tempdir
def test_default_filename(tempdir): def test_default_filename(tempdir):
answers = { answers = {
'Root path': tempdir, 'Root path': tempdir,
@ -300,7 +297,6 @@ def test_default_filename(tempdir):
assert ns['texinfo_documents'][0][1] == 'sphinx' assert ns['texinfo_documents'][0][1] == 'sphinx'
@with_tempdir
def test_extensions(tempdir): def test_extensions(tempdir):
qs.main(['sphinx-quickstart', '-q', qs.main(['sphinx-quickstart', '-q',
'-p', 'project_name', '-a', 'author', '-p', 'project_name', '-a', 'author',

View File

@ -15,8 +15,7 @@ from docutils.parsers import rst
from sphinx.search import IndexBuilder from sphinx.search import IndexBuilder
from sphinx.util import jsdump from sphinx.util import jsdump
import pytest
from util import with_app
settings = parser = None settings = parser = None
@ -58,7 +57,7 @@ def test_wordcollector():
assert 'fermion' in ix._mapping assert 'fermion' in ix._mapping
@with_app(testroot='ext-viewcode') @pytest.mark.sphinx(testroot='ext-viewcode')
def test_objects_are_escaped(app, status, warning): def test_objects_are_escaped(app, status, warning):
app.builder.build_all() app.builder.build_all()
searchindex = (app.outdir / 'searchindex.js').text() searchindex = (app.outdir / 'searchindex.js').text()
@ -68,7 +67,7 @@ def test_objects_are_escaped(app, status, warning):
assert 'n::Array&lt;T, d&gt;' in index.get('objects').get('') # n::Array<T,d> is escaped assert 'n::Array&lt;T, d&gt;' in index.get('objects').get('') # n::Array<T,d> is escaped
@with_app(testroot='search') @pytest.mark.sphinx(testroot='search')
def test_meta_keys_are_handled_for_language_en(app, status, warning): def test_meta_keys_are_handled_for_language_en(app, status, warning):
app.builder.build_all() app.builder.build_all()
searchindex = jsload(app.outdir / 'searchindex.js') searchindex = jsload(app.outdir / 'searchindex.js')
@ -81,7 +80,7 @@ def test_meta_keys_are_handled_for_language_en(app, status, warning):
assert not is_registered_term(searchindex, 'onlytoogerman') assert not is_registered_term(searchindex, 'onlytoogerman')
@with_app(testroot='search', confoverrides={'html_search_language': 'de'}) @pytest.mark.sphinx(testroot='search', confoverrides={'html_search_language': 'de'})
def test_meta_keys_are_handled_for_language_de(app, status, warning): def test_meta_keys_are_handled_for_language_de(app, status, warning):
app.builder.build_all() app.builder.build_all()
searchindex = jsload(app.outdir / 'searchindex.js') searchindex = jsload(app.outdir / 'searchindex.js')
@ -94,14 +93,14 @@ def test_meta_keys_are_handled_for_language_de(app, status, warning):
assert is_registered_term(searchindex, 'onlytoogerman') assert is_registered_term(searchindex, 'onlytoogerman')
@with_app(testroot='search') @pytest.mark.sphinx(testroot='search')
def test_stemmer_does_not_remove_short_words(app, status, warning): def test_stemmer_does_not_remove_short_words(app, status, warning):
app.builder.build_all() app.builder.build_all()
searchindex = (app.outdir / 'searchindex.js').text() searchindex = (app.outdir / 'searchindex.js').text()
assert 'zfs' in searchindex assert 'zfs' in searchindex
@with_app(testroot='search') @pytest.mark.sphinx(testroot='search')
def test_stemmer(app, status, warning): def test_stemmer(app, status, warning):
searchindex = jsload(app.outdir / 'searchindex.js') searchindex = jsload(app.outdir / 'searchindex.js')
print(searchindex) print(searchindex)
@ -109,7 +108,7 @@ def test_stemmer(app, status, warning):
assert is_registered_term(searchindex, 'intern') assert is_registered_term(searchindex, 'intern')
@with_app(testroot='search') @pytest.mark.sphinx(testroot='search')
def test_term_in_heading_and_section(app, status, warning): def test_term_in_heading_and_section(app, status, warning):
searchindex = (app.outdir / 'searchindex.js').text() searchindex = (app.outdir / 'searchindex.js').text()
# if search term is in the title of one doc and in the text of another # if search term is in the title of one doc and in the text of another
@ -119,7 +118,7 @@ def test_term_in_heading_and_section(app, status, warning):
assert 'textinhead:0' in searchindex assert 'textinhead:0' in searchindex
@with_app(testroot='search') @pytest.mark.sphinx(testroot='search')
def test_term_in_raw_directive(app, status, warning): def test_term_in_raw_directive(app, status, warning):
searchindex = jsload(app.outdir / 'searchindex.js') searchindex = jsload(app.outdir / 'searchindex.js')
assert not is_registered_term(searchindex, 'raw') assert not is_registered_term(searchindex, 'raw')

View File

@ -12,12 +12,13 @@
import os import os
import sys import sys
import subprocess import subprocess
from functools import wraps from collections import namedtuple
import tempfile
import sphinx import sphinx
from util import rootdir, tempdir, SkipTest import pytest
from path import path
from sphinx.util.osutil import cd
from util import rootdir, tempdir
from textwrap import dedent from textwrap import dedent
root = tempdir / 'test-setup' root = tempdir / 'test-setup'
@ -28,57 +29,52 @@ def setup_module():
(rootdir / 'roots' / 'test-setup').copytree(root) (rootdir / 'roots' / 'test-setup').copytree(root)
def with_setup_command(root, *args, **kwds): @pytest.fixture
def setup_command(request, tempdir):
""" """
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.
""" """
def generator(func): marker = request.node.get_marker('setup_command')
@wraps(func) args = marker.args if marker else []
def deco(*args2, **kwargs2):
tempdir = path(tempfile.mkdtemp()) pkgrootdir = tempdir / 'root'
pkgrootdir = (tempdir / 'root') root.copytree(pkgrootdir)
root.copytree(pkgrootdir)
cwd = os.getcwd() with cd(pkgrootdir):
os.chdir(pkgrootdir) pythonpath = os.path.dirname(os.path.dirname(sphinx.__file__))
pythonpath = os.path.dirname(os.path.dirname(sphinx.__file__)) if os.getenv('PYTHONPATH'):
if os.getenv('PYTHONPATH'): pythonpath = os.getenv('PYTHONPATH') + os.pathsep + pythonpath
pythonpath = os.getenv('PYTHONPATH') + os.pathsep + pythonpath command = [sys.executable, 'setup.py', 'build_sphinx']
command = [sys.executable, 'setup.py', 'build_sphinx'] command.extend(args)
command.extend(args)
try: proc = subprocess.Popen(
proc = subprocess.Popen( command,
command, env=dict(os.environ, PYTHONPATH=pythonpath),
env=dict(os.environ, PYTHONPATH=pythonpath), stdout=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stderr=subprocess.PIPE) yield namedtuple('setup', 'pkgroot,proc')(pkgrootdir, proc)
func(pkgrootdir, proc)
finally:
tempdir.rmtree(ignore_errors=True)
os.chdir(cwd)
return deco
return generator
@with_setup_command(root) def test_build_sphinx(setup_command):
def test_build_sphinx(pkgroot, proc): proc = setup_command.proc
out, err = proc.communicate() out, err = proc.communicate()
print(out) print(out)
print(err) print(err)
assert proc.returncode == 0 assert proc.returncode == 0
@with_setup_command(root) @pytest.fixture
def test_build_sphinx_with_nonascii_path(pkgroot, proc): def nonascii_srcdir(request, setup_command):
mb_name = u'\u65e5\u672c\u8a9e' mb_name = u'\u65e5\u672c\u8a9e'
srcdir = (pkgroot / 'doc') srcdir = (setup_command.pkgroot / 'doc')
try: try:
(srcdir / mb_name).makedirs() (srcdir / mb_name).makedirs()
except UnicodeEncodeError: except UnicodeEncodeError:
from path import FILESYSTEMENCODING from path import FILESYSTEMENCODING
raise SkipTest( pytest.skip(
'non-ASCII filename not supported on this filesystem encoding: ' 'non-ASCII filename not supported on this filesystem encoding: '
'%s', FILESYSTEMENCODING) '%s' % FILESYSTEMENCODING)
(srcdir / mb_name / (mb_name + '.txt')).write_text(dedent(""" (srcdir / mb_name / (mb_name + '.txt')).write_text(dedent("""
multi byte file name page multi byte file name page
@ -91,41 +87,47 @@ def test_build_sphinx_with_nonascii_path(pkgroot, proc):
%(mb_name)s/%(mb_name)s %(mb_name)s/%(mb_name)s
""" % locals()) """ % locals())
).encode('utf-8')) ).encode('utf-8'))
@pytest.mark.usefixtures('nonascii_srcdir')
def test_build_sphinx_with_nonascii_path(setup_command):
proc = setup_command.proc
out, err = proc.communicate() out, err = proc.communicate()
print(out) print(out)
print(err) print(err)
assert proc.returncode == 0 assert proc.returncode == 0
@with_setup_command(root, '-b', 'linkcheck') @pytest.mark.setup_command('-b', 'linkcheck')
def test_build_sphinx_return_nonzero_status(pkgroot, proc): def test_build_sphinx_return_nonzero_status(setup_command):
srcdir = (pkgroot / 'doc') srcdir = (setup_command.pkgroot / 'doc')
(srcdir / 'contents.txt').write_text( (srcdir / 'contents.txt').write_text(
'http://localhost.unexistentdomain/index.html') 'http://localhost.unexistentdomain/index.html')
proc = setup_command.proc
out, err = proc.communicate() out, err = proc.communicate()
print(out) print(out)
print(err) print(err)
assert proc.returncode != 0, 'expect non-zero status for setup.py' assert proc.returncode != 0, 'expect non-zero status for setup.py'
@with_setup_command(root) def test_build_sphinx_warning_return_zero_status(setup_command):
def test_build_sphinx_warning_return_zero_status(pkgroot, proc): srcdir = (setup_command.pkgroot / 'doc')
srcdir = (pkgroot / 'doc')
(srcdir / 'contents.txt').write_text( (srcdir / 'contents.txt').write_text(
'See :ref:`unexisting-reference-label`') 'See :ref:`unexisting-reference-label`')
proc = setup_command.proc
out, err = proc.communicate() out, err = proc.communicate()
print(out) print(out)
print(err) print(err)
assert proc.returncode == 0 assert proc.returncode == 0
@with_setup_command(root, '--warning-is-error') @pytest.mark.setup_command('--warning-is-error')
def test_build_sphinx_warning_is_error_return_nonzero_status(pkgroot, proc): def test_build_sphinx_warning_is_error_return_nonzero_status(setup_command):
srcdir = (pkgroot / 'doc') srcdir = (setup_command.pkgroot / 'doc')
(srcdir / 'contents.txt').write_text( (srcdir / 'contents.txt').write_text(
'See :ref:`unexisting-reference-label`') 'See :ref:`unexisting-reference-label`')
proc = setup_command.proc
out, err = proc.communicate() out, err = proc.communicate()
print(out) print(out)
print(err) print(err)

View File

@ -9,10 +9,10 @@
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
from util import with_app import pytest
@with_app('html', testroot='templating') @pytest.mark.sphinx('html', testroot='templating')
def test_layout_overloading(app, status, warning): def test_layout_overloading(app, status, warning):
app.builder.build_update() app.builder.build_update()
@ -21,7 +21,7 @@ def test_layout_overloading(app, status, warning):
assert '<!-- layout overloading -->' in result assert '<!-- layout overloading -->' in result
@with_app('html', testroot='templating') @pytest.mark.sphinx('html', testroot='templating')
def test_autosummary_class_template_overloading(app, status, warning): def test_autosummary_class_template_overloading(app, status, warning):
app.builder.build_update() app.builder.build_update()

View File

@ -13,14 +13,16 @@ import os
import zipfile import zipfile
import mock import mock
import pytest
from sphinx.theming import Theme, ThemeError from sphinx.theming import Theme, ThemeError
from util import with_app, raises, path from util import with_app, path
@with_app(confoverrides={'html_theme': 'ziptheme', @pytest.mark.sphinx(
'html_theme_options.testopt': 'foo'}) confoverrides={'html_theme': 'ziptheme',
'html_theme_options.testopt': 'foo'})
def test_theme_api(app, status, warning): def test_theme_api(app, status, warning):
cfg = app.config cfg = app.config
@ -46,10 +48,12 @@ def test_theme_api(app, status, warning):
assert theme.get_confstr('options', 'nosidebar') == 'false' assert theme.get_confstr('options', 'nosidebar') == 'false'
# nonexisting setting # nonexisting setting
assert theme.get_confstr('theme', 'foobar', 'def') == 'def' assert theme.get_confstr('theme', 'foobar', 'def') == 'def'
raises(ThemeError, theme.get_confstr, 'theme', 'foobar') with pytest.raises(ThemeError):
theme.get_confstr('theme', 'foobar')
# options API # options API
raises(ThemeError, theme.get_options, {'nonexisting': 'foo'}) with pytest.raises(ThemeError):
theme.get_options({'nonexisting': 'foo'})
options = theme.get_options(cfg.html_theme_options) options = theme.get_options(cfg.html_theme_options)
assert options['testopt'] == 'foo' assert options['testopt'] == 'foo'
assert options['nosidebar'] == 'false' assert options['nosidebar'] == 'false'
@ -59,7 +63,7 @@ def test_theme_api(app, status, warning):
assert not os.path.exists(themedir) assert not os.path.exists(themedir)
@with_app(testroot='tocdepth') # a minimal root @pytest.mark.sphinx(testroot='tocdepth') # a minimal root
def test_js_source(app, status, warning): def test_js_source(app, status, warning):
# Now sphinx provides non-minified JS files for jquery.js and underscore.js # Now sphinx provides non-minified JS files for jquery.js and underscore.js
# to clarify the source of the minified files. see also #1434. # to clarify the source of the minified files. see also #1434.
@ -83,7 +87,8 @@ def test_js_source(app, status, warning):
assert 'Underscore.js {v}'.format(v=v) in underscore_src, msg assert 'Underscore.js {v}'.format(v=v) in underscore_src, msg
def test_double_inheriting_theme(): @pytest.mark.sphinx(testroot='double-inheriting-theme')
def test_double_inheriting_theme(make_app, app_params):
from sphinx.theming import load_theme_plugins # load original before patching from sphinx.theming import load_theme_plugins # load original before patching
def load_themes(): def load_themes():
@ -92,8 +97,6 @@ def test_double_inheriting_theme():
for t in load_theme_plugins(): for t in load_theme_plugins():
yield t yield t
@mock.patch('sphinx.theming.load_theme_plugins', side_effect=load_themes) with mock.patch('sphinx.theming.load_theme_plugins', side_effect=load_themes):
@with_app(testroot='double-inheriting-theme') args, kwargs = app_params
def test_double_inheriting_theme_(app, status, warning, m_): make_app(*args, **kwargs)
pass
yield test_double_inheriting_theme_

View File

@ -8,11 +8,9 @@
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS. :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
import pytest
from util import with_app @pytest.mark.sphinx(testroot='toctree-glob')
@with_app(testroot='toctree-glob')
def test_relations(app, status, warning): def test_relations(app, status, warning):
app.builder.build_all() app.builder.build_all()
assert app.builder.relations['index'] == [None, None, 'foo'] assert app.builder.relations['index'] == [None, None, 'foo']

View File

@ -12,7 +12,6 @@ from sphinx.util.fileutil import copy_asset, copy_asset_file
from sphinx.jinja2glue import BuiltinTemplateLoader from sphinx.jinja2glue import BuiltinTemplateLoader
import mock import mock
from util import with_tempdir
class DummyTemplateLoader(BuiltinTemplateLoader): class DummyTemplateLoader(BuiltinTemplateLoader):
@ -24,33 +23,32 @@ class DummyTemplateLoader(BuiltinTemplateLoader):
self.init(builder) self.init(builder)
@with_tempdir def test_copy_asset_file(tempdir):
def test_copy_asset_file(tmpdir):
renderer = DummyTemplateLoader() renderer = DummyTemplateLoader()
# copy normal file # copy normal file
src = (tmpdir / 'asset.txt') src = (tempdir / 'asset.txt')
src.write_text('# test data') src.write_text('# test data')
dest = (tmpdir / 'output.txt') dest = (tempdir / 'output.txt')
copy_asset_file(src, dest) copy_asset_file(src, dest)
assert dest.exists() assert dest.exists()
assert src.text() == dest.text() assert src.text() == dest.text()
# copy template file # copy template file
src = (tmpdir / 'asset.txt_t') src = (tempdir / 'asset.txt_t')
src.write_text('# {{var1}} data') src.write_text('# {{var1}} data')
dest = (tmpdir / 'output.txt_t') dest = (tempdir / 'output.txt_t')
copy_asset_file(src, dest, {'var1': 'template'}, renderer) copy_asset_file(src, dest, {'var1': 'template'}, renderer)
assert not dest.exists() assert not dest.exists()
assert (tmpdir / 'output.txt').exists() assert (tempdir / 'output.txt').exists()
assert (tmpdir / 'output.txt').text() == '# template data' assert (tempdir / 'output.txt').text() == '# template data'
# copy template file to subdir # copy template file to subdir
src = (tmpdir / 'asset.txt_t') src = (tempdir / 'asset.txt_t')
src.write_text('# {{var1}} data') src.write_text('# {{var1}} data')
subdir1 = (tmpdir / 'subdir') subdir1 = (tempdir / 'subdir')
subdir1.makedirs() subdir1.makedirs()
copy_asset_file(src, subdir1, {'var1': 'template'}, renderer) copy_asset_file(src, subdir1, {'var1': 'template'}, renderer)
@ -58,8 +56,8 @@ def test_copy_asset_file(tmpdir):
assert (subdir1 / 'asset.txt').text() == '# template data' assert (subdir1 / 'asset.txt').text() == '# template data'
# copy template file without context # copy template file without context
src = (tmpdir / 'asset.txt_t') src = (tempdir / 'asset.txt_t')
subdir2 = (tmpdir / 'subdir2') subdir2 = (tempdir / 'subdir2')
subdir2.makedirs() subdir2.makedirs()
copy_asset_file(src, subdir2) copy_asset_file(src, subdir2)
@ -68,12 +66,11 @@ def test_copy_asset_file(tmpdir):
assert (subdir2 / 'asset.txt_t').text() == '# {{var1}} data' assert (subdir2 / 'asset.txt_t').text() == '# {{var1}} data'
@with_tempdir def test_copy_asset(tempdir):
def test_copy_asset(tmpdir):
renderer = DummyTemplateLoader() renderer = DummyTemplateLoader()
# prepare source files # prepare source files
source = (tmpdir / 'source') source = (tempdir / 'source')
source.makedirs() source.makedirs()
(source / 'index.rst').write_text('index.rst') (source / 'index.rst').write_text('index.rst')
(source / 'foo.rst_t').write_text('{{var1}}.rst') (source / 'foo.rst_t').write_text('{{var1}}.rst')
@ -84,13 +81,13 @@ def test_copy_asset(tmpdir):
(source / '_templates' / 'sidebar.html_t').write_text('sidebar: {{var2}}') (source / '_templates' / 'sidebar.html_t').write_text('sidebar: {{var2}}')
# copy a single file # copy a single file
assert not (tmpdir / 'test1').exists() assert not (tempdir / 'test1').exists()
copy_asset(source / 'index.rst', tmpdir / 'test1') copy_asset(source / 'index.rst', tempdir / 'test1')
assert (tmpdir / 'test1').exists() assert (tempdir / 'test1').exists()
assert (tmpdir / 'test1/index.rst').exists() assert (tempdir / 'test1/index.rst').exists()
# copy directories # copy directories
destdir = tmpdir / 'test2' destdir = tempdir / 'test2'
copy_asset(source, destdir, context=dict(var1='bar', var2='baz'), renderer=renderer) copy_asset(source, destdir, context=dict(var1='bar', var2='baz'), renderer=renderer)
assert (destdir / 'index.rst').exists() assert (destdir / 'index.rst').exists()
assert (destdir / 'foo.rst').exists() assert (destdir / 'foo.rst').exists()
@ -104,7 +101,7 @@ def test_copy_asset(tmpdir):
def excluded(path): def excluded(path):
return ('sidebar.html' in path or 'basic.css' in path) return ('sidebar.html' in path or 'basic.css' in path)
destdir = tmpdir / 'test3' destdir = tempdir / 'test3'
copy_asset(source, destdir, excluded, copy_asset(source, destdir, excluded,
context=dict(var1='bar', var2='baz'), renderer=renderer) context=dict(var1='bar', var2='baz'), renderer=renderer)
assert (destdir / 'index.rst').exists() assert (destdir / 'index.rst').exists()

View File

@ -17,8 +17,9 @@ from os import path
from babel.messages.mofile import read_mo from babel.messages.mofile import read_mo
from sphinx.util import i18n from sphinx.util import i18n
from sphinx.errors import SphinxError from sphinx.errors import SphinxError
import pytest
from util import TestApp, with_tempdir, raises from util import TestApp
def test_catalog_info_for_file_and_path(): def test_catalog_info_for_file_and_path():
@ -37,13 +38,12 @@ def test_catalog_info_for_sub_domain_file_and_path():
assert cat.mo_path == path.join('path', 'sub/domain.mo') assert cat.mo_path == path.join('path', 'sub/domain.mo')
@with_tempdir def test_catalog_outdated(tempdir):
def test_catalog_outdated(dir): (tempdir / 'test.po').write_text('#')
(dir / 'test.po').write_text('#') cat = i18n.CatalogInfo(tempdir, 'test', 'utf-8')
cat = i18n.CatalogInfo(dir, 'test', 'utf-8')
assert cat.is_outdated() # if mo is not exist assert cat.is_outdated() # if mo is not exist
mo_file = (dir / 'test.mo') mo_file = (tempdir / 'test.mo')
mo_file.write_text('#') mo_file.write_text('#')
assert not cat.is_outdated() # if mo is exist and newer than po assert not cat.is_outdated() # if mo is exist and newer than po
@ -51,31 +51,29 @@ def test_catalog_outdated(dir):
assert cat.is_outdated() # if mo is exist and older than po assert cat.is_outdated() # if mo is exist and older than po
@with_tempdir def test_catalog_write_mo(tempdir):
def test_catalog_write_mo(dir): (tempdir / 'test.po').write_text('#')
(dir / 'test.po').write_text('#') cat = i18n.CatalogInfo(tempdir, 'test', 'utf-8')
cat = i18n.CatalogInfo(dir, 'test', 'utf-8')
cat.write_mo('en') cat.write_mo('en')
assert path.exists(cat.mo_path) assert path.exists(cat.mo_path)
with open(cat.mo_path, 'rb') as f: with open(cat.mo_path, 'rb') as f:
assert read_mo(f) is not None assert read_mo(f) is not None
@with_tempdir def test_get_catalogs_for_xx(tempdir):
def test_get_catalogs_for_xx(dir): (tempdir / 'loc1' / 'xx' / 'LC_MESSAGES').makedirs()
(dir / 'loc1' / 'xx' / 'LC_MESSAGES').makedirs() (tempdir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'test1.po').write_text('#')
(dir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'test1.po').write_text('#') (tempdir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'test2.po').write_text('#')
(dir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'test2.po').write_text('#') (tempdir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'test3.pot').write_text('#')
(dir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'test3.pot').write_text('#') (tempdir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'sub').makedirs()
(dir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'sub').makedirs() (tempdir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'sub' / 'test4.po').write_text('#')
(dir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'sub' / 'test4.po').write_text('#') (tempdir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'sub' / 'test5.po').write_text('#')
(dir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'sub' / 'test5.po').write_text('#') (tempdir / 'loc1' / 'en' / 'LC_MESSAGES').makedirs()
(dir / 'loc1' / 'en' / 'LC_MESSAGES').makedirs() (tempdir / 'loc1' / 'en' / 'LC_MESSAGES' / 'test6.po').write_text('#')
(dir / 'loc1' / 'en' / 'LC_MESSAGES' / 'test6.po').write_text('#') (tempdir / 'loc1' / 'xx' / 'LC_ALL').makedirs()
(dir / 'loc1' / 'xx' / 'LC_ALL').makedirs() (tempdir / 'loc1' / 'xx' / 'LC_ALL' / 'test7.po').write_text('#')
(dir / 'loc1' / 'xx' / 'LC_ALL' / 'test7.po').write_text('#')
catalogs = i18n.find_catalog_source_files([dir / 'loc1'], 'xx', force_all=False) catalogs = i18n.find_catalog_source_files([tempdir / 'loc1'], 'xx', force_all=False)
domains = set(c.domain for c in catalogs) domains = set(c.domain for c in catalogs)
assert domains == set([ assert domains == set([
'test1', 'test1',
@ -85,24 +83,22 @@ def test_get_catalogs_for_xx(dir):
]) ])
@with_tempdir def test_get_catalogs_for_en(tempdir):
def test_get_catalogs_for_en(dir): (tempdir / 'loc1' / 'xx' / 'LC_MESSAGES').makedirs()
(dir / 'loc1' / 'xx' / 'LC_MESSAGES').makedirs() (tempdir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'xx_dom.po').write_text('#')
(dir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'xx_dom.po').write_text('#') (tempdir / 'loc1' / 'en' / 'LC_MESSAGES').makedirs()
(dir / 'loc1' / 'en' / 'LC_MESSAGES').makedirs() (tempdir / 'loc1' / 'en' / 'LC_MESSAGES' / 'en_dom.po').write_text('#')
(dir / 'loc1' / 'en' / 'LC_MESSAGES' / 'en_dom.po').write_text('#')
catalogs = i18n.find_catalog_source_files([dir / 'loc1'], 'en', force_all=False) catalogs = i18n.find_catalog_source_files([tempdir / 'loc1'], 'en', force_all=False)
domains = set(c.domain for c in catalogs) domains = set(c.domain for c in catalogs)
assert domains == set(['en_dom']) assert domains == set(['en_dom'])
@with_tempdir def test_get_catalogs_with_non_existent_locale(tempdir):
def test_get_catalogs_with_non_existent_locale(dir): catalogs = i18n.find_catalog_source_files([tempdir / 'loc1'], 'xx')
catalogs = i18n.find_catalog_source_files([dir / 'loc1'], 'xx')
assert not catalogs assert not catalogs
catalogs = i18n.find_catalog_source_files([dir / 'loc1'], None) catalogs = i18n.find_catalog_source_files([tempdir / 'loc1'], None)
assert not catalogs assert not catalogs
@ -111,25 +107,24 @@ def test_get_catalogs_with_non_existent_locale_dirs():
assert not catalogs assert not catalogs
@with_tempdir def test_get_catalogs_for_xx_without_outdated(tempdir):
def test_get_catalogs_for_xx_without_outdated(dir): (tempdir / 'loc1' / 'xx' / 'LC_MESSAGES').makedirs()
(dir / 'loc1' / 'xx' / 'LC_MESSAGES').makedirs() (tempdir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'test1.po').write_text('#')
(dir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'test1.po').write_text('#') (tempdir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'test1.mo').write_text('#')
(dir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'test1.mo').write_text('#') (tempdir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'test2.po').write_text('#')
(dir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'test2.po').write_text('#') (tempdir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'test2.mo').write_text('#')
(dir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'test2.mo').write_text('#') (tempdir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'test3.pot').write_text('#')
(dir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'test3.pot').write_text('#') (tempdir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'test3.mo').write_text('#')
(dir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'test3.mo').write_text('#') (tempdir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'sub').makedirs()
(dir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'sub').makedirs() (tempdir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'sub' / 'test4.po').write_text('#')
(dir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'sub' / 'test4.po').write_text('#') (tempdir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'sub' / 'test4.mo').write_text('#')
(dir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'sub' / 'test4.mo').write_text('#') (tempdir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'sub' / 'test5.po').write_text('#')
(dir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'sub' / 'test5.po').write_text('#') (tempdir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'sub' / 'test5.mo').write_text('#')
(dir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'sub' / 'test5.mo').write_text('#')
catalogs = i18n.find_catalog_source_files([dir / 'loc1'], 'xx', force_all=False) catalogs = i18n.find_catalog_source_files([tempdir / 'loc1'], 'xx', force_all=False)
assert not catalogs assert not catalogs
catalogs = i18n.find_catalog_source_files([dir / 'loc1'], 'xx', force_all=True) catalogs = i18n.find_catalog_source_files([tempdir / 'loc1'], 'xx', force_all=True)
domains = set(c.domain for c in catalogs) domains = set(c.domain for c in catalogs)
assert domains == set([ assert domains == set([
'test1', 'test1',
@ -139,29 +134,27 @@ def test_get_catalogs_for_xx_without_outdated(dir):
]) ])
@with_tempdir def test_get_catalogs_from_multiple_locale_dirs(tempdir):
def test_get_catalogs_from_multiple_locale_dirs(dir): (tempdir / 'loc1' / 'xx' / 'LC_MESSAGES').makedirs()
(dir / 'loc1' / 'xx' / 'LC_MESSAGES').makedirs() (tempdir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'test1.po').write_text('#')
(dir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'test1.po').write_text('#') (tempdir / 'loc2' / 'xx' / 'LC_MESSAGES').makedirs()
(dir / 'loc2' / 'xx' / 'LC_MESSAGES').makedirs() (tempdir / 'loc2' / 'xx' / 'LC_MESSAGES' / 'test1.po').write_text('#')
(dir / 'loc2' / 'xx' / 'LC_MESSAGES' / 'test1.po').write_text('#') (tempdir / 'loc2' / 'xx' / 'LC_MESSAGES' / 'test2.po').write_text('#')
(dir / 'loc2' / 'xx' / 'LC_MESSAGES' / 'test2.po').write_text('#')
catalogs = i18n.find_catalog_source_files([dir / 'loc1', dir / 'loc2'], 'xx') catalogs = i18n.find_catalog_source_files([tempdir / 'loc1', tempdir / 'loc2'], 'xx')
domains = sorted(c.domain for c in catalogs) domains = sorted(c.domain for c in catalogs)
assert domains == ['test1', 'test1', 'test2'] assert domains == ['test1', 'test1', 'test2']
@with_tempdir def test_get_catalogs_with_compact(tempdir):
def test_get_catalogs_with_compact(dir): (tempdir / 'loc1' / 'xx' / 'LC_MESSAGES').makedirs()
(dir / 'loc1' / 'xx' / 'LC_MESSAGES').makedirs() (tempdir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'test1.po').write_text('#')
(dir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'test1.po').write_text('#') (tempdir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'test2.po').write_text('#')
(dir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'test2.po').write_text('#') (tempdir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'sub').makedirs()
(dir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'sub').makedirs() (tempdir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'sub' / 'test3.po').write_text('#')
(dir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'sub' / 'test3.po').write_text('#') (tempdir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'sub' / 'test4.po').write_text('#')
(dir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'sub' / 'test4.po').write_text('#')
catalogs = i18n.find_catalog_source_files([dir / 'loc1'], 'xx', gettext_compact=True) catalogs = i18n.find_catalog_source_files([tempdir / 'loc1'], 'xx', gettext_compact=True)
domains = set(c.domain for c in catalogs) domains = set(c.domain for c in catalogs)
assert domains == set(['test1', 'test2', 'sub']) assert domains == set(['test1', 'test2', 'sub'])
@ -251,4 +244,5 @@ def test_get_filename_for_language():
# invalid figure_language_filename # invalid figure_language_filename
app.env.config.figure_language_filename = '{root}.{invalid}{ext}' app.env.config.figure_language_filename = '{root}.{invalid}{ext}'
raises(SphinxError, i18n.get_image_filename_for_language, 'foo.png', app.env) with pytest.raises(SphinxError):
i18n.get_image_filename_for_language('foo.png', app.env)

View File

@ -9,10 +9,6 @@
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
from functools import wraps
from six import StringIO
from sphinx.websupport import WebSupport from sphinx.websupport import WebSupport
from sphinx.websupport.errors import DocumentNotFoundError, \ from sphinx.websupport.errors import DocumentNotFoundError, \
CommentNotAllowedError, UserNotAuthorizedError CommentNotAllowedError, UserNotAuthorizedError
@ -26,26 +22,28 @@ try:
except ImportError: except ImportError:
sqlalchemy_missing = True sqlalchemy_missing = True
from util import rootdir, tempdir, raises, skip_if import pytest
from util import rootdir, tempdir, skip_if
default_settings = {'builddir': tempdir / 'websupport', @pytest.fixture
'status': StringIO(), def support(request):
'warning': StringIO()} settings = {
'srcdir': rootdir / 'root',
# to use same directory for 'builddir' in each 'support' fixture, using
# 'tempdir' (static) value instead of 'tempdir' fixture value.
# each test expect result of db value at previous test case.
'builddir': tempdir / 'websupport'
}
marker = request.node.get_marker('support')
if marker:
settings.update(marker.kwargs)
support = WebSupport(**settings)
yield support
def with_support(*args, **kwargs): with_support = pytest.mark.support
"""Make a WebSupport object and pass it the test."""
settings = default_settings.copy()
settings.update(kwargs)
def generator(func):
@wraps(func)
def new_func(*args2, **kwargs2):
support = WebSupport(**settings)
func(support, *args2, **kwargs2)
return new_func
return generator
class NullStorage(StorageBackend): class NullStorage(StorageBackend):
@ -55,11 +53,12 @@ class NullStorage(StorageBackend):
@with_support(storage=NullStorage()) @with_support(storage=NullStorage())
def test_no_srcdir(support): def test_no_srcdir(support):
# make sure the correct exception is raised if srcdir is not given. # make sure the correct exception is raised if srcdir is not given.
raises(RuntimeError, support.build) with pytest.raises(RuntimeError):
support.build()
@skip_if(sqlalchemy_missing, 'needs sqlalchemy') @skip_if(sqlalchemy_missing, 'needs sqlalchemy')
@with_support(srcdir=rootdir / 'root') @with_support()
def test_build(support): def test_build(support):
support.build() support.build()
@ -67,7 +66,8 @@ def test_build(support):
@skip_if(sqlalchemy_missing, 'needs sqlalchemy') @skip_if(sqlalchemy_missing, 'needs sqlalchemy')
@with_support() @with_support()
def test_get_document(support): def test_get_document(support):
raises(DocumentNotFoundError, support.get_document, 'nonexisting') with pytest.raises(DocumentNotFoundError):
support.get_document('nonexisting')
contents = support.get_document('contents') contents = support.get_document('contents')
assert contents['title'] and contents['body'] \ assert contents['title'] and contents['body'] \
@ -92,8 +92,8 @@ def test_comments(support):
# Make sure that comments can't be added to a comment where # Make sure that comments can't be added to a comment where
# displayed == False, since it could break the algorithm that # displayed == False, since it could break the algorithm that
# converts a nodes comments to a tree. # converts a nodes comments to a tree.
raises(CommentNotAllowedError, support.add_comment, 'Not allowed', with pytest.raises(CommentNotAllowedError):
parent_id=str(hidden_comment['id'])) support.add_comment('Not allowed', parent_id=str(hidden_comment['id']))
# Add a displayed and not displayed child to the displayed comment. # Add a displayed and not displayed child to the displayed comment.
support.add_comment('Child test comment', parent_id=str(comment['id']), support.add_comment('Child test comment', parent_id=str(comment['id']),
username='user_one') username='user_one')
@ -123,56 +123,6 @@ def test_comments(support):
assert children[0]['text'] == '<p>Child test comment</p>\n' assert children[0]['text'] == '<p>Child test comment</p>\n'
@skip_if(sqlalchemy_missing, 'needs sqlalchemy')
@with_support()
def test_voting(support):
session = Session()
nodes = session.query(Node).all()
node = nodes[0]
comment = support.get_data(node.id)['comments'][0]
def check_rating(val):
data = support.get_data(node.id)
comment = data['comments'][0]
assert comment['rating'] == val, '%s != %s' % (comment['rating'], val)
support.process_vote(comment['id'], 'user_one', '1')
support.process_vote(comment['id'], 'user_two', '1')
support.process_vote(comment['id'], 'user_three', '1')
check_rating(3)
support.process_vote(comment['id'], 'user_one', '-1')
check_rating(1)
support.process_vote(comment['id'], 'user_one', '0')
check_rating(2)
# Make sure a vote with value > 1 or < -1 can't be cast.
raises(ValueError, support.process_vote, comment['id'], 'user_one', '2')
raises(ValueError, support.process_vote, comment['id'], 'user_one', '-2')
# Make sure past voting data is associated with comments when they are
# fetched.
data = support.get_data(str(node.id), username='user_two')
comment = data['comments'][0]
assert comment['vote'] == 1, '%s != 1' % comment['vote']
@skip_if(sqlalchemy_missing, 'needs sqlalchemy')
@with_support()
def test_proposals(support):
session = Session()
node = session.query(Node).first()
data = support.get_data(node.id)
source = data['source']
proposal = source[:5] + source[10:15] + 'asdf' + source[15:]
support.add_comment('Proposal comment',
node_id=node.id,
proposal=proposal)
@skip_if(sqlalchemy_missing, 'needs sqlalchemy') @skip_if(sqlalchemy_missing, 'needs sqlalchemy')
@with_support() @with_support()
def test_user_delete_comments(support): def test_user_delete_comments(support):
@ -185,8 +135,8 @@ def test_user_delete_comments(support):
comment = get_comment() comment = get_comment()
assert comment['username'] == 'user_one' assert comment['username'] == 'user_one'
# Make sure other normal users can't delete someone elses comments. # Make sure other normal users can't delete someone elses comments.
raises(UserNotAuthorizedError, support.delete_comment, with pytest.raises(UserNotAuthorizedError):
comment['id'], username='user_two') support.delete_comment(comment['id'], username='user_two')
# Now delete the comment using the correct username. # Now delete the comment using the correct username.
support.delete_comment(comment['id'], username='user_one') support.delete_comment(comment['id'], username='user_one')
comment = get_comment() comment = get_comment()
@ -194,40 +144,6 @@ def test_user_delete_comments(support):
assert comment['text'] == '[deleted]' assert comment['text'] == '[deleted]'
@skip_if(sqlalchemy_missing, 'needs sqlalchemy')
@with_support()
def test_moderator_delete_comments(support):
def get_comment():
session = Session()
node = session.query(Node).first()
session.close()
return support.get_data(node.id, moderator=True)['comments'][1]
comment = get_comment()
support.delete_comment(comment['id'], username='user_two',
moderator=True)
raises(IndexError, get_comment)
@skip_if(sqlalchemy_missing, 'needs sqlalchemy')
@with_support()
def test_update_username(support):
support.update_username('user_two', 'new_user_two')
session = Session()
comments = session.query(Comment).\
filter(Comment.username == 'user_two').all()
assert len(comments) == 0
votes = session.query(CommentVote).\
filter(CommentVote.username == 'user_two').all()
assert len(votes) == 0
comments = session.query(Comment).\
filter(Comment.username == 'new_user_two').all()
assert len(comments) == 1
votes = session.query(CommentVote).\
filter(CommentVote.username == 'new_user_two').all()
assert len(votes) == 0
called = False called = False
@ -250,8 +166,10 @@ def test_moderation(support):
# Make sure the moderation_callback is called. # Make sure the moderation_callback is called.
assert called assert called
# Make sure the user must be a moderator. # Make sure the user must be a moderator.
raises(UserNotAuthorizedError, support.accept_comment, accepted['id']) with pytest.raises(UserNotAuthorizedError):
raises(UserNotAuthorizedError, support.delete_comment, deleted['id']) support.accept_comment(accepted['id'])
with pytest.raises(UserNotAuthorizedError):
support.delete_comment(deleted['id'])
support.accept_comment(accepted['id'], moderator=True) support.accept_comment(accepted['id'], moderator=True)
support.delete_comment(deleted['id'], moderator=True) support.delete_comment(deleted['id'], moderator=True)
comments = support.get_data(node.id)['comments'] comments = support.get_data(node.id)['comments']
@ -260,6 +178,93 @@ def test_moderation(support):
assert len(comments) == 1 assert len(comments) == 1
@skip_if(sqlalchemy_missing, 'needs sqlalchemy')
@with_support()
def test_moderator_delete_comments(support):
def get_comment():
session = Session()
node = session.query(Node).first()
session.close()
return support.get_data(node.id, moderator=True)['comments'][1]
comment = get_comment()
support.delete_comment(comment['id'], username='user_two',
moderator=True)
with pytest.raises(IndexError):
get_comment()
@skip_if(sqlalchemy_missing, 'needs sqlalchemy')
@with_support()
def test_update_username(support):
support.update_username('user_two', 'new_user_two')
session = Session()
comments = session.query(Comment).\
filter(Comment.username == 'user_two').all()
assert len(comments) == 0
votes = session.query(CommentVote).\
filter(CommentVote.username == 'user_two').all()
assert len(votes) == 0
comments = session.query(Comment).\
filter(Comment.username == 'new_user_two').all()
assert len(comments) == 1
votes = session.query(CommentVote).\
filter(CommentVote.username == 'new_user_two').all()
assert len(votes) == 0
@skip_if(sqlalchemy_missing, 'needs sqlalchemy')
@with_support()
def test_proposals(support):
session = Session()
node = session.query(Node).first()
data = support.get_data(node.id)
source = data['source']
proposal = source[:5] + source[10:15] + 'asdf' + source[15:]
support.add_comment('Proposal comment',
node_id=node.id,
proposal=proposal)
@skip_if(sqlalchemy_missing, 'needs sqlalchemy')
@with_support()
def test_voting(support):
session = Session()
nodes = session.query(Node).all()
node = nodes[0]
comment = support.get_data(node.id)['comments'][0]
def check_rating(val):
data = support.get_data(node.id)
comment = data['comments'][0]
assert comment['rating'] == val, '%s != %s' % (comment['rating'], val)
support.process_vote(comment['id'], 'user_one', '1')
support.process_vote(comment['id'], 'user_two', '1')
support.process_vote(comment['id'], 'user_three', '1')
check_rating(3)
support.process_vote(comment['id'], 'user_one', '-1')
check_rating(1)
support.process_vote(comment['id'], 'user_one', '0')
check_rating(2)
# Make sure a vote with value > 1 or < -1 can't be cast.
with pytest.raises(ValueError):
support.process_vote(comment['id'], 'user_one', '2')
with pytest.raises(ValueError):
support.process_vote(comment['id'], 'user_one', '-2')
# Make sure past voting data is associated with comments when they are
# fetched.
data = support.get_data(str(node.id), username='user_two')
comment = data['comments'][0]
assert comment['vote'] == 1, '%s != 1' % comment['vote']
def test_differ(): def test_differ():
source = 'Lorem ipsum dolor sit amet,\nconsectetur adipisicing elit,\n' \ source = 'Lorem ipsum dolor sit amet,\nconsectetur adipisicing elit,\n' \
'sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.' 'sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.'

View File

@ -11,7 +11,7 @@
from __future__ import print_function from __future__ import print_function
from sphinx.writers.latex import rstdim_to_latexdim from sphinx.writers.latex import rstdim_to_latexdim
from util import raises import pytest
def test_rstdim_to_latexdim(): def test_rstdim_to_latexdim():
@ -32,5 +32,6 @@ def test_rstdim_to_latexdim():
assert rstdim_to_latexdim('.5em') == '.5em' assert rstdim_to_latexdim('.5em') == '.5em'
# unknown values (it might be generated by 3rd party extension) # unknown values (it might be generated by 3rd party extension)
raises(ValueError, rstdim_to_latexdim, 'unknown') with pytest.raises(ValueError):
rstdim_to_latexdim('unknown')
assert rstdim_to_latexdim('160.0unknown') == '160.0unknown' assert rstdim_to_latexdim('160.0unknown') == '160.0unknown'

View File

@ -10,14 +10,13 @@
import os import os
import re import re
import sys import sys
import tempfile
import warnings import warnings
from functools import wraps from functools import wraps
from xml.etree import ElementTree from xml.etree import ElementTree
from six import StringIO, string_types from six import string_types
from nose import tools, SkipTest import pytest
from docutils import nodes from docutils import nodes
from docutils.parsers.rst import directives, roles from docutils.parsers.rst import directives, roles
@ -27,16 +26,17 @@ from sphinx.builders.latex import LaTeXBuilder
from sphinx.theming import Theme from sphinx.theming import Theme
from sphinx.ext.autodoc import AutoDirective from sphinx.ext.autodoc import AutoDirective
from sphinx.pycode import ModuleAnalyzer from sphinx.pycode import ModuleAnalyzer
from sphinx.deprecation import RemovedInSphinx17Warning
from path import path, repr_as # NOQA from path import path
__all__ = [ __all__ = [
'rootdir', 'tempdir', 'raises', 'raises_msg', 'rootdir', 'tempdir',
'skip_if', 'skip_unless', 'skip_unless_importable', 'Struct', 'skip_unless_importable', 'Struct',
'ListOutput', 'TestApp', 'with_app', 'gen_with_app', 'SphinxTestApp',
'path', 'with_tempdir', 'path',
'sprint', 'remove_unicode_literals', 'remove_unicode_literals',
] ]
@ -44,36 +44,6 @@ rootdir = path(os.path.dirname(__file__) or '.').abspath()
tempdir = path(os.environ['SPHINX_TEST_TEMPDIR']).abspath() tempdir = path(os.environ['SPHINX_TEST_TEMPDIR']).abspath()
def _excstr(exc):
if type(exc) is tuple:
return str(tuple(map(_excstr, exc)))
return exc.__name__
def raises(exc, func, *args, **kwds):
"""Raise AssertionError if ``func(*args, **kwds)`` does not raise *exc*."""
try:
func(*args, **kwds)
except exc:
pass
else:
raise AssertionError('%s did not raise %s' %
(func.__name__, _excstr(exc)))
def raises_msg(exc, msg, func, *args, **kwds):
"""Raise AssertionError if ``func(*args, **kwds)`` does not raise *exc*,
and check if the message contains *msg*.
"""
try:
func(*args, **kwds)
except exc as err:
assert msg in str(err), "\"%s\" not in \"%s\"" % (msg, err)
else:
raise AssertionError('%s did not raise %s' %
(func.__name__, _excstr(exc)))
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)
@ -118,43 +88,14 @@ 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])
try:
from nose.tools import assert_in, assert_not_in
except ImportError:
def assert_in(x, thing, msg=''):
if x not in thing:
assert False, msg or '%r is not in %r' % (x, thing)
def assert_not_in(x, thing, msg=''):
if x in thing:
assert False, msg or '%r is in %r' % (x, thing)
def skip_if(condition, msg=None):
"""Decorator to skip test if condition is true."""
def deco(test):
@tools.make_decorator(test)
def skipper(*args, **kwds):
if condition:
raise SkipTest(msg or 'conditional skip')
return test(*args, **kwds)
return skipper
return deco
def skip_unless(condition, msg=None):
"""Decorator to skip test if condition is false."""
return skip_if(not condition, msg)
def skip_unless_importable(module, msg=None): def skip_unless_importable(module, msg=None):
"""Decorator to skip test if module is not importable.""" """Decorator to skip test if module is not importable."""
try: try:
__import__(module) __import__(module)
except ImportError: except ImportError:
return skip_if(True, msg) return pytest.mark.skipif(True, reason=(msg or 'conditional skip'))
else: else:
return skip_if(False, msg) return pytest.mark.skipif(False, reason=(msg or 'conditional skip'))
def etree_parse(path): def etree_parse(path):
@ -168,22 +109,7 @@ class Struct(object):
self.__dict__.update(kwds) self.__dict__.update(kwds)
class ListOutput(object): class SphinxTestApp(application.Sphinx):
"""
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)
class TestApp(application.Sphinx):
""" """
A subclass of :class:`Sphinx` that runs on the test root, with some A subclass of :class:`Sphinx` that runs on the test root, with some
better default values for the initialization parameters. better default values for the initialization parameters.
@ -222,10 +148,6 @@ class TestApp(application.Sphinx):
doctreedir.makedirs() doctreedir.makedirs()
if confoverrides is None: if confoverrides is None:
confoverrides = {} confoverrides = {}
if status is None:
status = StringIO()
if warning is None:
warning = ListOutput('stderr')
# if warningiserror is None: # if warningiserror is None:
warningiserror = False warningiserror = False
@ -263,59 +185,6 @@ class TestApp(application.Sphinx):
return '<%s buildername=%r>' % (self.__class__.__name__, self.builder.name) return '<%s buildername=%r>' % (self.__class__.__name__, self.builder.name)
def with_app(*args, **kwargs):
"""
Make a TestApp with args and kwargs, pass it to the test and clean up
properly.
"""
def generator(func):
@wraps(func)
def deco(*args2, **kwargs2):
status, warning = StringIO(), StringIO()
kwargs['status'] = status
kwargs['warning'] = warning
app = TestApp(*args, **kwargs)
try:
func(app, status, warning, *args2, **kwargs2)
finally:
app.cleanup()
return deco
return generator
def gen_with_app(*args, **kwargs):
"""
Decorate a test generator to pass a TestApp 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 = TestApp(*args, **kwargs)
try:
for item in func(app, status, warning, *args2, **kwargs2):
yield item
finally:
app.cleanup()
return deco
return generator
def with_tempdir(func):
def new_func(*args, **kwds):
new_tempdir = path(tempfile.mkdtemp(dir=tempdir))
func(new_tempdir, *args, **kwds)
new_func.__name__ = func.__name__
return new_func
def sprint(*args):
sys.stderr.write(' '.join(map(str, args)) + '\n')
_unicode_literals_re = re.compile(r'u(".*?")|u(\'.*?\')') _unicode_literals_re = re.compile(r'u(".*?")|u(\'.*?\')')
@ -333,3 +202,163 @@ def find_files(root, suffix=None):
def strip_escseq(text): def strip_escseq(text):
return re.sub('\x1b.*?m', '', text) return re.sub('\x1b.*?m', '', text)
# #############################################
# DEPRECATED implementations
import tempfile
from six import StringIO
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'),
))