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

1"""Tests for the plugin module.""" 

2 

3from __future__ import annotations 

4 

5import functools 

6from typing import Literal 

7 

8import pytest 

9from mkdocs.config.defaults import MkDocsConfig 

10from mkdocs.theme import Theme 

11 

12from mkdocs_autorefs import AutorefsConfig, AutorefsPlugin, fix_refs 

13from tests.helpers import create_page 

14 

15 

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") 

21 

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") 

26 

27 

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") 

33 

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") 

38 

39 

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") 

46 

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) 

53 

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 _: ()) 

58 

59 

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) 

64 

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 ) 

70 

71 

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 

94 

95 

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"]} 

101 

102 

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 

115 

116 

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 

130 

131 

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()) 

137 

138 

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" 

148 

149 

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() 

156 

157 config.theme = Theme(name="material", features=[]) 

158 plugin.on_config(config=config) 

159 assert plugin._link_titles is True 

160 

161 config.theme = Theme("mkdocs") 

162 plugin.on_config(config=config) 

163 assert plugin._link_titles is True 

164 

165 config.theme = Theme("readthedocs") 

166 plugin.on_config(config=config) 

167 assert plugin._link_titles is True 

168 

169 

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 

178 

179 

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 

189 

190 

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() 

197 

198 config.theme = Theme(name="material", features=[]) 

199 plugin.on_config(config=config) 

200 assert plugin._strip_title_tags is True 

201 

202 config.theme = Theme("mkdocs") 

203 plugin.on_config(config=config) 

204 assert plugin._strip_title_tags is True 

205 

206 config.theme = Theme("readthedocs") 

207 plugin.on_config(config=config) 

208 assert plugin._strip_title_tags is True 

209 

210 

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