unit tests passing
This commit is contained in:
parent
73353a953a
commit
9db91b09b6
2 changed files with 79 additions and 74 deletions
|
|
@ -3,7 +3,6 @@ from typing import Optional
|
||||||
from urllib.parse import parse_qs
|
from urllib.parse import parse_qs
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
from ytdl_sub.utils.exceptions import ValidationException
|
|
||||||
from ytdl_sub.validators.validators import StringValidator
|
from ytdl_sub.validators.validators import StringValidator
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -20,9 +19,9 @@ class YoutubeVideoUrlValidator(StringValidator):
|
||||||
- https://www.youtube.com/embed/SA2iWivDJiE
|
- https://www.youtube.com/embed/SA2iWivDJiE
|
||||||
- https://www.youtube.com/v/SA2iWivDJiE?version=3&hl=en_US
|
- https://www.youtube.com/v/SA2iWivDJiE?version=3&hl=en_US
|
||||||
"""
|
"""
|
||||||
# If the url doesn't contain youtube, assume it is the video id
|
# If the url doesn't contain youtube or youtu.be, assume it is invalid
|
||||||
if "youtube.com" not in url and "youtu.be" not in url:
|
if "youtube.com" not in url and "youtu.be" not in url:
|
||||||
return url
|
return None
|
||||||
|
|
||||||
# If https:// is not present, urlparse will not work
|
# If https:// is not present, urlparse will not work
|
||||||
if not url.startswith("https://"):
|
if not url.startswith("https://"):
|
||||||
|
|
@ -47,16 +46,16 @@ class YoutubeVideoUrlValidator(StringValidator):
|
||||||
|
|
||||||
self._video_id = self._get_video_id(value)
|
self._video_id = self._get_video_id(value)
|
||||||
if not self._video_id:
|
if not self._video_id:
|
||||||
raise self._validation_exception(f"'{value}' is not a valid Youtube video url or ID.")
|
raise self._validation_exception(f"'{value}' is not a valid Youtube video url.")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def video_id(self) -> str:
|
def video_url(self) -> str:
|
||||||
"""
|
"""
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
ID of the video
|
Full video URL
|
||||||
"""
|
"""
|
||||||
return self._video_id
|
return f"https://youtube.com/watch?v={self._video_id}"
|
||||||
|
|
||||||
|
|
||||||
class YoutubePlaylistUrlValidator(StringValidator):
|
class YoutubePlaylistUrlValidator(StringValidator):
|
||||||
|
|
@ -69,9 +68,9 @@ class YoutubePlaylistUrlValidator(StringValidator):
|
||||||
Examples:
|
Examples:
|
||||||
- https://www.youtube.com/playlist?list=PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc
|
- https://www.youtube.com/playlist?list=PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc
|
||||||
"""
|
"""
|
||||||
# If the url doesn't contain youtube, assume it is the ID
|
# If the url doesn't contain youtube, assume it is invalid
|
||||||
if "youtube.com" not in url:
|
if "youtube.com" not in url:
|
||||||
return url
|
return None
|
||||||
|
|
||||||
# If https:// is not present, urlparse will not work
|
# If https:// is not present, urlparse will not work
|
||||||
if not url.startswith("https://"):
|
if not url.startswith("https://"):
|
||||||
|
|
@ -90,16 +89,16 @@ class YoutubePlaylistUrlValidator(StringValidator):
|
||||||
|
|
||||||
self._playlist_id = self._get_playlist_id(value)
|
self._playlist_id = self._get_playlist_id(value)
|
||||||
if not self._playlist_id:
|
if not self._playlist_id:
|
||||||
raise self._validation_exception(f"'{value}' is not a valid Youtube playlist url or ID.")
|
raise self._validation_exception(f"'{value}' is not a valid Youtube playlist url.")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def playlist_id(self) -> str:
|
def playlist_url(self) -> str:
|
||||||
"""
|
"""
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
ID of the channel
|
Full playlist URL
|
||||||
"""
|
"""
|
||||||
return self._playlist_id
|
return f"https://youtube.com/playlist?list={self._playlist_id}"
|
||||||
|
|
||||||
|
|
||||||
class YoutubeChannelUrlValidator(StringValidator):
|
class YoutubeChannelUrlValidator(StringValidator):
|
||||||
|
|
@ -107,23 +106,16 @@ class YoutubeChannelUrlValidator(StringValidator):
|
||||||
_expected_value_type_name = "Youtube channel url"
|
_expected_value_type_name = "Youtube channel url"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _get_channel_id(cls, url: str) -> Optional[str]:
|
def _get_channel_url(cls, url: str) -> Optional[str]:
|
||||||
"""
|
"""
|
||||||
Examples:
|
Examples:
|
||||||
- https://www.youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw
|
- https://www.youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw
|
||||||
|
- https://www.youtube.com/user/username
|
||||||
NOT:
|
- https://www.youtube.com/c/channel_name
|
||||||
- https://www.youtube.com/user/a_username_that_can_change
|
|
||||||
- https://www.youtube.com/c/a_name_that_can_change
|
|
||||||
|
|
||||||
Raises
|
|
||||||
------
|
|
||||||
ValidationException
|
|
||||||
If the url is for the user name
|
|
||||||
"""
|
"""
|
||||||
# If the url doesn't contain youtube, assume it is the ID
|
# If the url doesn't contain youtube, assume it is invalid
|
||||||
if "youtube.com" not in url:
|
if "youtube.com" not in url:
|
||||||
return url
|
return None
|
||||||
|
|
||||||
# If https:// is not present, urlparse will not work
|
# If https:// is not present, urlparse will not work
|
||||||
if not url.startswith("https://"):
|
if not url.startswith("https://"):
|
||||||
|
|
@ -131,33 +123,23 @@ class YoutubeChannelUrlValidator(StringValidator):
|
||||||
|
|
||||||
query = urlparse(url)
|
query = urlparse(url)
|
||||||
if query.hostname in ("youtube.com", "www.youtube.com"):
|
if query.hostname in ("youtube.com", "www.youtube.com"):
|
||||||
if query.path == "/channel":
|
if any(query.path.startswith(qpath) for qpath in ("/channel/", "/user/", "/c/")):
|
||||||
parsed_q = parse_qs(query.query)
|
return f"https://youtube.com{query.path}"
|
||||||
return parsed_q["v"][0]
|
|
||||||
if query.path in ("/user", "/c"):
|
|
||||||
raise ValidationException('user or c not allowed since it can change')
|
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def __init__(self, name: str, value: Any):
|
def __init__(self, name: str, value: Any):
|
||||||
super().__init__(name, value)
|
super().__init__(name, value)
|
||||||
|
|
||||||
try:
|
self._channel_url = self._get_channel_url(value)
|
||||||
self._channel_id = self._get_channel_id(value)
|
if not self._channel_url:
|
||||||
except ValidationException:
|
raise self._validation_exception(f"'{value}' is not a valid Youtube channel url.")
|
||||||
raise self._validation_exception(
|
|
||||||
f"{value} uses a deprecated Youtube url that which can change. "
|
|
||||||
f"Use the /channel/ url instead."
|
|
||||||
)
|
|
||||||
|
|
||||||
if not self._channel_id:
|
|
||||||
raise self._validation_exception(f"'{value}' is not a valid Youtube channel url or ID.")
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def channel_id(self) -> str:
|
def channel_url(self) -> str:
|
||||||
"""
|
"""
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
ID of the channel
|
Full channel URL
|
||||||
"""
|
"""
|
||||||
return self._channel_id
|
return self._channel_url
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,17 @@
|
||||||
|
import re
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from ytdl_sub.utils.exceptions import ValidationException
|
from ytdl_sub.utils.exceptions import ValidationException
|
||||||
from ytdl_sub.validators.url_validator import YoutubeVideoUrlValidator, YoutubePlaylistUrlValidator
|
from ytdl_sub.validators.url_validator import YoutubeChannelUrlValidator
|
||||||
|
from ytdl_sub.validators.url_validator import YoutubePlaylistUrlValidator
|
||||||
|
from ytdl_sub.validators.url_validator import YoutubeVideoUrlValidator
|
||||||
|
|
||||||
|
|
||||||
class TestYoutubeVideoUrlValidator:
|
class TestYoutubeVideoUrlValidator:
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"url",
|
"url",
|
||||||
[
|
[
|
||||||
"dQw4w9WgXcQ",
|
|
||||||
"youtu.be/dQw4w9WgXcQ",
|
"youtu.be/dQw4w9WgXcQ",
|
||||||
"www.youtu.be/dQw4w9WgXcQ",
|
"www.youtu.be/dQw4w9WgXcQ",
|
||||||
"https://youtu.be/dQw4w9WgXcQ",
|
"https://youtu.be/dQw4w9WgXcQ",
|
||||||
|
|
@ -18,15 +21,14 @@ class TestYoutubeVideoUrlValidator:
|
||||||
"https://www.youtube.com/v/dQw4w9WgXcQ?version=3&hl=en_US",
|
"https://www.youtube.com/v/dQw4w9WgXcQ?version=3&hl=en_US",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_youtube_video_validator_success(self, url):
|
def test_youtube_video_url_validator_success(self, url):
|
||||||
video_id = YoutubeVideoUrlValidator(name="unit test", value=url).video_id
|
video_url = YoutubeVideoUrlValidator(name="unit test", value=url).video_url
|
||||||
assert video_id == "dQw4w9WgXcQ"
|
assert video_url == "https://youtube.com/watch?v=dQw4w9WgXcQ"
|
||||||
|
|
||||||
|
def test_youtube_video_url_validator_fail(self):
|
||||||
def test_youtube_video_validator_fail(self):
|
|
||||||
bad_url = "youtube.cum/asdfd"
|
bad_url = "youtube.cum/asdfd"
|
||||||
expected_error_msg = f"'{bad_url}' is not a valid Youtube video url or ID."
|
expected_error_msg = f"'{bad_url}' is not a valid Youtube video url."
|
||||||
with pytest.raises(ValidationException, match=expected_error_msg):
|
with pytest.raises(ValidationException, match=re.escape(expected_error_msg)):
|
||||||
YoutubeVideoUrlValidator(name="unit test", value=bad_url)
|
YoutubeVideoUrlValidator(name="unit test", value=bad_url)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -34,40 +36,61 @@ class TestYoutubePlaylistUrlValidator:
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"url",
|
"url",
|
||||||
[
|
[
|
||||||
"PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc",
|
|
||||||
"youtube.com/playlist?list=PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc",
|
"youtube.com/playlist?list=PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc",
|
||||||
"www.youtube.com/playlist?list=PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc",
|
"www.youtube.com/playlist?list=PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc",
|
||||||
"https://youtube.com/playlist?list=PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc",
|
"https://youtube.com/playlist?list=PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc",
|
||||||
"https://www.youtube.com/playlist?list=PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc",
|
"https://www.youtube.com/playlist?list=PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_youtube_video_validator_success(self, url):
|
def test_youtube_playlist_url_validator_success(self, url):
|
||||||
playlist_id = YoutubePlaylistUrlValidator(name="unit test", value=url).playlist_id
|
playlist_url = YoutubePlaylistUrlValidator(name="unit test", value=url).playlist_url
|
||||||
assert playlist_id == "PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc"
|
assert (
|
||||||
|
playlist_url == "https://youtube.com/playlist?list=PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc"
|
||||||
|
)
|
||||||
|
|
||||||
def test_youtube_playlist_validator_fail(self):
|
def test_youtube_playlist_url_validator_fail(self):
|
||||||
bad_url = "youpoop.com/playlist?list=PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc"
|
bad_url = "youpoop.com/playlist?list=PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc"
|
||||||
expected_error_msg = f"'{bad_url}' is not a valid Youtube playlist url or ID."
|
expected_error_msg = f"'{bad_url}' is not a valid Youtube playlist url."
|
||||||
with pytest.raises(ValidationException, match=expected_error_msg):
|
with pytest.raises(ValidationException, match=re.escape(expected_error_msg)):
|
||||||
YoutubeVideoUrlValidator(name="unit test", value=bad_url)
|
YoutubePlaylistUrlValidator(name="unit test", value=bad_url)
|
||||||
|
|
||||||
|
|
||||||
class TestYoutubeChannelUrlValidator:
|
class TestYoutubeChannelUrlValidator:
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"url",
|
"url, expected_url",
|
||||||
[
|
[
|
||||||
"PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc",
|
(
|
||||||
"youtube.com/playlist?list=PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc",
|
"https://www.youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw",
|
||||||
"www.youtube.com/playlist?list=PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc",
|
"https://youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw",
|
||||||
"https://youtube.com/playlist?list=PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc",
|
),
|
||||||
"https://www.youtube.com/playlist?list=PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc",
|
(
|
||||||
|
"https://youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw",
|
||||||
|
"https://youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw",
|
||||||
|
"https://youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"www.youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw",
|
||||||
|
"https://youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"https://www.youtube.com/c/RickastleyCoUkOfficial",
|
||||||
|
"https://youtube.com/c/RickastleyCoUkOfficial",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"https://www.youtube.com/user/videogamedunkey",
|
||||||
|
"https://youtube.com/user/videogamedunkey",
|
||||||
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_youtube_video_validator_success(self, url):
|
def test_youtube_channel_url_validator_success(self, url, expected_url):
|
||||||
playlist_id = YoutubePlaylistUrlValidator(name="unit test", value=url).playlist_id
|
channel_url = YoutubeChannelUrlValidator(name="unit test", value=url).channel_url
|
||||||
assert playlist_id == "PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc"
|
assert channel_url == expected_url
|
||||||
|
|
||||||
def test_youtube_playlist_validator_fail(self):
|
def test_youtube_channel_url_validator_fail(self):
|
||||||
bad_url = "youpoop.com/playlist?list=PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc"
|
bad_url = "www.youtube.com/cha/UCuAXFkgsw1L7xaCfnd5JJOw"
|
||||||
expected_error_msg = f"'{bad_url}' is not a valid Youtube playlist url or ID."
|
expected_error_msg = f"'{bad_url}' is not a valid Youtube channel url."
|
||||||
with pytest.raises(ValidationException, match=expected_error_msg):
|
with pytest.raises(ValidationException, match=re.escape(expected_error_msg)):
|
||||||
YoutubeVideoUrlValidator(name="unit test", value=bad_url)
|
YoutubeChannelUrlValidator(name="unit test", value=bad_url)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue