Spring-clean `sphinx.testing.utils` (#11534)

This commit is contained in:
Adam Turner 2023-07-28 23:24:13 +01:00 committed by GitHub
parent 1cfb68d8be
commit 629b862cde
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 27 additions and 59 deletions

View File

@ -1,7 +1,6 @@
"""Sphinx test suite utilities""" """Sphinx test suite utilities"""
from __future__ import annotations from __future__ import annotations
import functools
import os import os
import re import re
import sys import sys
@ -20,24 +19,7 @@ if TYPE_CHECKING:
from io import StringIO from io import StringIO
from pathlib import Path from pathlib import Path
__all__ = [ __all__ = 'SphinxTestApp', 'SphinxTestAppWrapperForSkipBuilding'
'Struct', 'SphinxTestApp', 'SphinxTestAppWrapperForSkipBuilding',
]
def assert_re_search(regex: re.Pattern, text: str, flags: int = 0) -> None:
if not re.search(regex, text, flags):
raise AssertionError(f'{regex!r} did not match {text!r}')
def assert_not_re_search(regex: re.Pattern, text: str, flags: int = 0) -> None:
if re.search(regex, text, flags):
raise AssertionError(f'{regex!r} did match {text!r}')
def assert_startswith(thing: str, prefix: str) -> None:
if not thing.startswith(prefix):
raise AssertionError(f'{thing!r} does not start with {prefix!r}')
def assert_node(node: Node, cls: Any = None, xpath: str = "", **kwargs: Any) -> None: def assert_node(node: Node, cls: Any = None, xpath: str = "", **kwargs: Any) -> None:
@ -86,11 +68,6 @@ def etree_parse(path: str) -> Any:
return ElementTree.parse(path) # NoQA: S314 # using known data in tests return ElementTree.parse(path) # NoQA: S314 # using known data in tests
class Struct:
def __init__(self, **kwargs: Any) -> None:
self.__dict__.update(kwargs)
class SphinxTestApp(application.Sphinx): class SphinxTestApp(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
@ -190,18 +167,5 @@ class SphinxTestAppWrapperForSkipBuilding:
# otherwise, we can use built cache # otherwise, we can use built cache
_unicode_literals_re = re.compile(r'u(".*?")|u(\'.*?\')')
def strip_escseq(text: str) -> str: def strip_escseq(text: str) -> str:
return re.sub('\x1b.*?m', '', text) return re.sub('\x1b.*?m', '', text)
def simple_decorator(f):
"""
A simple decorator that does nothing, for tests to use.
"""
@functools.wraps(f)
def wrapper(*args, **kwargs):
return f(*args, **kwargs)
return wrapper

View File

@ -5,6 +5,7 @@ source file translated by test_build.
""" """
import sys import sys
from types import SimpleNamespace
from unittest.mock import Mock from unittest.mock import Mock
from warnings import catch_warnings from warnings import catch_warnings
@ -14,7 +15,6 @@ from docutils.statemachine import ViewList
from sphinx import addnodes from sphinx import addnodes
from sphinx.ext.autodoc import ALL, ModuleLevelDocumenter, Options from sphinx.ext.autodoc import ALL, ModuleLevelDocumenter, Options
from sphinx.ext.autodoc.directive import DocumenterBridge, process_documenter_options from sphinx.ext.autodoc.directive import DocumenterBridge, process_documenter_options
from sphinx.testing.util import SphinxTestApp, Struct # noqa: F401
from sphinx.util.docutils import LoggingReporter from sphinx.util.docutils import LoggingReporter
try: try:
@ -59,7 +59,7 @@ def make_directive_bridge(env):
ignore_module_all = False, ignore_module_all = False,
) )
directive = Struct( directive = SimpleNamespace(
env = env, env = env,
genopt = options, genopt = options,
result = ViewList(), result = ViewList(),

View File

@ -1,5 +1,6 @@
"""Tests for :mod:`sphinx.ext.napoleon.__init__` module.""" """Tests for :mod:`sphinx.ext.napoleon.__init__` module."""
import functools
from collections import namedtuple from collections import namedtuple
from unittest import mock from unittest import mock
@ -7,7 +8,16 @@ import pytest
from sphinx.application import Sphinx from sphinx.application import Sphinx
from sphinx.ext.napoleon import Config, _process_docstring, _skip_member, setup from sphinx.ext.napoleon import Config, _process_docstring, _skip_member, setup
from sphinx.testing.util import simple_decorator
def simple_decorator(f):
"""
A simple decorator that does nothing, for tests to use.
"""
@functools.wraps(f)
def wrapper(*args, **kwargs):
return f(*args, **kwargs)
return wrapper
def _private_doc(): def _private_doc():

View File

@ -17,14 +17,7 @@ from babel.messages.catalog import Catalog
from docutils import nodes from docutils import nodes
from sphinx import locale from sphinx import locale
from sphinx.testing.util import ( from sphinx.testing.util import assert_node, etree_parse, strip_escseq
assert_node,
assert_not_re_search,
assert_re_search,
assert_startswith,
etree_parse,
strip_escseq,
)
from sphinx.util.nodes import NodeMatcher from sphinx.util.nodes import NodeMatcher
sphinx_intl = pytest.mark.sphinx( sphinx_intl = pytest.mark.sphinx(
@ -105,7 +98,7 @@ def test_text_emit_warnings(app, warning):
warnings = getwarning(warning) warnings = getwarning(warning)
warning_expr = ('.*/warnings.txt:4:<translated>:1: ' warning_expr = ('.*/warnings.txt:4:<translated>:1: '
'WARNING: Inline literal start-string without end-string.\n') 'WARNING: Inline literal start-string without end-string.\n')
assert_re_search(warning_expr, warnings) assert re.search(warning_expr, warnings), f'{warning_expr!r} did not match {warnings!r}'
@sphinx_intl @sphinx_intl
@ -142,7 +135,7 @@ def test_text_subdirs(app):
app.build() app.build()
# --- check translation in subdirs # --- check translation in subdirs
result = (app.outdir / 'subdir' / 'index.txt').read_text(encoding='utf8') result = (app.outdir / 'subdir' / 'index.txt').read_text(encoding='utf8')
assert_startswith(result, "1. subdir contents\n******************\n") assert result.startswith('1. subdir contents\n******************\n')
@sphinx_intl @sphinx_intl
@ -187,12 +180,12 @@ def test_text_inconsistency_warnings(app, warning):
'original': "\\[\\]", 'original': "\\[\\]",
'translated': "\\['`I18N WITH REFS INCONSISTENCY`_'\\]", 'translated': "\\['`I18N WITH REFS INCONSISTENCY`_'\\]",
}) })
assert_re_search(expected_warning_expr, warnings) assert re.search(expected_warning_expr, warnings), f'{expected_warning_expr!r} did not match {warnings!r}'
expected_citation_warning_expr = ( expected_citation_warning_expr = (
'.*/refs_inconsistency.txt:\\d+: WARNING: Citation \\[ref2\\] is not referenced.\n' + '.*/refs_inconsistency.txt:\\d+: WARNING: Citation \\[ref2\\] is not referenced.\n' +
'.*/refs_inconsistency.txt:\\d+: WARNING: citation not found: ref3') '.*/refs_inconsistency.txt:\\d+: WARNING: citation not found: ref3')
assert_re_search(expected_citation_warning_expr, warnings) assert re.search(expected_citation_warning_expr, warnings), f'{expected_citation_warning_expr!r} did not match {warnings!r}'
@sphinx_intl @sphinx_intl
@ -235,12 +228,12 @@ def test_text_literalblock_warnings(app, warning):
"\n literal block\n" "\n literal block\n"
"\nMISSING LITERAL BLOCK:\n" "\nMISSING LITERAL BLOCK:\n"
"\n<SYSTEM MESSAGE:") "\n<SYSTEM MESSAGE:")
assert_startswith(result, expect) assert result.startswith(expect)
warnings = getwarning(warning) warnings = getwarning(warning)
expected_warning_expr = ('.*/literalblock.txt:\\d+: ' expected_warning_expr = ('.*/literalblock.txt:\\d+: '
'WARNING: Literal block expected; none found.') 'WARNING: Literal block expected; none found.')
assert_re_search(expected_warning_expr, warnings) assert re.search(expected_warning_expr, warnings), f'{expected_warning_expr!r} did not match {warnings!r}'
@sphinx_intl @sphinx_intl
@ -316,7 +309,7 @@ def test_text_glossary_term_inconsistencies(app, warning):
'WARNING: inconsistent term references in translated message.' 'WARNING: inconsistent term references in translated message.'
" original: \\[':term:`Some term`', ':term:`Some other term`'\\]," " original: \\[':term:`Some term`', ':term:`Some other term`'\\],"
" translated: \\[':term:`SOME NEW TERM`'\\]\n") " translated: \\[':term:`SOME NEW TERM`'\\]\n")
assert_re_search(expected_warning_expr, warnings) assert re.search(expected_warning_expr, warnings), f'{expected_warning_expr!r} did not match {warnings!r}'
@sphinx_intl @sphinx_intl
@ -798,7 +791,7 @@ def test_html_index_entries(app):
wrap_nest('li', 'ul', 'SEE'), wrap_nest('li', 'ul', 'SEE'),
] ]
for expr in expected_exprs: for expr in expected_exprs:
assert_re_search(expr, result, re.M) assert re.search(expr, result, re.MULTILINE), f'{expr!r} did not match {result!r}'
@sphinx_intl @sphinx_intl
@ -927,7 +920,7 @@ def test_xml_footnotes(app, warning):
warnings = getwarning(warning) warnings = getwarning(warning)
warning_expr = '.*/footnote.xml:\\d*: SEVERE: Duplicate ID: ".*".\n' warning_expr = '.*/footnote.xml:\\d*: SEVERE: Duplicate ID: ".*".\n'
assert_not_re_search(warning_expr, warnings) assert not re.search(warning_expr, warnings), f'{warning_expr!r} did match {warnings!r}'
@sphinx_intl @sphinx_intl

View File

@ -2,6 +2,7 @@
import re import re
import warnings import warnings
from types import SimpleNamespace
import pytest import pytest
from docutils import frontend, nodes, utils from docutils import frontend, nodes, utils
@ -12,7 +13,7 @@ from sphinx.builders.html.transforms import KeyboardTransform
from sphinx.builders.latex import LaTeXBuilder from sphinx.builders.latex import LaTeXBuilder
from sphinx.environment import default_settings from sphinx.environment import default_settings
from sphinx.roles import XRefRole from sphinx.roles import XRefRole
from sphinx.testing.util import Struct, assert_node from sphinx.testing.util import assert_node
from sphinx.transforms import SphinxSmartQuotes from sphinx.transforms import SphinxSmartQuotes
from sphinx.util import texescape from sphinx.util import texescape
from sphinx.util.docutils import sphinx_domains from sphinx.util.docutils import sphinx_domains
@ -55,7 +56,7 @@ def new_document(settings):
def inliner(new_document): def inliner(new_document):
document = new_document() document = new_document()
document.reporter.get_source_and_line = lambda line=1: ('dummy.rst', line) document.reporter.get_source_and_line = lambda line=1: ('dummy.rst', line)
return Struct(document=document, reporter=document.reporter) return SimpleNamespace(document=document, reporter=document.reporter)
@pytest.fixture() @pytest.fixture()