diff --git a/src/ytdl_sub/script/functions/error_functions.py b/src/ytdl_sub/script/functions/error_functions.py index 3a1be9f5..34b92a74 100644 --- a/src/ytdl_sub/script/functions/error_functions.py +++ b/src/ytdl_sub/script/functions/error_functions.py @@ -20,9 +20,10 @@ class ErrorFunctions: Explicitly throw an error with the provided assert message if ``value`` evaluates to False. If it evaluates to True, it will return ``value``. """ - if not bool(value.value): + evaluated_val = value.value() + if not bool(evaluated_val.value): raise UserThrownRuntimeError(assert_message) - return value + return evaluated_val @staticmethod def assert_then( @@ -35,7 +36,7 @@ class ErrorFunctions: """ if not bool(value.value): raise UserThrownRuntimeError(assert_message) - return ret + return ret.value() @staticmethod def assert_eq( @@ -46,9 +47,10 @@ class ErrorFunctions: Explicitly throw an error with the provided assert message if ``value`` does not equal ``equals``. If they do equal, then return ``value``. """ - if not value.value == equals.value: + evaluated_val = value.value() + if not evaluated_val.value == equals.value: raise UserThrownRuntimeError(assert_message) - return value + return evaluated_val @staticmethod def assert_ne( @@ -59,6 +61,7 @@ class ErrorFunctions: Explicitly throw an error with the provided assert message if ``value`` equals ``equals``. If they do equal, then return ``value``. """ - if value.value == equals.value: + evaluated_value = value.value() + if evaluated_value.value == equals.value: raise UserThrownRuntimeError(assert_message) - return value + return evaluated_value diff --git a/src/ytdl_sub/script/types/function.py b/src/ytdl_sub/script/types/function.py index a61fc7d4..7ecd1999 100644 --- a/src/ytdl_sub/script/types/function.py +++ b/src/ytdl_sub/script/types/function.py @@ -259,7 +259,7 @@ class BuiltInFunction(Function, BuiltInFunctionType): resolved_variables: Dict[Variable, Resolvable], custom_functions: Dict[str, "VariableDependency"], ) -> Resolvable: - # TODO: Make conditionals not execute all branches!!! + # Ensure conditionals do not execute all branches conditional_return_args = self.function_spec.conditional_arg_indices( num_input_args=len(self.args) ) diff --git a/src/ytdl_sub/script/utils/type_checking.py b/src/ytdl_sub/script/utils/type_checking.py index 2489760b..e8a8bc79 100644 --- a/src/ytdl_sub/script/utils/type_checking.py +++ b/src/ytdl_sub/script/utils/type_checking.py @@ -208,6 +208,10 @@ class FunctionSpec: return list(range(1, num_input_args, 2)) + [num_input_args - 1] if self.function_name == "if_passthrough": return [0, 1] # true-passthrough, false-passthrough + if self.function_name in ("assert", "assert_eq", "assert_ne"): + return [0] + if self.function_name == "assert_then": + return [1] return [] @property diff --git a/tests/integration/prebuilt_presets/test_filter_keywords.py b/tests/integration/prebuilt_presets/test_filter_keywords.py index 5c68cbf5..41761b03 100644 --- a/tests/integration/prebuilt_presets/test_filter_keywords.py +++ b/tests/integration/prebuilt_presets/test_filter_keywords.py @@ -1,8 +1,9 @@ import re import pytest - from expected_transaction_log import assert_transaction_log_matches + +from ytdl_sub.script.utils.exceptions import UserThrownRuntimeError from ytdl_sub.subscriptions.subscription import Subscription from ytdl_sub.utils.exceptions import ValidationException @@ -14,12 +15,10 @@ def filter_subscription_dict(output_directory): "Plex TV Show by Date", "Filter Keywords", ], - "overrides": { - "url": "https://your.name.here", - "tv_show_directory": output_directory - } + "overrides": {"url": "https://your.name.here", "tv_show_directory": output_directory}, } + class TestFilterKeywords: def test_no_overrides( @@ -36,7 +35,7 @@ class TestFilterKeywords: preset_dict=filter_subscription_dict, ) - with mock_download_collection_entries( + with mock_download_collection_entries( is_youtube_channel=False, num_urls=1, is_dry_run=True ): transaction_log = subscription.download(dry_run=True) @@ -59,7 +58,7 @@ class TestFilterKeywords: ): filter_subscription_dict["overrides"][f"title_{filter_mode}_keywords"] = [ "not included", - "MOCK ENTRY 20-3" + "MOCK ENTRY 20-3", ] subscription = Subscription.from_dict( config=config, @@ -67,7 +66,7 @@ class TestFilterKeywords: preset_dict=filter_subscription_dict, ) - with mock_download_collection_entries( + with mock_download_collection_entries( is_youtube_channel=False, num_urls=1, is_dry_run=True ): transaction_log = subscription.download(dry_run=True) @@ -75,7 +74,7 @@ class TestFilterKeywords: assert_transaction_log_matches( output_directory=output_directory, transaction_log=transaction_log, - transaction_log_summary_file_name=f"integration/prebuilt_presets/filter_keywords_{filter_mode}.txt", + transaction_log_summary_file_name=f"integration/prebuilt_presets/title_filter_keywords_{filter_mode}.txt", ) @pytest.mark.parametrize("filter_mode", ["include", "exclude"]) @@ -89,8 +88,8 @@ class TestFilterKeywords: filter_mode: str, ): filter_subscription_dict["overrides"][f"description_{filter_mode}_keywords"] = [ - "not included", - "MOCK ENTRY 20-3" + "no filter here", + "description", ] subscription = Subscription.from_dict( config=config, @@ -98,7 +97,7 @@ class TestFilterKeywords: preset_dict=filter_subscription_dict, ) - with mock_download_collection_entries( + with mock_download_collection_entries( is_youtube_channel=False, num_urls=1, is_dry_run=True ): transaction_log = subscription.download(dry_run=True) @@ -106,25 +105,67 @@ class TestFilterKeywords: assert_transaction_log_matches( output_directory=output_directory, transaction_log=transaction_log, - transaction_log_summary_file_name=f"integration/prebuilt_presets/filter_keywords_{filter_mode}.txt", + transaction_log_summary_file_name=f"integration/prebuilt_presets/description_filter_keywords_{filter_mode}.txt", ) + @pytest.mark.parametrize( + "keyword_variable", + [ + "title_include_keywords", + "title_exclude_keywords", + "description_include_keywords", + "description_exclude_keywords", + ], + ) def test_error_not_list_type( - self, - config, - filter_subscription_dict, - output_directory, - subscription_name, - mock_download_collection_entries, + self, + config, + filter_subscription_dict, + output_directory, + subscription_name, + mock_download_collection_entries, + keyword_variable, ): - filter_subscription_dict["overrides"][f"description_include_keywords"] = "not list" + filter_subscription_dict["overrides"][keyword_variable] = "not array" subscription = Subscription.from_dict( config=config, preset_name=subscription_name, preset_dict=filter_subscription_dict, ) - with mock_download_collection_entries( - is_youtube_channel=False, num_urls=1, is_dry_run=True + with ( + mock_download_collection_entries(is_youtube_channel=False, num_urls=1, is_dry_run=True), + pytest.raises(UserThrownRuntimeError, match=f"{keyword_variable} must be an array"), ): - transaction_log = subscription.download(dry_run=True) \ No newline at end of file + _ = subscription.download(dry_run=True) + + @pytest.mark.parametrize( + "keyword_variable", + [ + "title_include_keywords", + "title_exclude_keywords", + "description_include_keywords", + "description_exclude_keywords", + ], + ) + def test_error_not_string_keyword( + self, + config, + filter_subscription_dict, + output_directory, + subscription_name, + mock_download_collection_entries, + keyword_variable, + ): + filter_subscription_dict["overrides"][keyword_variable] = "{['str', ['nested array not']]}" + subscription = Subscription.from_dict( + config=config, + preset_name=subscription_name, + preset_dict=filter_subscription_dict, + ) + + with ( + mock_download_collection_entries(is_youtube_channel=False, num_urls=1, is_dry_run=True), + pytest.raises(UserThrownRuntimeError, match="filter keywords must be strings"), + ): + _ = subscription.download(dry_run=True) diff --git a/tests/resources.py b/tests/resources.py index bb9808fd..8a426c9e 100644 --- a/tests/resources.py +++ b/tests/resources.py @@ -2,7 +2,7 @@ import os import shutil from pathlib import Path -REGENERATE_FIXTURES: bool = True +REGENERATE_FIXTURES: bool = False RESOURCE_PATH: Path = Path("tests") / "resources" _FILE_FIXTURE_PATH: Path = RESOURCE_PATH / "file_fixtures" diff --git a/tests/resources/transaction_log_summaries/integration/prebuilt_presets/filter_keywords_include.txt b/tests/resources/transaction_log_summaries/integration/prebuilt_presets/description_filter_keywords_exclude.txt similarity index 100% rename from tests/resources/transaction_log_summaries/integration/prebuilt_presets/filter_keywords_include.txt rename to tests/resources/transaction_log_summaries/integration/prebuilt_presets/description_filter_keywords_exclude.txt diff --git a/tests/resources/transaction_log_summaries/integration/prebuilt_presets/filter_keywords_exclude.txt b/tests/resources/transaction_log_summaries/integration/prebuilt_presets/description_filter_keywords_include.txt similarity index 100% rename from tests/resources/transaction_log_summaries/integration/prebuilt_presets/filter_keywords_exclude.txt rename to tests/resources/transaction_log_summaries/integration/prebuilt_presets/description_filter_keywords_include.txt diff --git a/tests/resources/transaction_log_summaries/integration/prebuilt_presets/title_filter_keywords_exclude.txt b/tests/resources/transaction_log_summaries/integration/prebuilt_presets/title_filter_keywords_exclude.txt new file mode 100644 index 00000000..36d8f389 --- /dev/null +++ b/tests/resources/transaction_log_summaries/integration/prebuilt_presets/title_filter_keywords_exclude.txt @@ -0,0 +1,51 @@ +Files created: +---------------------------------------- +{output_directory} + .ytdl-sub-subscription_test-download-archive.json +{output_directory}/Season 2020 + s2020.e080801 - Mock Entry 20-2-thumb.jpg + s2020.e080801 - Mock Entry 20-2.info.json + s2020.e080801 - Mock Entry 20-2.mp4 + Video Tags: + contentRating: TV-14 + date: 2020-08-08 + episode_id: 80801 + genre: ytdl-sub + show: subscription_test + synopsis: + https://20-2.com + + The Description + title: 2020-08-08 - Mock Entry 20-2 + year: 2020 + s2020.e080802 - Mock Entry 20-1-thumb.jpg + s2020.e080802 - Mock Entry 20-1.info.json + s2020.e080802 - Mock Entry 20-1.mp4 + Video Tags: + contentRating: TV-14 + date: 2020-08-08 + episode_id: 80802 + genre: ytdl-sub + show: subscription_test + synopsis: + https://20-1.com + + The Description + title: 2020-08-08 - Mock Entry 20-1 + year: 2020 +{output_directory}/Season 2021 + s2021.e080801 - Mock Entry 21-1-thumb.jpg + s2021.e080801 - Mock Entry 21-1.info.json + s2021.e080801 - Mock Entry 21-1.mp4 + Video Tags: + contentRating: TV-14 + date: 2021-08-08 + episode_id: 80801 + genre: ytdl-sub + show: subscription_test + synopsis: + https://21-1.com + + The Description + title: 2021-08-08 - Mock Entry 21-1 + year: 2021 \ No newline at end of file diff --git a/tests/resources/transaction_log_summaries/integration/prebuilt_presets/title_filter_keywords_include.txt b/tests/resources/transaction_log_summaries/integration/prebuilt_presets/title_filter_keywords_include.txt new file mode 100644 index 00000000..cf4f5275 --- /dev/null +++ b/tests/resources/transaction_log_summaries/integration/prebuilt_presets/title_filter_keywords_include.txt @@ -0,0 +1,20 @@ +Files created: +---------------------------------------- +{output_directory} + .ytdl-sub-subscription_test-download-archive.json +{output_directory}/Season 2020 + s2020.e080701 - Mock Entry 20-3-thumb.jpg + s2020.e080701 - Mock Entry 20-3.info.json + s2020.e080701 - Mock Entry 20-3.mp4 + Video Tags: + contentRating: TV-14 + date: 2020-08-07 + episode_id: 80701 + genre: ytdl-sub + show: subscription_test + synopsis: + https://20-3.com + + The Description + title: 2020-08-07 - Mock Entry 20-3 + year: 2020 \ No newline at end of file