sphinx/tests/test_builders/test_build_html_5_output.py
Hugo van Kemenade 95b2cce9a0
Add a `versionremoved` directive (#11905)
Co-authored-by: C.A.M. Gerlach <CAM.Gerlach@Gerlach.CAM>
Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com>
2024-01-21 20:12:52 +00:00

277 lines
15 KiB
Python
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Test the HTML builder and check output against XPath."""
import re
import pytest
from tests.test_builders.test_build_html import check_xpath
def tail_check(check):
rex = re.compile(check)
def checker(nodes):
for node in nodes:
if node.tail and rex.search(node.tail):
return True
msg = f'{check!r} not found in tail of any nodes {nodes}'
raise AssertionError(msg)
return checker
@pytest.mark.parametrize(("fname", "path", "check"), [
('images.html', ".//img[@src='_images/img.png']", ''),
('images.html', ".//img[@src='_images/img1.png']", ''),
('images.html', ".//img[@src='_images/simg.png']", ''),
('images.html', ".//img[@src='_images/svgimg.svg']", ''),
('images.html', ".//a[@href='_sources/images.txt']", ''),
('subdir/images.html', ".//img[@src='../_images/img1.png']", ''),
('subdir/images.html', ".//img[@src='../_images/rimg.png']", ''),
('subdir/includes.html', ".//a[@class='reference download internal']", ''),
('subdir/includes.html', ".//img[@src='../_images/img.png']", ''),
('subdir/includes.html', ".//p", 'This is an include file.'),
('subdir/includes.html', ".//pre/span", 'line 1'),
('subdir/includes.html', ".//pre/span", 'line 2'),
('includes.html', ".//pre", 'Max Strauß'),
('includes.html', ".//a[@class='reference download internal']", ''),
('includes.html', ".//pre/span", '"quotes"'),
('includes.html', ".//pre/span", "'included'"),
('includes.html', ".//pre/span[@class='s2']", 'üöä'),
('includes.html', ".//div[@class='inc-pyobj1 highlight-text notranslate']//pre",
r'^class Foo:\n pass\n\s*$'),
('includes.html', ".//div[@class='inc-pyobj2 highlight-text notranslate']//pre",
r'^ def baz\(\):\n pass\n\s*$'),
('includes.html', ".//div[@class='inc-lines highlight-text notranslate']//pre",
r'^class Foo:\n pass\nclass Bar:\n$'),
('includes.html', ".//div[@class='inc-startend highlight-text notranslate']//pre",
'^foo = "Including Unicode characters: üöä"\\n$'),
('includes.html', ".//div[@class='inc-preappend highlight-text notranslate']//pre",
r'(?m)^START CODE$'),
('includes.html', ".//div[@class='inc-pyobj-dedent highlight-python notranslate']//span",
r'def'),
('includes.html', ".//div[@class='inc-tab3 highlight-text notranslate']//pre",
r'-| |-'),
('includes.html', ".//div[@class='inc-tab8 highlight-python notranslate']//pre/span",
r'-| |-'),
('autodoc.html', ".//dl[@class='py class']/dt[@id='autodoc_target.Class']", ''),
('autodoc.html', ".//dl[@class='py function']/dt[@id='autodoc_target.function']/em/span/span", r'\*\*'),
('autodoc.html', ".//dl[@class='py function']/dt[@id='autodoc_target.function']/em/span/span", r'kwds'),
('autodoc.html', ".//dd/p", r'Return spam\.'),
('extapi.html', ".//strong", 'from class: Bar'),
('markup.html', ".//title", 'set by title directive'),
('markup.html', ".//p/em", 'Section author: Georg Brandl'),
('markup.html', ".//p/em", 'Module author: Georg Brandl'),
# created by the meta directive
('markup.html', ".//meta[@name='author'][@content='Me']", ''),
('markup.html', ".//meta[@name='keywords'][@content='docs, sphinx']", ''),
# a label created by ``.. _label:``
('markup.html', ".//div[@id='label']", ''),
# code with standard code blocks
('markup.html', ".//pre", '^some code$'),
# an option list
('markup.html', ".//span[@class='option']", '--help'),
# admonitions
('markup.html', ".//p[@class='admonition-title']", 'My Admonition'),
('markup.html', ".//div[@class='admonition note']/p", 'Note text.'),
('markup.html', ".//div[@class='admonition warning']/p", 'Warning text.'),
# inline markup
('markup.html', ".//li/p/strong", r'^command\\n$'),
('markup.html', ".//li/p/strong", r'^program\\n$'),
('markup.html', ".//li/p/em", r'^dfn\\n$'),
('markup.html', ".//li/p/kbd", r'^kbd\\n$'),
('markup.html', ".//li/p/span", 'File \N{TRIANGULAR BULLET} Close'),
('markup.html', ".//li/p/code/span[@class='pre']", '^a/$'),
('markup.html', ".//li/p/code/em/span[@class='pre']", '^varpart$'),
('markup.html', ".//li/p/code/em/span[@class='pre']", '^i$'),
('markup.html', ".//a[@href='https://peps.python.org/pep-0008/']"
"[@class='pep reference external']/strong", 'PEP 8'),
('markup.html', ".//a[@href='https://peps.python.org/pep-0008/']"
"[@class='pep reference external']/strong",
'Python Enhancement Proposal #8'),
('markup.html', ".//a[@href='https://datatracker.ietf.org/doc/html/rfc1.html']"
"[@class='rfc reference external']/strong", 'RFC 1'),
('markup.html', ".//a[@href='https://datatracker.ietf.org/doc/html/rfc1.html']"
"[@class='rfc reference external']/strong", 'Request for Comments #1'),
('markup.html', ".//a[@href='objects.html#envvar-HOME']"
"[@class='reference internal']/code/span[@class='pre']", 'HOME'),
('markup.html', ".//a[@href='#with']"
"[@class='reference internal']/code/span[@class='pre']", '^with$'),
('markup.html', ".//a[@href='#grammar-token-try_stmt']"
"[@class='reference internal']/code/span", '^statement$'),
('markup.html', ".//a[@href='#some-label'][@class='reference internal']/span", '^here$'),
('markup.html', ".//a[@href='#some-label'][@class='reference internal']/span", '^there$'),
('markup.html', ".//a[@href='subdir/includes.html']"
"[@class='reference internal']/span", 'Including in subdir'),
('markup.html', ".//a[@href='objects.html#cmdoption-python-c']"
"[@class='reference internal']/code/span[@class='pre']", '-c'),
# abbreviations
('markup.html', ".//abbr[@title='abbreviation']", '^abbr$'),
# version stuff
('markup.html', ".//div[@class='versionadded']/p/span", 'New in version 0.6: '),
('markup.html', ".//div[@class='versionadded']/p/span",
tail_check('First paragraph of versionadded')),
('markup.html', ".//div[@class='versionchanged']/p/span",
tail_check('First paragraph of versionchanged')),
('markup.html', ".//div[@class='versionchanged']/p",
'Second paragraph of versionchanged'),
('markup.html', ".//div[@class='versionremoved']/p/span", 'Removed in version 0.6: '),
# footnote reference
('markup.html', ".//a[@class='footnote-reference brackets']", r'1'),
# created by reference lookup
('markup.html', ".//a[@href='index.html#ref1']", ''),
# ``seealso`` directive
('markup.html', ".//div/p[@class='admonition-title']", 'See also'),
# a ``hlist`` directive
('markup.html', ".//table[@class='hlist']/tbody/tr/td/ul/li/p", '^This$'),
# a ``centered`` directive
('markup.html', ".//p[@class='centered']/strong", 'LICENSE'),
# a glossary
('markup.html', ".//dl/dt[@id='term-boson']", 'boson'),
('markup.html', ".//dl/dt[@id='term-boson']/a", ''),
# a production list
('markup.html', ".//pre/strong", 'try_stmt'),
('markup.html', ".//pre/a[@href='#grammar-token-try1_stmt']/code/span", 'try1_stmt'),
# tests for ``only`` directive
('markup.html', ".//p", 'A global substitution!'),
('markup.html', ".//p", 'In HTML.'),
('markup.html', ".//p", 'In both.'),
('markup.html', ".//p", 'Always present'),
# tests for ``any`` role
('markup.html', ".//a[@href='#with']/span", 'headings'),
('markup.html', ".//a[@href='objects.html#func_without_body']/code/span", 'objects'),
# tests for numeric labels
('markup.html', ".//a[@href='#id1'][@class='reference internal']/span", 'Testing various markup'),
# tests for smartypants
('markup.html', ".//li/p", 'Smart “quotes” in English text.'),
('markup.html', ".//li/p", 'Smart — long and short dashes.'),
('markup.html', ".//li/p", 'Ellipsis…'),
('markup.html', ".//li/p/code/span[@class='pre']", 'foo--"bar"...'),
('markup.html', ".//p", 'Этот «абзац» должен использовать „русские“ кавычки.'),
('markup.html', ".//p", 'Il dit : « Cest “super” ! »'),
('objects.html', ".//dt[@id='mod.Cls.meth1']", ''),
('objects.html', ".//dt[@id='errmod.Error']", ''),
('objects.html', ".//dt/span[@class='sig-name descname']/span[@class='pre']", r'long\(parameter,'),
('objects.html', ".//dt/span[@class='sig-name descname']/span[@class='pre']", r'list\)'),
('objects.html', ".//dt/span[@class='sig-name descname']/span[@class='pre']", 'another'),
('objects.html', ".//dt/span[@class='sig-name descname']/span[@class='pre']", 'one'),
('objects.html', ".//a[@href='#mod.Cls'][@class='reference internal']", ''),
('objects.html', ".//dl[@class='std userdesc']", ''),
('objects.html', ".//dt[@id='userdesc-myobj']", ''),
('objects.html', ".//a[@href='#userdesc-myobj'][@class='reference internal']", ''),
# docfields
('objects.html', ".//a[@class='reference internal'][@href='#TimeInt']/em", 'TimeInt'),
('objects.html', ".//a[@class='reference internal'][@href='#Time']", 'Time'),
('objects.html', ".//a[@class='reference internal'][@href='#errmod.Error']/strong", 'Error'),
# C references
('objects.html', ".//span[@class='pre']", 'CFunction()'),
('objects.html', ".//a[@href='#c.Sphinx_DoSomething']", ''),
('objects.html', ".//a[@href='#c.SphinxStruct.member']", ''),
('objects.html', ".//a[@href='#c.SPHINX_USE_PYTHON']", ''),
('objects.html', ".//a[@href='#c.SphinxType']", ''),
('objects.html', ".//a[@href='#c.sphinx_global']", ''),
# test global TOC created by toctree()
('objects.html', ".//ul[@class='current']/li[@class='toctree-l1 current']/a[@href='#']",
'Testing object descriptions'),
('objects.html', ".//li[@class='toctree-l1']/a[@href='markup.html']",
'Testing various markup'),
# test unknown field names
('objects.html', ".//dt[@class='field-odd']", 'Field_name'),
('objects.html', ".//dt[@class='field-even']", 'Field_name all lower'),
('objects.html', ".//dt[@class='field-odd']", 'FIELD_NAME'),
('objects.html', ".//dt[@class='field-even']", 'FIELD_NAME ALL CAPS'),
('objects.html', ".//dt[@class='field-odd']", 'Field_Name'),
('objects.html', ".//dt[@class='field-even']", 'Field_Name All Word Caps'),
# ('objects.html', ".//dt[@class='field-odd']", 'Field_name'), (duplicate)
('objects.html', ".//dt[@class='field-even']", 'Field_name First word cap'),
('objects.html', ".//dt[@class='field-odd']", 'FIELd_name'),
('objects.html', ".//dt[@class='field-even']", 'FIELd_name PARTial caps'),
# custom sidebar
('objects.html', ".//h4", 'Custom sidebar'),
# docfields
('objects.html', ".//dd[@class='field-odd']/p/strong", '^moo$'),
('objects.html', ".//dd[@class='field-odd']/p/strong", tail_check(r'\(Moo\) .* Moo')),
('objects.html', ".//dd[@class='field-odd']/ul/li/p/strong", '^hour$'),
('objects.html', ".//dd[@class='field-odd']/ul/li/p/em", '^DuplicateType$'),
('objects.html', ".//dd[@class='field-odd']/ul/li/p/em", tail_check(r'.* Some parameter')),
# others
('objects.html', ".//a[@class='reference internal'][@href='#cmdoption-perl-arg-p']/code/span",
'perl'),
('objects.html', ".//a[@class='reference internal'][@href='#cmdoption-perl-arg-p']/code/span",
'\\+p'),
('objects.html', ".//a[@class='reference internal'][@href='#cmdoption-perl-ObjC']/code/span",
'--ObjC\\+\\+'),
('objects.html', ".//a[@class='reference internal'][@href='#cmdoption-perl-plugin.option']/code/span",
'--plugin.option'),
('objects.html', ".//a[@class='reference internal'][@href='#cmdoption-perl-arg-create-auth-token']"
"/code/span",
'create-auth-token'),
('objects.html', ".//a[@class='reference internal'][@href='#cmdoption-perl-arg-arg']/code/span",
'arg'),
('objects.html', ".//a[@class='reference internal'][@href='#cmdoption-perl-j']/code/span",
'-j'),
('objects.html', ".//a[@class='reference internal'][@href='#cmdoption-hg-arg-commit']/code/span",
'hg'),
('objects.html', ".//a[@class='reference internal'][@href='#cmdoption-hg-arg-commit']/code/span",
'commit'),
('objects.html', ".//a[@class='reference internal'][@href='#cmdoption-git-commit-p']/code/span",
'git'),
('objects.html', ".//a[@class='reference internal'][@href='#cmdoption-git-commit-p']/code/span",
'commit'),
('objects.html', ".//a[@class='reference internal'][@href='#cmdoption-git-commit-p']/code/span",
'-p'),
('index.html', ".//meta[@name='hc'][@content='hcval']", ''),
('index.html', ".//meta[@name='hc_co'][@content='hcval_co']", ''),
('index.html', ".//li[@class='toctree-l1']/a", 'Testing various markup'),
('index.html', ".//li[@class='toctree-l2']/a", 'Inline markup'),
('index.html', ".//title", 'Sphinx <Tests>'),
('index.html', ".//div[@class='footer']", 'copyright text credits'),
('index.html', ".//a[@href='https://python.org/']"
"[@class='reference external']", ''),
('index.html', ".//li/p/a[@href='genindex.html']/span", 'Index'),
('index.html', ".//li/p/a[@href='py-modindex.html']/span", 'Module Index'),
# custom sidebar only for contents
('index.html', ".//h4", 'Contents sidebar'),
# custom JavaScript
('index.html', ".//script[@src='file://moo.js']", ''),
# URL in contents
('index.html', ".//a[@class='reference external'][@href='https://sphinx-doc.org/']",
'https://sphinx-doc.org/'),
('index.html', ".//a[@class='reference external'][@href='https://sphinx-doc.org/latest/']",
'Latest reference'),
# Indirect hyperlink targets across files
('index.html', ".//a[@href='markup.html#some-label'][@class='reference internal']/span",
'^indirect hyperref$'),
('bom.html', ".//title", " File with UTF-8 BOM"),
('extensions.html', ".//a[@href='https://python.org/dev/']", "https://python.org/dev/"),
('extensions.html', ".//a[@href='https://bugs.python.org/issue1000']", "issue 1000"),
('extensions.html', ".//a[@href='https://bugs.python.org/issue1042']", "explicit caption"),
# index entries
('genindex.html', ".//a/strong", "Main"),
('genindex.html', ".//a/strong", "[1]"),
('genindex.html', ".//a/strong", "Other"),
('genindex.html', ".//a", "entry"),
('genindex.html', ".//li/a", "double"),
('otherext.html', ".//h1", "Generated section"),
('otherext.html', ".//a[@href='_sources/otherext.foo.txt']", ''),
('search.html', ".//meta[@name='robots'][@content='noindex']", ''),
])
@pytest.mark.sphinx('html', tags=['testtag'],
confoverrides={'html_context.hckey_co': 'hcval_co'})
@pytest.mark.test_params(shared_result='test_build_html_output')
def test_html5_output(app, cached_etree_parse, fname, path, check):
app.build()
check_xpath(cached_etree_parse(app.outdir / fname), fname, path, check)