unit tests passing

This commit is contained in:
jbannon 2022-06-05 15:08:37 +00:00
parent 73353a953a
commit 9db91b09b6
2 changed files with 79 additions and 74 deletions

View file

@ -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

View file

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