[DEV] Unit test filter plugin (#1066)
This commit is contained in:
parent
513d1f5a97
commit
fd5882051a
10 changed files with 315 additions and 438 deletions
|
|
@ -10,7 +10,7 @@ from ytdl_sub.script.types.resolvable import Boolean
|
|||
from ytdl_sub.script.types.resolvable import Float
|
||||
from ytdl_sub.script.types.resolvable import Integer
|
||||
from ytdl_sub.script.types.resolvable import String
|
||||
from ytdl_sub.script.utils.exceptions import RuntimeException
|
||||
from ytdl_sub.script.utils.exceptions import FunctionRuntimeException
|
||||
|
||||
|
||||
def _re_output_to_array(re_out: Match[AnyStr] | None) -> Array:
|
||||
|
|
@ -115,12 +115,12 @@ class RegexFunctions:
|
|||
# ["2020-02-27", "2020", "02"]
|
||||
"""
|
||||
if len(regex_array) == 0:
|
||||
raise RuntimeException("regex_array must contain at least a single element")
|
||||
raise FunctionRuntimeException("regex_array must contain at least a single element")
|
||||
|
||||
regex_list: List[String] = []
|
||||
for regex in regex_array.value:
|
||||
if not isinstance(regex, String):
|
||||
raise RuntimeException("All regex_array elements must be strings")
|
||||
raise FunctionRuntimeException("All regex_array elements must be strings")
|
||||
regex_list.append(regex)
|
||||
|
||||
if default is None:
|
||||
|
|
@ -129,13 +129,13 @@ class RegexFunctions:
|
|||
RegexFunctions.regex_capture_groups(regex).value != num_capture_groups
|
||||
for regex in regex_list[1:]
|
||||
):
|
||||
raise RuntimeException(
|
||||
raise FunctionRuntimeException(
|
||||
"regex_array elements must contain the same number of capture groups"
|
||||
)
|
||||
elif any(
|
||||
RegexFunctions.regex_capture_groups(regex).value > len(default) for regex in regex_list
|
||||
):
|
||||
raise RuntimeException(
|
||||
raise FunctionRuntimeException(
|
||||
"When using %regex_capture_array, number of regex capture groups must be less than "
|
||||
"or equal to the number of defaults"
|
||||
)
|
||||
|
|
@ -147,7 +147,7 @@ class RegexFunctions:
|
|||
break
|
||||
|
||||
if len(output) == 0 and not default:
|
||||
raise RuntimeException(
|
||||
raise FunctionRuntimeException(
|
||||
f"no regex strings were captured for input string {string.value}"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,299 +0,0 @@
|
|||
import re
|
||||
from typing import Any
|
||||
from typing import Dict
|
||||
|
||||
import mergedeep
|
||||
import pytest
|
||||
from expected_transaction_log import assert_transaction_log_matches
|
||||
|
||||
from ytdl_sub.config.config_file import ConfigFile
|
||||
from ytdl_sub.script.utils.exceptions import RuntimeException
|
||||
from ytdl_sub.script.utils.exceptions import UserThrownRuntimeError
|
||||
from ytdl_sub.subscriptions.subscription import Subscription
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def regex_subscription_dict_base(output_directory):
|
||||
return {
|
||||
"preset": "Jellyfin Music Videos",
|
||||
# override the output directory with our fixture-generated dir
|
||||
"output_options": {"output_directory": output_directory},
|
||||
"format": "best[height<=480]", # download the worst format so it is fast
|
||||
"filter_include": ["{%not(%is_null(description_website))}"],
|
||||
"overrides": {
|
||||
"in_regex_default": "in regex default",
|
||||
"url": "https://youtube.com/playlist?list=PL5BC0FC26BECA5A35",
|
||||
"upload_capture": """{
|
||||
%regex_capture_many_with_defaults(
|
||||
upload_date_standardized,
|
||||
["([0-9]+)-([0-9]+)-27"],
|
||||
["First", %concat("Second containing ", in_regex_default)]
|
||||
)
|
||||
}""",
|
||||
"upload_captured_year": "{%array_at(upload_capture, 1)}",
|
||||
"upload_captured_month": "{%array_at(upload_capture, 2)}",
|
||||
"description_capture": """{
|
||||
%regex_capture_many_with_defaults(
|
||||
description,
|
||||
[".*http:\\/\\/(.+).com.*"],
|
||||
[null]
|
||||
)
|
||||
}""",
|
||||
"description_website": "{%array_at(description_capture, 1)}",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def regex_subscription_dict(regex_subscription_dict_base, output_directory):
|
||||
return mergedeep.merge(
|
||||
regex_subscription_dict_base,
|
||||
{
|
||||
"nfo_tags": {
|
||||
"tags": {
|
||||
"title_cap_1": "{title_type}",
|
||||
"title_cap_1_sanitized": "{title_type_sanitized}",
|
||||
"title_cap_2": "{title_date}",
|
||||
"desc_cap": "{description_website}",
|
||||
"upload_date_both_caps": "{upload_captured_year} and {upload_captured_month}",
|
||||
"override_with_capture_variable": "{contains_regex_default}",
|
||||
"override_with_capture_variable_sanitized": "{contains_regex_sanitized_default}",
|
||||
}
|
||||
},
|
||||
"filter_exclude": ["{%is_null(title_type)}"],
|
||||
"overrides": {
|
||||
"title_capture_list": """{
|
||||
%regex_capture_many_with_defaults(
|
||||
title,
|
||||
[ "should not cap (.+) - (.+)", ".*\\[(.+) - (Feb.+)]" ],
|
||||
[ null, null ]
|
||||
)
|
||||
}""",
|
||||
"title_type": "{%array_at(title_capture_list, 1)}",
|
||||
"title_date": "{%array_at(title_capture_list, 2)}",
|
||||
"contains_regex_default": "contains {title_type}",
|
||||
"contains_regex_sanitized_default": "contains {title_type_sanitized}",
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def regex_subscription_dict_exclude(regex_subscription_dict_base, output_directory):
|
||||
return mergedeep.merge(
|
||||
regex_subscription_dict_base,
|
||||
{
|
||||
"filter_exclude": [
|
||||
"""{
|
||||
%regex_search_any(
|
||||
title,
|
||||
[ "should not cap", ".*Feb.*" ]
|
||||
)
|
||||
}"""
|
||||
]
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def regex_subscription_dict_match_and_exclude(regex_subscription_dict_base, output_directory):
|
||||
return mergedeep.merge(
|
||||
regex_subscription_dict_base,
|
||||
{
|
||||
"regex": {
|
||||
# tests that skip_if_match_fails defaults to True
|
||||
"from": {
|
||||
"title": {
|
||||
"match": [
|
||||
"should not cap (.+) - (.+)",
|
||||
".*\\[(.+) - (Feb.+)]", # should filter out march video
|
||||
],
|
||||
"capture_group_names": ["title_type", "title_date"],
|
||||
"exclude": [
|
||||
"should not cap",
|
||||
".*27.*", # should filter out Feb 27th video
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
"nfo_tags": {
|
||||
"tags": {
|
||||
"title_cap_1": "{title_type}",
|
||||
"title_cap_1_sanitized": "{title_type_sanitized}",
|
||||
"title_cap_2": "{title_date}",
|
||||
"desc_cap": "{description_website}",
|
||||
"upload_date_both_caps": "{upload_captured_year} and {upload_captured_month}",
|
||||
"override_with_capture_variable": "{contains_regex_default}",
|
||||
"override_with_capture_variable_sanitized": "{contains_regex_sanitized_default}",
|
||||
}
|
||||
},
|
||||
"overrides": {
|
||||
"contains_regex_default": "contains {title_type}",
|
||||
"contains_regex_sanitized_default": "contains {title_type_sanitized}",
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def regex_subscription_dict_match_and_exclude_override_variable(
|
||||
regex_subscription_dict_base, output_directory
|
||||
):
|
||||
return mergedeep.merge(
|
||||
regex_subscription_dict_base,
|
||||
{
|
||||
"regex": {
|
||||
# tests that skip_if_match_fails defaults to True
|
||||
"from": {
|
||||
"override_title": {
|
||||
"exclude": [
|
||||
"should not cap",
|
||||
".*Feb.*", # should filter out march video
|
||||
],
|
||||
},
|
||||
"override_description": {
|
||||
"match": [".*http:\\/\\/(.+).com.*"],
|
||||
"capture_group_names": ["override_description_website"],
|
||||
},
|
||||
},
|
||||
},
|
||||
"overrides": {"override_title": "{title}", "override_description": "{description}"},
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def playlist_subscription(default_config, regex_subscription_dict):
|
||||
return Subscription.from_dict(
|
||||
config=default_config,
|
||||
preset_name="regex_capture_playlist_test",
|
||||
preset_dict=regex_subscription_dict,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def playlist_subscription_no_match_fails(
|
||||
default_config: ConfigFile, regex_subscription_dict: Dict[str, Any]
|
||||
):
|
||||
regex_subscription_dict["overrides"][
|
||||
"title_capture_list"
|
||||
] = """{
|
||||
%regex_capture_many_required(
|
||||
title,
|
||||
[ "should not cap (.+) - (.+)", ".*\\[(.+) - (Feb.+)]" ]
|
||||
)
|
||||
}"""
|
||||
|
||||
return Subscription.from_dict(
|
||||
config=default_config,
|
||||
preset_name="regex_capture_playlist_test",
|
||||
preset_dict=regex_subscription_dict,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def playlist_subscription_exclude(
|
||||
default_config: ConfigFile, regex_subscription_dict_exclude: Dict[str, Any]
|
||||
) -> Subscription:
|
||||
return Subscription.from_dict(
|
||||
config=default_config,
|
||||
preset_name="regex_exclude_playlist_test",
|
||||
preset_dict=regex_subscription_dict_exclude,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def playlist_subscription_overrides(
|
||||
default_config: ConfigFile,
|
||||
regex_subscription_dict_match_and_exclude_override_variable: Dict[str, Any],
|
||||
) -> Subscription:
|
||||
return Subscription.from_dict(
|
||||
config=default_config,
|
||||
preset_name="regex_using_overrides_test",
|
||||
preset_dict=regex_subscription_dict_match_and_exclude_override_variable,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def playlist_subscription_match_and_exclude(
|
||||
default_config: ConfigFile, regex_subscription_dict_match_and_exclude: Dict[str, Any]
|
||||
) -> Subscription:
|
||||
return Subscription.from_dict(
|
||||
config=default_config,
|
||||
preset_name="regex_match_and_exclude_playlist_test",
|
||||
preset_dict=regex_subscription_dict_match_and_exclude,
|
||||
)
|
||||
|
||||
|
||||
class TestFilter:
|
||||
def test_regex_success(self, playlist_subscription, output_directory):
|
||||
# Only dry run is needed to see if capture variables are created
|
||||
transaction_log = playlist_subscription.download(dry_run=True)
|
||||
assert_transaction_log_matches(
|
||||
output_directory=output_directory,
|
||||
transaction_log=transaction_log,
|
||||
transaction_log_summary_file_name="plugins/test_regex.txt",
|
||||
)
|
||||
|
||||
def test_regex_excludes_success(self, playlist_subscription_exclude, output_directory):
|
||||
# Should only contain the march video
|
||||
transaction_log = playlist_subscription_exclude.download(dry_run=True)
|
||||
assert_transaction_log_matches(
|
||||
output_directory=output_directory,
|
||||
transaction_log=transaction_log,
|
||||
transaction_log_summary_file_name="plugins/test_regex_exclude.txt",
|
||||
)
|
||||
|
||||
def test_regex_match_and_excludes_success(
|
||||
self, playlist_subscription_match_and_exclude, output_directory
|
||||
):
|
||||
# Should only contain the Feb 1st video
|
||||
transaction_log = playlist_subscription_match_and_exclude.download(dry_run=True)
|
||||
assert_transaction_log_matches(
|
||||
output_directory=output_directory,
|
||||
transaction_log=transaction_log,
|
||||
transaction_log_summary_file_name="plugins/test_regex_match_and_exclude.txt",
|
||||
)
|
||||
|
||||
def test_regex_using_overrides_success(self, playlist_subscription_overrides, output_directory):
|
||||
# Should only contain the march video
|
||||
transaction_log = playlist_subscription_overrides.download(dry_run=True)
|
||||
assert_transaction_log_matches(
|
||||
output_directory=output_directory,
|
||||
transaction_log=transaction_log,
|
||||
transaction_log_summary_file_name="plugins/test_regex_overrides.txt",
|
||||
)
|
||||
|
||||
def test_regex_fails_no_match(self, playlist_subscription_no_match_fails, output_directory):
|
||||
with pytest.raises(
|
||||
RuntimeException,
|
||||
match=re.escape(
|
||||
"no regex strings were captured for input string Jesse's Minecraft Server [Trailer - Mar.21]"
|
||||
),
|
||||
):
|
||||
_ = playlist_subscription_no_match_fails.download(dry_run=True)
|
||||
|
||||
def test_regex_fails_unequal_defaults(self, regex_subscription_dict, default_config):
|
||||
regex_subscription_dict["overrides"][
|
||||
"title_capture_list"
|
||||
] = """{
|
||||
%regex_capture_many_with_defaults(
|
||||
title,
|
||||
[ "should not cap (.+) - (.+)", ".*\\[(.+) - (Feb.+)]" ],
|
||||
[ "one default, expects >= 2" ]
|
||||
)
|
||||
}"""
|
||||
|
||||
subscription = Subscription.from_dict(
|
||||
config=default_config,
|
||||
preset_name="regex_capture_playlist_test",
|
||||
preset_dict=regex_subscription_dict,
|
||||
)
|
||||
|
||||
with pytest.raises(
|
||||
RuntimeException,
|
||||
match=re.escape(
|
||||
"When using %regex_capture_array, number of regex capture groups must be less than or equal to the number of defaults"
|
||||
),
|
||||
):
|
||||
_ = subscription.download(dry_run=True)
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
Files created:
|
||||
----------------------------------------
|
||||
{output_directory}
|
||||
.ytdl-sub-subscription_test-download-archive.json
|
||||
{output_directory}/subscription_test
|
||||
Mock Entry 20-1.info.json
|
||||
Mock Entry 20-1.jpg
|
||||
Mock Entry 20-1.mp4
|
||||
Video Tags:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2020-08-08
|
||||
title: Mock Entry 20-1
|
||||
year: 2020
|
||||
Mock Entry 20-1.nfo
|
||||
NFO tags:
|
||||
musicvideo:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
desc_cap: Description
|
||||
genre: ytdl-sub
|
||||
override_with_capture_variable: contains 20
|
||||
override_with_capture_variable_sanitized: contains 20
|
||||
premiered: 2020-08-08
|
||||
title: Mock Entry 20-1
|
||||
title_cap_1: 20
|
||||
title_cap_1_sanitized: 20
|
||||
title_cap_2: 1
|
||||
upload_date_both_caps: First and Second containing in regex default
|
||||
Mock Entry 20-2.info.json
|
||||
Mock Entry 20-2.jpg
|
||||
Mock Entry 20-2.mp4
|
||||
Video Tags:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2020-08-08
|
||||
title: Mock Entry 20-2
|
||||
year: 2020
|
||||
Mock Entry 20-2.nfo
|
||||
NFO tags:
|
||||
musicvideo:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
desc_cap: Description
|
||||
genre: ytdl-sub
|
||||
override_with_capture_variable: contains 20
|
||||
override_with_capture_variable_sanitized: contains 20
|
||||
premiered: 2020-08-08
|
||||
title: Mock Entry 20-2
|
||||
title_cap_1: 20
|
||||
title_cap_1_sanitized: 20
|
||||
title_cap_2: 2
|
||||
upload_date_both_caps: First and Second containing in regex default
|
||||
Mock Entry 20-3.info.json
|
||||
Mock Entry 20-3.jpg
|
||||
Mock Entry 20-3.mp4
|
||||
Video Tags:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2020-08-07
|
||||
title: Mock Entry 20-3
|
||||
year: 2020
|
||||
Mock Entry 20-3.nfo
|
||||
NFO tags:
|
||||
musicvideo:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
desc_cap: Description
|
||||
genre: ytdl-sub
|
||||
override_with_capture_variable: contains 20
|
||||
override_with_capture_variable_sanitized: contains 20
|
||||
premiered: 2020-08-07
|
||||
title: Mock Entry 20-3
|
||||
title_cap_1: 20
|
||||
title_cap_1_sanitized: 20
|
||||
title_cap_2: 3
|
||||
upload_date_both_caps: First and Second containing in regex default
|
||||
Mock Entry 21-1.info.json
|
||||
Mock Entry 21-1.jpg
|
||||
Mock Entry 21-1.mp4
|
||||
Video Tags:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2021-08-08
|
||||
title: Mock Entry 21-1
|
||||
year: 2021
|
||||
Mock Entry 21-1.nfo
|
||||
NFO tags:
|
||||
musicvideo:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
desc_cap: Description
|
||||
genre: ytdl-sub
|
||||
override_with_capture_variable: contains 21
|
||||
override_with_capture_variable_sanitized: contains 21
|
||||
premiered: 2021-08-08
|
||||
title: Mock Entry 21-1
|
||||
title_cap_1: 21
|
||||
title_cap_1_sanitized: 21
|
||||
title_cap_2: 1
|
||||
upload_date_both_caps: First and Second containing in regex default
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
Files created:
|
||||
----------------------------------------
|
||||
{output_directory}
|
||||
.ytdl-sub-subscription_test-download-archive.json
|
||||
{output_directory}/subscription_test
|
||||
Mock Entry 21-1.info.json
|
||||
Mock Entry 21-1.jpg
|
||||
Mock Entry 21-1.mp4
|
||||
Video Tags:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2021-08-08
|
||||
title: Mock Entry 21-1
|
||||
year: 2021
|
||||
Mock Entry 21-1.nfo
|
||||
NFO tags:
|
||||
musicvideo:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2021-08-08
|
||||
title: Mock Entry 21-1
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
Files created:
|
||||
----------------------------------------
|
||||
{output_directory}
|
||||
.ytdl-sub-regex_capture_playlist_test-download-archive.json
|
||||
{output_directory}/regex_capture_playlist_test
|
||||
Jesse's Minecraft Server [Trailer - Feb.1].info.json
|
||||
Jesse's Minecraft Server [Trailer - Feb.1].jpg
|
||||
Jesse's Minecraft Server [Trailer - Feb.1].mp4
|
||||
Video Tags:
|
||||
album: Music Videos
|
||||
artist: regex_capture_playlist_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2011-02-01
|
||||
title: Jesse's Minecraft Server [Trailer - Feb.1]
|
||||
year: 2011
|
||||
Jesse's Minecraft Server [Trailer - Feb.1].nfo
|
||||
NFO tags:
|
||||
musicvideo:
|
||||
album: Music Videos
|
||||
artist: regex_capture_playlist_test
|
||||
desc_cap: www.jesseminecraft.webs
|
||||
genre: ytdl-sub
|
||||
override_with_capture_variable: contains Trailer
|
||||
override_with_capture_variable_sanitized: contains Trailer
|
||||
premiered: 2011-02-01
|
||||
title: Jesse's Minecraft Server [Trailer - Feb.1]
|
||||
title_cap_1: Trailer
|
||||
title_cap_1_sanitized: Trailer
|
||||
title_cap_2: Feb.1
|
||||
upload_date_both_caps: First and Second containing in regex default
|
||||
Jesse's Minecraft Server [Trailer - Feb.27].info.json
|
||||
Jesse's Minecraft Server [Trailer - Feb.27].jpg
|
||||
Jesse's Minecraft Server [Trailer - Feb.27].mp4
|
||||
Video Tags:
|
||||
album: Music Videos
|
||||
artist: regex_capture_playlist_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2011-02-27
|
||||
title: Jesse's Minecraft Server [Trailer - Feb.27]
|
||||
year: 2011
|
||||
Jesse's Minecraft Server [Trailer - Feb.27].nfo
|
||||
NFO tags:
|
||||
musicvideo:
|
||||
album: Music Videos
|
||||
artist: regex_capture_playlist_test
|
||||
desc_cap: jesseminecraft.webs
|
||||
genre: ytdl-sub
|
||||
override_with_capture_variable: contains Trailer
|
||||
override_with_capture_variable_sanitized: contains Trailer
|
||||
premiered: 2011-02-27
|
||||
title: Jesse's Minecraft Server [Trailer - Feb.27]
|
||||
title_cap_1: Trailer
|
||||
title_cap_1_sanitized: Trailer
|
||||
title_cap_2: Feb.27
|
||||
upload_date_both_caps: 2011 and 02
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
Files created:
|
||||
----------------------------------------
|
||||
{output_directory}
|
||||
.ytdl-sub-regex_exclude_playlist_test-download-archive.json
|
||||
{output_directory}/regex_exclude_playlist_test
|
||||
Jesse's Minecraft Server [Trailer - Mar.21].info.json
|
||||
Jesse's Minecraft Server [Trailer - Mar.21].jpg
|
||||
Jesse's Minecraft Server [Trailer - Mar.21].mp4
|
||||
Video Tags:
|
||||
album: Music Videos
|
||||
artist: regex_exclude_playlist_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2011-03-21
|
||||
title: Jesse's Minecraft Server [Trailer - Mar.21]
|
||||
year: 2011
|
||||
Jesse's Minecraft Server [Trailer - Mar.21].nfo
|
||||
NFO tags:
|
||||
musicvideo:
|
||||
album: Music Videos
|
||||
artist: regex_exclude_playlist_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2011-03-21
|
||||
title: Jesse's Minecraft Server [Trailer - Mar.21]
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
Files created:
|
||||
----------------------------------------
|
||||
{output_directory}
|
||||
.ytdl-sub-regex_match_and_exclude_playlist_test-download-archive.json
|
||||
{output_directory}/regex_match_and_exclude_playlist_test
|
||||
Jesse's Minecraft Server [Trailer - Feb.1].info.json
|
||||
Jesse's Minecraft Server [Trailer - Feb.1].jpg
|
||||
Jesse's Minecraft Server [Trailer - Feb.1].mp4
|
||||
Video Tags:
|
||||
album: Music Videos
|
||||
artist: regex_match_and_exclude_playlist_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2011-02-01
|
||||
title: Jesse's Minecraft Server [Trailer - Feb.1]
|
||||
year: 2011
|
||||
Jesse's Minecraft Server [Trailer - Feb.1].nfo
|
||||
NFO tags:
|
||||
musicvideo:
|
||||
album: Music Videos
|
||||
artist: regex_match_and_exclude_playlist_test
|
||||
desc_cap: www.jesseminecraft.webs
|
||||
genre: ytdl-sub
|
||||
override_with_capture_variable: contains Trailer
|
||||
override_with_capture_variable_sanitized: contains Trailer
|
||||
premiered: 2011-02-01
|
||||
title: Jesse's Minecraft Server [Trailer - Feb.1]
|
||||
title_cap_1: Trailer
|
||||
title_cap_1_sanitized: Trailer
|
||||
title_cap_2: Feb.1
|
||||
upload_date_both_caps: First and Second containing in regex default
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
Files created:
|
||||
----------------------------------------
|
||||
{output_directory}
|
||||
.ytdl-sub-regex_using_overrides_test-download-archive.json
|
||||
{output_directory}/regex_using_overrides_test
|
||||
Jesse's Minecraft Server [Trailer - Mar.21].info.json
|
||||
Jesse's Minecraft Server [Trailer - Mar.21].jpg
|
||||
Jesse's Minecraft Server [Trailer - Mar.21].mp4
|
||||
Video Tags:
|
||||
album: Music Videos
|
||||
artist: regex_using_overrides_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2011-03-21
|
||||
title: Jesse's Minecraft Server [Trailer - Mar.21]
|
||||
year: 2011
|
||||
Jesse's Minecraft Server [Trailer - Mar.21].nfo
|
||||
NFO tags:
|
||||
musicvideo:
|
||||
album: Music Videos
|
||||
artist: regex_using_overrides_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2011-03-21
|
||||
title: Jesse's Minecraft Server [Trailer - Mar.21]
|
||||
145
tests/unit/plugins/test_filter.py
Normal file
145
tests/unit/plugins/test_filter.py
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
from typing import Any
|
||||
from typing import Dict
|
||||
|
||||
import mergedeep
|
||||
import pytest
|
||||
from expected_transaction_log import assert_transaction_log_matches
|
||||
|
||||
from ytdl_sub.config.config_file import ConfigFile
|
||||
from ytdl_sub.subscriptions.subscription import Subscription
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def regex_subscription_dict_base(output_directory):
|
||||
return {
|
||||
"preset": "Jellyfin Music Videos",
|
||||
# override the output directory with our fixture-generated dir
|
||||
"output_options": {"output_directory": output_directory},
|
||||
"format": "best[height<=480]", # download the worst format so it is fast
|
||||
"filter_include": ["{%not(%is_null(description_website))}"],
|
||||
"overrides": {
|
||||
"in_regex_default": "in regex default",
|
||||
"url": "https://youtube.com/playlist?list=PL5BC0FC26BECA5A35",
|
||||
"upload_capture": """{
|
||||
%regex_capture_many_with_defaults(
|
||||
upload_date_standardized,
|
||||
["([0-9]+)-([0-9]+)-27"],
|
||||
["First", %concat("Second containing ", in_regex_default)]
|
||||
)
|
||||
}""",
|
||||
"upload_captured_year": "{%array_at(upload_capture, 1)}",
|
||||
"upload_captured_month": "{%array_at(upload_capture, 2)}",
|
||||
"description_capture": """{
|
||||
%regex_capture_many_with_defaults(
|
||||
description,
|
||||
["The (.*)"],
|
||||
[null]
|
||||
)
|
||||
}""",
|
||||
"description_website": "{%array_at(description_capture, 1)}",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def regex_subscription_dict(regex_subscription_dict_base, output_directory):
|
||||
return mergedeep.merge(
|
||||
regex_subscription_dict_base,
|
||||
{
|
||||
"nfo_tags": {
|
||||
"tags": {
|
||||
"title_cap_1": "{title_type}",
|
||||
"title_cap_1_sanitized": "{title_type_sanitized}",
|
||||
"title_cap_2": "{title_date}",
|
||||
"desc_cap": "{description_website}",
|
||||
"upload_date_both_caps": "{upload_captured_year} and {upload_captured_month}",
|
||||
"override_with_capture_variable": "{contains_regex_default}",
|
||||
"override_with_capture_variable_sanitized": "{contains_regex_sanitized_default}",
|
||||
}
|
||||
},
|
||||
"filter_exclude": ["{%is_null(title_type)}"],
|
||||
"overrides": {
|
||||
"title_capture_list": """{
|
||||
%regex_capture_many_with_defaults(
|
||||
title,
|
||||
[ "should not cap (.+) - (.+)", "Mock Entry (.*)-(.*)" ],
|
||||
[ null, null ]
|
||||
)
|
||||
}""",
|
||||
"title_type": "{%array_at(title_capture_list, 1)}",
|
||||
"title_date": "{%array_at(title_capture_list, 2)}",
|
||||
"contains_regex_default": "contains {title_type}",
|
||||
"contains_regex_sanitized_default": "contains {title_type_sanitized}",
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def regex_subscription_dict_exclude(regex_subscription_dict_base, output_directory):
|
||||
return mergedeep.merge(
|
||||
regex_subscription_dict_base,
|
||||
{
|
||||
"filter_exclude": [
|
||||
"""{
|
||||
%regex_search_any(
|
||||
title,
|
||||
[ "should not cap", "Mock Entry 20-.*" ]
|
||||
)
|
||||
}"""
|
||||
]
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def playlist_subscription(
|
||||
config: ConfigFile, subscription_name: str, regex_subscription_dict: Dict[str, Any]
|
||||
):
|
||||
return Subscription.from_dict(
|
||||
config=config,
|
||||
preset_name=subscription_name,
|
||||
preset_dict=regex_subscription_dict,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def playlist_subscription_exclude(
|
||||
config: ConfigFile, subscription_name: str, regex_subscription_dict_exclude: Dict[str, Any]
|
||||
) -> Subscription:
|
||||
return Subscription.from_dict(
|
||||
config=config,
|
||||
preset_name=subscription_name,
|
||||
preset_dict=regex_subscription_dict_exclude,
|
||||
)
|
||||
|
||||
|
||||
class TestFilter:
|
||||
def test_filter_regex_success(
|
||||
self, mock_download_collection_entries, playlist_subscription, output_directory
|
||||
):
|
||||
with mock_download_collection_entries(
|
||||
is_youtube_channel=False, num_urls=1, is_extracted_audio=False, is_dry_run=True
|
||||
):
|
||||
transaction_log = playlist_subscription.download(dry_run=True)
|
||||
|
||||
assert_transaction_log_matches(
|
||||
output_directory=output_directory,
|
||||
transaction_log=transaction_log,
|
||||
transaction_log_summary_file_name="plugins/filter/test_regex.txt",
|
||||
)
|
||||
|
||||
def test_filter_regex_excludes_success(
|
||||
self, mock_download_collection_entries, playlist_subscription_exclude, output_directory
|
||||
):
|
||||
# Should only contain the march video
|
||||
with mock_download_collection_entries(
|
||||
is_youtube_channel=False, num_urls=1, is_extracted_audio=False, is_dry_run=True
|
||||
):
|
||||
transaction_log = playlist_subscription_exclude.download(dry_run=True)
|
||||
|
||||
assert_transaction_log_matches(
|
||||
output_directory=output_directory,
|
||||
transaction_log=transaction_log,
|
||||
transaction_log_summary_file_name="plugins/filter/test_regex_exclude.txt",
|
||||
)
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
import pytest
|
||||
from unit.script.conftest import single_variable_output
|
||||
|
||||
from ytdl_sub.script.script import Script
|
||||
from ytdl_sub.script.utils.exceptions import FunctionRuntimeException
|
||||
|
||||
|
||||
class TestNumericFunctions:
|
||||
class TestRegexFunctions:
|
||||
@pytest.mark.parametrize(
|
||||
"values, expected_output",
|
||||
[
|
||||
|
|
@ -59,3 +59,37 @@ class TestNumericFunctions:
|
|||
def test_regex_sub(self, values: str, expected_output: str):
|
||||
output = single_variable_output(f"{{%regex_sub({values})}}")
|
||||
assert output == expected_output
|
||||
|
||||
def test_regex_capture_many_fails_no_match(self):
|
||||
with pytest.raises(
|
||||
FunctionRuntimeException,
|
||||
match="no regex strings were captured for input string the string",
|
||||
):
|
||||
single_variable_output(
|
||||
f"""{{
|
||||
%regex_capture_many(
|
||||
"the string",
|
||||
[
|
||||
"no (.*) match",
|
||||
"not here either (.*)"
|
||||
]
|
||||
)
|
||||
}}"""
|
||||
)
|
||||
|
||||
def test_regex_capture_many_fails_unequal_capture_groups(self):
|
||||
with pytest.raises(
|
||||
FunctionRuntimeException,
|
||||
match="regex_array elements must contain the same number of capture groups",
|
||||
):
|
||||
single_variable_output(
|
||||
f"""{{
|
||||
%regex_capture_many(
|
||||
"the string",
|
||||
[
|
||||
"no (.*) match",
|
||||
"(.*) not equal to 1 (.*)"
|
||||
]
|
||||
)
|
||||
}}"""
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in a new issue