summaryrefslogtreecommitdiffstats
path: root/tests/test_domains
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test_domains')
-rw-r--r--tests/test_domains/test_domain_cpp.py108
-rw-r--r--tests/test_domains/test_domain_py.py80
-rw-r--r--tests/test_domains/test_domain_py_pyobject.py71
3 files changed, 187 insertions, 72 deletions
diff --git a/tests/test_domains/test_domain_cpp.py b/tests/test_domains/test_domain_cpp.py
index abd0f82..d8e612e 100644
--- a/tests/test_domains/test_domain_cpp.py
+++ b/tests/test_domains/test_domain_cpp.py
@@ -1046,19 +1046,21 @@ def test_domain_cpp_ast_attributes():
check('enumerator', '{key}Foo [[attr1]] [[attr2]] = 42', {2: '3Foo'})
+def check_ast_xref_parsing(target):
+ class Config:
+ cpp_id_attributes = ["id_attr"]
+ cpp_paren_attributes = ["paren_attr"]
+
+ parser = DefinitionParser(target, location='', config=Config())
+ parser.parse_xref_object()
+ parser.assert_end()
+
+
def test_domain_cpp_ast_xref_parsing():
- def check(target):
- class Config:
- cpp_id_attributes = ["id_attr"]
- cpp_paren_attributes = ["paren_attr"]
- parser = DefinitionParser(target, location=None,
- config=Config())
- ast, isShorthand = parser.parse_xref_object()
- parser.assert_end()
- check('f')
- check('f()')
- check('void f()')
- check('T f()')
+ check_ast_xref_parsing('f')
+ check_ast_xref_parsing('f()')
+ check_ast_xref_parsing('void f()')
+ check_ast_xref_parsing('T f()')
@pytest.mark.parametrize(
@@ -1213,18 +1215,12 @@ def test_domain_cpp_build_misuse_of_roles(app, status, warning):
def test_domain_cpp_build_with_add_function_parentheses_is_True(app, status, warning):
app.build(force_all=True)
- def check(spec, text, file):
- pattern = '<li><p>%s<a .*?><code .*?><span .*?>%s</span></code></a></p></li>' % spec
- res = re.search(pattern, text)
- if not res:
- print(f"Pattern\n\t{pattern}\nnot found in {file}")
- raise AssertionError
rolePatterns = [
- ('', 'Sphinx'),
- ('', 'Sphinx::version'),
- ('', 'version'),
- ('', 'List'),
- ('', 'MyEnum'),
+ 'Sphinx',
+ 'Sphinx::version',
+ 'version',
+ 'List',
+ 'MyEnum',
]
parenPatterns = [
('ref function without parens ', r'paren_1\(\)'),
@@ -1237,35 +1233,33 @@ def test_domain_cpp_build_with_add_function_parentheses_is_True(app, status, war
('ref op call with parens, explicit title ', 'paren_8_title'),
]
- f = 'roles.html'
- t = (app.outdir / f).read_text(encoding='utf8')
- for s in rolePatterns:
- check(s, t, f)
- for s in parenPatterns:
- check(s, t, f)
+ text = (app.outdir / 'roles.html').read_text(encoding='utf8')
+ for ref_text in rolePatterns:
+ pattern = f'<li><p><a .*?><code .*?><span .*?>{ref_text}</span></code></a></p></li>'
+ match = re.search(pattern, text)
+ assert match is not None, f"Pattern not found in roles.html:\n\t{pattern}"
+ for (desc_text, ref_text) in parenPatterns:
+ pattern = f'<li><p>{desc_text}<a .*?><code .*?><span .*?>{ref_text}</span></code></a></p></li>'
+ match = re.search(pattern, text)
+ assert match is not None, f"Pattern not found in roles.html:\n\t{pattern}"
- f = 'any-role.html'
- t = (app.outdir / f).read_text(encoding='utf8')
- for s in parenPatterns:
- check(s, t, f)
+ text = (app.outdir / 'any-role.html').read_text(encoding='utf8')
+ for (desc_text, ref_text) in parenPatterns:
+ pattern = f'<li><p>{desc_text}<a .*?><code .*?><span .*?>{ref_text}</span></code></a></p></li>'
+ match = re.search(pattern, text)
+ assert match is not None, f"Pattern not found in any-role.html:\n\t{pattern}"
@pytest.mark.sphinx(testroot='domain-cpp', confoverrides={'add_function_parentheses': False})
def test_domain_cpp_build_with_add_function_parentheses_is_False(app, status, warning):
app.build(force_all=True)
- def check(spec, text, file):
- pattern = '<li><p>%s<a .*?><code .*?><span .*?>%s</span></code></a></p></li>' % spec
- res = re.search(pattern, text)
- if not res:
- print(f"Pattern\n\t{pattern}\nnot found in {file}")
- raise AssertionError
rolePatterns = [
- ('', 'Sphinx'),
- ('', 'Sphinx::version'),
- ('', 'version'),
- ('', 'List'),
- ('', 'MyEnum'),
+ 'Sphinx',
+ 'Sphinx::version',
+ 'version',
+ 'List',
+ 'MyEnum',
]
parenPatterns = [
('ref function without parens ', 'paren_1'),
@@ -1278,17 +1272,21 @@ def test_domain_cpp_build_with_add_function_parentheses_is_False(app, status, wa
('ref op call with parens, explicit title ', 'paren_8_title'),
]
- f = 'roles.html'
- t = (app.outdir / f).read_text(encoding='utf8')
- for s in rolePatterns:
- check(s, t, f)
- for s in parenPatterns:
- check(s, t, f)
-
- f = 'any-role.html'
- t = (app.outdir / f).read_text(encoding='utf8')
- for s in parenPatterns:
- check(s, t, f)
+ text = (app.outdir / 'roles.html').read_text(encoding='utf8')
+ for ref_text in rolePatterns:
+ pattern = f'<li><p><a .*?><code .*?><span .*?>{ref_text}</span></code></a></p></li>'
+ match = re.search(pattern, text)
+ assert match is not None, f"Pattern not found in roles.html:\n\t{pattern}"
+ for (desc_text, ref_text) in parenPatterns:
+ pattern = f'<li><p>{desc_text}<a .*?><code .*?><span .*?>{ref_text}</span></code></a></p></li>'
+ match = re.search(pattern, text)
+ assert match is not None, f"Pattern not found in roles.html:\n\t{pattern}"
+
+ text = (app.outdir / 'any-role.html').read_text(encoding='utf8')
+ for (desc_text, ref_text) in parenPatterns:
+ pattern = f'<li><p>{desc_text}<a .*?><code .*?><span .*?>{ref_text}</span></code></a></p></li>'
+ match = re.search(pattern, text)
+ assert match is not None, f"Pattern not found in any-role.html:\n\t{pattern}"
@pytest.mark.sphinx(testroot='domain-cpp')
diff --git a/tests/test_domains/test_domain_py.py b/tests/test_domains/test_domain_py.py
index e653c80..ce3d444 100644
--- a/tests/test_domains/test_domain_py.py
+++ b/tests/test_domains/test_domain_py.py
@@ -92,19 +92,21 @@ def test_domain_py_xrefs(app, status, warning):
refnodes = list(doctree.findall(pending_xref))
assert_refnode(refnodes[0], None, None, 'TopLevel', 'class')
assert_refnode(refnodes[1], None, None, 'top_level', 'meth')
- assert_refnode(refnodes[2], None, 'NestedParentA', 'child_1', 'meth')
- assert_refnode(refnodes[3], None, 'NestedParentA', 'NestedChildA.subchild_2', 'meth')
- assert_refnode(refnodes[4], None, 'NestedParentA', 'child_2', 'meth')
- assert_refnode(refnodes[5], False, 'NestedParentA', 'any_child', domain='')
- assert_refnode(refnodes[6], None, 'NestedParentA', 'NestedChildA', 'class')
- assert_refnode(refnodes[7], None, 'NestedParentA.NestedChildA', 'subchild_2', 'meth')
- assert_refnode(refnodes[8], None, 'NestedParentA.NestedChildA',
+ assert_refnode(refnodes[2], None, None, 'TopLevelType', 'type')
+ assert_refnode(refnodes[3], None, 'NestedParentA', 'child_1', 'meth')
+ assert_refnode(refnodes[4], None, 'NestedParentA', 'NestedChildA.subchild_2', 'meth')
+ assert_refnode(refnodes[5], None, 'NestedParentA', 'child_2', 'meth')
+ assert_refnode(refnodes[6], False, 'NestedParentA', 'any_child', domain='')
+ assert_refnode(refnodes[7], None, 'NestedParentA', 'NestedChildA', 'class')
+ assert_refnode(refnodes[8], None, 'NestedParentA.NestedChildA', 'subchild_2', 'meth')
+ assert_refnode(refnodes[9], None, 'NestedParentA.NestedChildA',
'NestedParentA.child_1', 'meth')
- assert_refnode(refnodes[9], None, 'NestedParentA', 'NestedChildA.subchild_1', 'meth')
- assert_refnode(refnodes[10], None, 'NestedParentB', 'child_1', 'meth')
- assert_refnode(refnodes[11], None, 'NestedParentB', 'NestedParentB', 'class')
- assert_refnode(refnodes[12], None, None, 'NestedParentA.NestedChildA', 'class')
- assert len(refnodes) == 13
+ assert_refnode(refnodes[10], None, 'NestedParentA', 'NestedChildA.subchild_1', 'meth')
+ assert_refnode(refnodes[11], None, 'NestedParentB', 'child_1', 'meth')
+ assert_refnode(refnodes[12], None, 'NestedParentB', 'NestedParentB', 'class')
+ assert_refnode(refnodes[13], None, None, 'NestedParentA.NestedChildA', 'class')
+ assert_refnode(refnodes[14], None, None, 'NestedParentA.NestedTypeA', 'type')
+ assert len(refnodes) == 15
doctree = app.env.get_doctree('module')
refnodes = list(doctree.findall(pending_xref))
@@ -135,7 +137,10 @@ def test_domain_py_xrefs(app, status, warning):
assert_refnode(refnodes[15], False, False, 'index', 'doc', domain='std')
assert_refnode(refnodes[16], False, False, 'typing.Literal', 'obj', domain='py')
assert_refnode(refnodes[17], False, False, 'typing.Literal', 'obj', domain='py')
- assert len(refnodes) == 18
+ assert_refnode(refnodes[18], False, False, 'list', 'class', domain='py')
+ assert_refnode(refnodes[19], False, False, 'int', 'class', domain='py')
+ assert_refnode(refnodes[20], False, False, 'str', 'class', domain='py')
+ assert len(refnodes) == 21
doctree = app.env.get_doctree('module_option')
refnodes = list(doctree.findall(pending_xref))
@@ -191,7 +196,9 @@ def test_domain_py_objects(app, status, warning):
assert objects['TopLevel'][2] == 'class'
assert objects['top_level'][2] == 'method'
+ assert objects['TopLevelType'][2] == 'type'
assert objects['NestedParentA'][2] == 'class'
+ assert objects['NestedParentA.NestedTypeA'][2] == 'type'
assert objects['NestedParentA.child_1'][2] == 'method'
assert objects['NestedParentA.any_child'][2] == 'method'
assert objects['NestedParentA.NestedChildA'][2] == 'class'
@@ -233,6 +240,9 @@ def test_domain_py_find_obj(app, status, warning):
assert (find_obj(None, None, 'NONEXISTANT', 'class') == [])
assert (find_obj(None, None, 'NestedParentA', 'class') ==
[('NestedParentA', ('roles', 'NestedParentA', 'class', False))])
+ assert (find_obj(None, None, 'NestedParentA.NestedTypeA', 'type') ==
+ [('NestedParentA.NestedTypeA',
+ ('roles', 'NestedParentA.NestedTypeA', 'type', False))])
assert (find_obj(None, None, 'NestedParentA.NestedChildA', 'class') ==
[('NestedParentA.NestedChildA',
('roles', 'NestedParentA.NestedChildA', 'class', False))])
@@ -360,6 +370,27 @@ def test_parse_annotation(app):
[desc_sig_punctuation, "]"]))
assert_node(doctree[0], pending_xref, refdomain="py", reftype="obj", reftarget="typing.Literal")
+ # Annotated type with callable gets parsed
+ doctree = _parse_annotation("Annotated[Optional[str], annotated_types.MaxLen(max_length=10)]", app.env)
+ assert_node(doctree, (
+ [pending_xref, 'Annotated'],
+ [desc_sig_punctuation, '['],
+ [pending_xref, 'str'],
+ [desc_sig_space, ' '],
+ [desc_sig_punctuation, '|'],
+ [desc_sig_space, ' '],
+ [pending_xref, 'None'],
+ [desc_sig_punctuation, ','],
+ [desc_sig_space, ' '],
+ [pending_xref, 'annotated_types.MaxLen'],
+ [desc_sig_punctuation, '('],
+ [desc_sig_name, 'max_length'],
+ [desc_sig_operator, '='],
+ [desc_sig_literal_number, '10'],
+ [desc_sig_punctuation, ')'],
+ [desc_sig_punctuation, ']'],
+ ))
+
def test_parse_annotation_suppress(app):
doctree = _parse_annotation("~typing.Dict[str, str]", app.env)
@@ -743,7 +774,7 @@ def test_function_pep_695(app):
S,\
T: int,\
U: (int, str),\
- R: int | int,\
+ R: int | str,\
A: int | Annotated[int, ctype("char")],\
*V,\
**P\
@@ -785,14 +816,29 @@ def test_function_pep_695(app):
desc_sig_space,
[desc_sig_punctuation, '|'],
desc_sig_space,
- [pending_xref, 'int'],
+ [pending_xref, 'str'],
)],
)],
[desc_type_parameter, (
[desc_sig_name, 'A'],
[desc_sig_punctuation, ':'],
desc_sig_space,
- [desc_sig_name, ([pending_xref, 'int | Annotated[int, ctype("char")]'])],
+ [desc_sig_name, (
+ [pending_xref, 'int'],
+ [desc_sig_space, ' '],
+ [desc_sig_punctuation, '|'],
+ [desc_sig_space, ' '],
+ [pending_xref, 'Annotated'],
+ [desc_sig_punctuation, '['],
+ [pending_xref, 'int'],
+ [desc_sig_punctuation, ','],
+ [desc_sig_space, ' '],
+ [pending_xref, 'ctype'],
+ [desc_sig_punctuation, '('],
+ [desc_sig_literal_string, "'char'"],
+ [desc_sig_punctuation, ')'],
+ [desc_sig_punctuation, ']'],
+ )],
)],
[desc_type_parameter, (
[desc_sig_operator, '*'],
@@ -977,7 +1023,7 @@ def test_class_def_pep_696(app):
('[T:(*Ts)|int]', '[T: (*Ts) | int]'),
('[T:(int|(*Ts))]', '[T: (int | (*Ts))]'),
('[T:((*Ts)|int)]', '[T: ((*Ts) | int)]'),
- ('[T:Annotated[int,ctype("char")]]', '[T: Annotated[int, ctype("char")]]'),
+ ("[T:Annotated[int,ctype('char')]]", "[T: Annotated[int, ctype('char')]]"),
])
def test_pep_695_and_pep_696_whitespaces_in_bound(app, tp_list, tptext):
text = f'.. py:function:: f{tp_list}()'
diff --git a/tests/test_domains/test_domain_py_pyobject.py b/tests/test_domains/test_domain_py_pyobject.py
index 04f9341..adc0453 100644
--- a/tests/test_domains/test_domain_py_pyobject.py
+++ b/tests/test_domains/test_domain_py_pyobject.py
@@ -2,6 +2,7 @@
from __future__ import annotations
+import pytest
from docutils import nodes
from sphinx import addnodes
@@ -362,6 +363,76 @@ def test_pyproperty(app):
assert domain.objects['Class.prop2'] == ('index', 'Class.prop2', 'property', False)
+def test_py_type_alias(app):
+ text = (".. py:module:: example\n"
+ ".. py:type:: Alias1\n"
+ " :canonical: list[str | int]\n"
+ "\n"
+ ".. py:class:: Class\n"
+ "\n"
+ " .. py:type:: Alias2\n"
+ " :canonical: int\n")
+ domain = app.env.get_domain('py')
+ doctree = restructuredtext.parse(app, text)
+ assert_node(doctree, (addnodes.index,
+ addnodes.index,
+ nodes.target,
+ [desc, ([desc_signature, ([desc_annotation, ('type', desc_sig_space)],
+ [desc_addname, 'example.'],
+ [desc_name, 'Alias1'],
+ [desc_annotation, (desc_sig_space,
+ [desc_sig_punctuation, '='],
+ desc_sig_space,
+ [pending_xref, 'list'],
+ [desc_sig_punctuation, '['],
+ [pending_xref, 'str'],
+ desc_sig_space,
+ [desc_sig_punctuation, '|'],
+ desc_sig_space,
+ [pending_xref, 'int'],
+ [desc_sig_punctuation, ']'],
+ )])],
+ [desc_content, ()])],
+ addnodes.index,
+ [desc, ([desc_signature, ([desc_annotation, ('class', desc_sig_space)],
+ [desc_addname, 'example.'],
+ [desc_name, 'Class'])],
+ [desc_content, (addnodes.index,
+ desc)])]))
+ assert_node(doctree[5][1][0], addnodes.index,
+ entries=[('single', 'Alias2 (type alias in example.Class)', 'example.Class.Alias2', '', None)])
+ assert_node(doctree[5][1][1], ([desc_signature, ([desc_annotation, ('type', desc_sig_space)],
+ [desc_name, 'Alias2'],
+ [desc_annotation, (desc_sig_space,
+ [desc_sig_punctuation, '='],
+ desc_sig_space,
+ [pending_xref, 'int'])])],
+ [desc_content, ()]))
+ assert 'example.Alias1' in domain.objects
+ assert domain.objects['example.Alias1'] == ('index', 'example.Alias1', 'type', False)
+ assert 'example.Class.Alias2' in domain.objects
+ assert domain.objects['example.Class.Alias2'] == ('index', 'example.Class.Alias2', 'type', False)
+
+
+@pytest.mark.sphinx('html', testroot='domain-py', freshenv=True)
+def test_domain_py_type_alias(app, status, warning):
+ app.build(force_all=True)
+
+ content = (app.outdir / 'type_alias.html').read_text(encoding='utf8')
+ assert ('<em class="property"><span class="pre">type</span><span class="w"> </span></em>'
+ '<span class="sig-prename descclassname"><span class="pre">module_one.</span></span>'
+ '<span class="sig-name descname"><span class="pre">MyAlias</span></span>'
+ '<em class="property"><span class="w"> </span><span class="p"><span class="pre">=</span></span>'
+ '<span class="w"> </span><span class="pre">list</span>'
+ '<span class="p"><span class="pre">[</span></span>'
+ '<span class="pre">int</span><span class="w"> </span>'
+ '<span class="p"><span class="pre">|</span></span><span class="w"> </span>'
+ '<a class="reference internal" href="#module_two.SomeClass" title="module_two.SomeClass">'
+ '<span class="pre">module_two.SomeClass</span></a>'
+ '<span class="p"><span class="pre">]</span></span></em>' in content)
+ assert warning.getvalue() == ''
+
+
def test_pydecorator_signature(app):
text = ".. py:decorator:: deco"
domain = app.env.get_domain('py')