Coverage for tests/test_plugin.py: 100.00%
130 statements
« prev ^ index » next coverage.py v7.6.12, created at 2025-02-24 16:00 +0100
« prev ^ index » next coverage.py v7.6.12, created at 2025-02-24 16:00 +0100
1"""Tests for the plugin module."""
3from __future__ import annotations
5import functools
6from typing import Literal
8import pytest
9from mkdocs.config.defaults import MkDocsConfig
10from mkdocs.theme import Theme
12from mkdocs_autorefs import AutorefsConfig, AutorefsPlugin, fix_refs
13from tests.helpers import create_page
16def test_url_registration() -> None:
17 """Check that URLs can be registered, then obtained."""
18 plugin = AutorefsPlugin()
19 plugin.register_anchor(identifier="foo", page=create_page("foo1.html"), primary=True)
20 plugin.register_url(identifier="bar", url="https://example.org/bar.html")
22 assert plugin.get_item_url("foo") == ("foo1.html#foo", None)
23 assert plugin.get_item_url("bar") == ("https://example.org/bar.html", None)
24 with pytest.raises(KeyError):
25 plugin.get_item_url("baz")
28def test_url_registration_with_from_url() -> None:
29 """Check that URLs can be registered, then obtained, relative to a page."""
30 plugin = AutorefsPlugin()
31 plugin.register_anchor(identifier="foo", page=create_page("foo1.html"), primary=True)
32 plugin.register_url(identifier="bar", url="https://example.org/bar.html")
34 assert plugin.get_item_url("foo", from_url="a/b.html") == ("../foo1.html#foo", None)
35 assert plugin.get_item_url("bar", from_url="a/b.html") == ("https://example.org/bar.html", None)
36 with pytest.raises(KeyError):
37 plugin.get_item_url("baz", from_url="a/b.html")
40# YORE: Bump 2: Remove block.
41def test_url_registration_with_fallback() -> None:
42 """Check that URLs can be registered, then obtained through a fallback."""
43 plugin = AutorefsPlugin()
44 plugin.register_anchor(identifier="foo", page=create_page("foo1.html"), primary=True)
45 plugin.register_url(identifier="bar", url="https://example.org/bar.html")
47 # URL map will be updated with baz -> foo1.html#foo
48 assert plugin.get_item_url("baz", fallback=lambda _: ("foo",)) == ("foo1.html#foo", None)
49 # as expected, baz is now known as foo1.html#foo
50 assert plugin.get_item_url("baz", fallback=lambda _: ("bar",)) == ("foo1.html#foo", None)
51 # unknown identifiers correctly fallback: qux -> https://example.org/bar.html
52 assert plugin.get_item_url("qux", fallback=lambda _: ("bar",)) == ("https://example.org/bar.html", None)
54 with pytest.raises(KeyError):
55 plugin.get_item_url("foobar", fallback=lambda _: ("baaaa",))
56 with pytest.raises(KeyError):
57 plugin.get_item_url("foobar", fallback=lambda _: ())
60def test_dont_make_relative_urls_relative_again() -> None:
61 """Check that URLs are not made relative more than once."""
62 plugin = AutorefsPlugin()
63 plugin.register_anchor(identifier="foo.bar.baz", page=create_page("foo/bar/baz.html"), primary=True)
65 for _ in range(2):
66 assert plugin.get_item_url("foo.bar.baz", from_url="baz/bar/foo.html") == (
67 "../../foo/bar/baz.html#foo.bar.baz",
68 None,
69 )
72@pytest.mark.parametrize(
73 ("base", "urls", "expected"),
74 [
75 # One URL is closest.
76 ("", ["x/#b", "#b"], "#b"),
77 # Several URLs are equally close.
78 ("a/b", ["x/#e", "a/c/#e", "a/d/#e"], "a/c/#e"),
79 ("a/b/", ["x/#e", "a/d/#e", "a/c/#e"], "a/d/#e"),
80 # Two close URLs, one is shorter (closer).
81 ("a/b", ["x/#e", "a/c/#e", "a/c/d/#e"], "a/c/#e"),
82 ("a/b/", ["x/#e", "a/c/d/#e", "a/c/#e"], "a/c/#e"),
83 # Deeper-nested URLs.
84 ("a/b/c", ["x/#e", "a/#e", "a/b/#e", "a/b/c/#e", "a/b/c/d/#e"], "a/b/c/#e"),
85 ("a/b/c/", ["x/#e", "a/#e", "a/b/#e", "a/b/c/d/#e", "a/b/c/#e"], "a/b/c/#e"),
86 # No closest URL, use first one even if longer distance.
87 ("a", ["b/c/#d", "c/#d"], "b/c/#d"),
88 ("a/", ["c/#d", "b/c/#d"], "c/#d"),
89 ],
90)
91def test_find_closest_url(base: str, urls: list[str], expected: str) -> None:
92 """Find closest URLs given a list of URLs."""
93 assert AutorefsPlugin._get_closest_url(base, urls, "test") == expected
96def test_register_secondary_url() -> None:
97 """Test registering secondary URLs."""
98 plugin = AutorefsPlugin()
99 plugin.register_anchor(identifier="foo", page=create_page("foo.html"), primary=False)
100 assert plugin._secondary_url_map == {"foo": ["foo.html#foo"]}
103@pytest.mark.parametrize("primary", [True, False])
104def test_warn_multiple_urls(caplog: pytest.LogCaptureFixture, primary: bool) -> None:
105 """Warn when multiple URLs are found for the same identifier."""
106 plugin = AutorefsPlugin()
107 plugin.config = AutorefsConfig()
108 plugin.register_anchor(identifier="foo", page=create_page("foo.html"), primary=primary)
109 plugin.register_anchor(identifier="foo", page=create_page("bar.html"), primary=primary)
110 url_mapper = functools.partial(plugin.get_item_url, from_url="/hello")
111 # YORE: Bump 2: Replace `, _legacy_refs=False` with `` within line.
112 fix_refs('<autoref identifier="foo">Foo</autoref>', url_mapper, _legacy_refs=False)
113 qualifier = "primary" if primary else "secondary"
114 assert (f"Multiple {qualifier} URLs found for 'foo': ['foo.html#foo', 'bar.html#foo']" in caplog.text) is primary
117@pytest.mark.parametrize("primary", [True, False])
118def test_use_closest_url(caplog: pytest.LogCaptureFixture, primary: bool) -> None:
119 """Use the closest URL when multiple URLs are found for the same identifier."""
120 plugin = AutorefsPlugin()
121 plugin.config = AutorefsConfig()
122 plugin.config.resolve_closest = True
123 plugin.register_anchor(identifier="foo", page=create_page("foo.html"), primary=primary)
124 plugin.register_anchor(identifier="foo", page=create_page("bar.html"), primary=primary)
125 url_mapper = functools.partial(plugin.get_item_url, from_url="/hello")
126 # YORE: Bump 2: Replace `, _legacy_refs=False` with `` within line.
127 fix_refs('<autoref identifier="foo">Foo</autoref>', url_mapper, _legacy_refs=False)
128 qualifier = "primary" if primary else "secondary"
129 assert f"Multiple {qualifier} URLs found for 'foo': ['foo.html#foo', 'bar.html#foo']" not in caplog.text
132def test_on_config_hook() -> None:
133 """Check that the `on_config` hook runs without issue."""
134 plugin = AutorefsPlugin()
135 plugin.config = AutorefsConfig()
136 plugin.on_config(config=MkDocsConfig())
139def test_auto_link_titles_external() -> None:
140 """Check that `link_titles` are made external when automatic and Material is detected."""
141 plugin = AutorefsPlugin()
142 plugin.config = AutorefsConfig()
143 plugin.config.link_titles = "auto"
144 config = MkDocsConfig()
145 config.theme = Theme(name="material", features=["navigation.instant.preview"])
146 plugin.on_config(config=config)
147 assert plugin._link_titles == "external"
150def test_auto_link_titles() -> None:
151 """Check that `link_titles` are made true when automatic and Material is not detected."""
152 plugin = AutorefsPlugin()
153 plugin.config = AutorefsConfig()
154 plugin.config.link_titles = "auto"
155 config = MkDocsConfig()
157 config.theme = Theme(name="material", features=[])
158 plugin.on_config(config=config)
159 assert plugin._link_titles is True
161 config.theme = Theme("mkdocs")
162 plugin.on_config(config=config)
163 assert plugin._link_titles is True
165 config.theme = Theme("readthedocs")
166 plugin.on_config(config=config)
167 assert plugin._link_titles is True
170@pytest.mark.parametrize("link_titles", ["external", True, False])
171def test_explicit_link_titles(link_titles: bool | Literal["external"]) -> None:
172 """Check that explicit `link_titles` are kept unchanged."""
173 plugin = AutorefsPlugin()
174 plugin.config = AutorefsConfig()
175 plugin.config.link_titles = link_titles
176 plugin.on_config(config=MkDocsConfig())
177 assert plugin._link_titles is link_titles
180def test_auto_strip_title_tags_false() -> None:
181 """Check that `strip_title_tags` is made false when Material is detected."""
182 plugin = AutorefsPlugin()
183 plugin.config = AutorefsConfig()
184 plugin.config.strip_title_tags = "auto"
185 config = MkDocsConfig()
186 config.theme = Theme(name="material", features=["content.tooltips"])
187 plugin.on_config(config=config)
188 assert plugin._strip_title_tags is False
191def test_auto_strip_title_tags_true() -> None:
192 """Check that `strip_title_tags` are made true when automatic and Material is not detected."""
193 plugin = AutorefsPlugin()
194 plugin.config = AutorefsConfig()
195 plugin.config.strip_title_tags = "auto"
196 config = MkDocsConfig()
198 config.theme = Theme(name="material", features=[])
199 plugin.on_config(config=config)
200 assert plugin._strip_title_tags is True
202 config.theme = Theme("mkdocs")
203 plugin.on_config(config=config)
204 assert plugin._strip_title_tags is True
206 config.theme = Theme("readthedocs")
207 plugin.on_config(config=config)
208 assert plugin._strip_title_tags is True
211@pytest.mark.parametrize("strip_title_tags", [True, False])
212def test_explicit_strip_tags(strip_title_tags: bool) -> None:
213 """Check that explicit `_strip_title_tags` are kept unchanged."""
214 plugin = AutorefsPlugin()
215 plugin.config = AutorefsConfig()
216 plugin.config.strip_title_tags = strip_title_tags
217 plugin.on_config(config=MkDocsConfig())
218 assert plugin._strip_title_tags is strip_title_tags