1"""Tests for `chives.urls`."""
3from pathlib import Path
6from vcr.cassette import Cassette
8from chives.urls import (
12 parse_mastodon_post_url,
13 parse_tumblr_post_url,
17@pytest.mark.parametrize(
21 "https://www.youtube.com/watch?v=2OHPPSew2nY&list=WL&index=6&t=193s",
22 "https://www.youtube.com/watch?v=2OHPPSew2nY",
25 "https://www.youtube.com/watch?v=2OHPPSew2nY",
26 "https://www.youtube.com/watch?v=2OHPPSew2nY",
29 "https://www.youtube.com/watch?v=WiIi7STG3e0&start_radio=1",
30 "https://www.youtube.com/watch?v=WiIi7STG3e0",
34def test_clean_youtube_url(url: str, cleaned_url: str) -> None:
36 All the query parameters get stripped from YouTube URLs correctly.
38 assert clean_youtube_url(url) == cleaned_url
41@pytest.mark.parametrize(
42 "url, server, acct, post_id",
45 "https://iconfactory.world/@Iconfactory/115650922400392083",
52 "https://social.alexwlchan.net/@chris__martin@functional.cafe/113369395383537892",
56 id="alexwlchan_redirect",
59 "https://social.alexwlchan.net/@alex/116300317590482708",
60 "social.alexwlchan.net",
67def test_parse_mastodon_post_url(
68 vcr_cassette: Cassette, url: str, server: str, acct: str, post_id: str
71 Mastodon post URLs are parsed correctly.
73 assert parse_mastodon_post_url(url) == (server, acct, post_id)
76@pytest.mark.parametrize(
80 "https://mastodon.social/", "Cannot parse Mastodon URL", id="no_path"
83 "https://mastodon.social/about",
84 "Cannot parse Mastodon URL",
88 "https://mastodon.social/about/subdir", "Cannot find `acct`", id="no_acct"
91 "https://mastodon.social/@example/about",
92 "Mastodon post ID is not numeric",
93 id="non_numeric_post_id",
96 "https://social.alexwlchan.net/@does@not.exist/123",
97 "Cannot parse Mastodon URL",
98 id="alexwlchan_does_not_exist",
102def test_parse_mastodon_post_url_errors(
103 vcr_cassette: Cassette, url: str, error: str
106 parse_mastodon_post_url returns a useful error if it can't parse the URL.
108 with pytest.raises(ValueError, match=error):
109 parse_mastodon_post_url(url)
112@pytest.mark.parametrize(
113 "url, blog_identifier, post_id",
116 "https://www.tumblr.com/kynvillingur/792473255236796416/",
118 "792473255236796416",
121 "https://cut3panda.tumblr.com/post/94093772689/for-some-people-the-more-you-get-to-know-them",
127def test_parse_tumblr_post_url(url: str, blog_identifier: str, post_id: str) -> None:
129 Tumblr URLs are parsed correctly.
131 assert parse_tumblr_post_url(url) == (blog_identifier, post_id)
134@pytest.mark.parametrize(
137 "https://www.tumblr.com/",
138 "https://www.tumblr.com/staff/",
139 "https://staff.tumblr.com/",
140 "https://www.example.com/",
143def test_parse_bad_tumblr_url(url: str) -> None:
145 Parsing a non-Tumblr URL throws a ValueError.
147 with pytest.raises(ValueError, match="Cannot parse Tumblr URL"):
148 parse_tumblr_post_url(url)
151class TestIsMastodonHost:
153 Tests for `is_mastodon_host`.
156 @pytest.mark.parametrize(
157 "host", ["mastodon.social", "hachyderm.io", "social.jvns.ca"]
159 def test_mastodon_servers(self, host: str, vcr_cassette: Cassette) -> None:
161 It correctly identifies real Mastodon servers.
163 assert is_mastodon_host(host)
165 @pytest.mark.parametrize(
168 # These are regular Internet websites which don't expose
169 # the /.well-known/nodeinfo endpoint
173 # PeerTube exposes /.well-known/nodeinfo, but it's running
174 # different software.
177 # A website with a known bad SSL certificate, which is assumed
178 # not to be a Mastodon host because we can't connect to it.
179 "expired.badssl.com",
182 def test_non_mastodon_servers(self, host: str, vcr_cassette: Cassette) -> None:
184 Other websites are not Mastodon servers.
186 assert not is_mastodon_host(host)
191 Tests for `is_url_safe`.
194 @pytest.mark.parametrize("path", ["example.txt", Path("a/b/cat.jpg")])
195 def test_safe(self, path: str | Path) -> None:
196 """Paths which are URL safe."""
197 assert is_url_safe(path)
199 @pytest.mark.parametrize("path", ["is it?", Path("cat%c.jpg"), "a#b"])
200 def test_unsafe(self, path: str | Path) -> None:
201 """Paths which are not URL safe."""
202 assert not is_url_safe(path)