ytdl-sub/tests/unit/config/test_preset.py
2022-10-25 22:15:39 -07:00

299 lines
11 KiB
Python

import re
from typing import Dict
from typing import Optional
import pytest
from ytdl_sub.config.config_file import ConfigFile
from ytdl_sub.config.preset import PRESET_KEYS
from ytdl_sub.config.preset import Preset
from ytdl_sub.plugins.nfo_tags import NfoTagsOptions
from ytdl_sub.utils.exceptions import StringFormattingVariableNotFoundException
from ytdl_sub.utils.exceptions import ValidationException
class TestPreset:
@pytest.mark.parametrize(
"source, download_strategy",
[
("youtube", {"download_strategy": "video", "video_url": "youtube.com/watch?v=123abc"}),
(
"youtube",
{
"download_strategy": "playlist",
"playlist_url": "youtube.com/playlist?list=123abc",
},
),
("youtube", {"download_strategy": "channel", "channel_url": "youtube.com/c/123abc"}),
(
"soundcloud",
{"download_strategy": "albums_and_singles", "url": "soundcloud.com/123abc"},
),
],
)
def test_bare_minimum_preset(self, config_file, output_options, source, download_strategy):
_ = Preset(
config=config_file,
name="test",
value={source: download_strategy, "output_options": output_options},
)
def test_preset_with_override_variable(self, config_file, output_options, youtube_video):
_ = Preset(
config=config_file,
name="test",
value={
"youtube": youtube_video,
"output_options": {"output_directory": "dir", "file_name": "{dne_var}"},
"overrides": {"dne_var": "not dne"},
},
)
def test_preset_parent(self, config_file, output_options, youtube_video):
preset = Preset(
config=config_file,
name="test",
value={
"preset": "parent_preset_1",
"youtube": youtube_video,
"output_options": output_options,
"nfo_tags": {"tags": {"key-2": "this-preset"}},
},
)
nfo_options: NfoTagsOptions = preset.plugins.get(NfoTagsOptions)
tags_string_dict = {
key: formatter[0].format_string
for key, formatter in nfo_options.tags.string_tags.items()
}
assert tags_string_dict == {"key-1": "preset_0", "key-2": "this-preset"}
@pytest.mark.parametrize(
"preset_value", [["parent_preset_1", "parent_preset_2"], "parent_preset_3"]
)
def test_preset_multiple_parents(
self, config_file, output_options, youtube_video, preset_value
):
preset = Preset(
config=config_file,
name="test",
value={
"preset": preset_value,
"youtube": youtube_video,
"output_options": output_options,
"nfo_tags": {"tags": {"key-3": "this-preset"}},
},
)
nfo_options: NfoTagsOptions = preset.plugins.get(NfoTagsOptions)
tags_string_dict = {
key: formatter[0].format_string
for key, formatter in nfo_options.tags.string_tags.items()
}
assert tags_string_dict == {
"key-1": "preset_0",
"key-2": "preset_2",
"key-3": "this-preset",
}
def test_preset_datetime_with_override(self, config_file, youtube_video, output_options):
preset = Preset(
config=config_file,
name="test",
value={
"youtube": youtube_video,
"output_options": dict(
output_options,
**{"maintain_download_archive": True, "keep_files_after": "today-{ttl}"},
),
"overrides": {"ttl": "2months"},
},
)
assert (
preset.overrides.apply_formatter(formatter=preset.output_options.keep_files_after)
== "today-2months"
)
@pytest.mark.parametrize(
"parent_preset", ["preset_self_loop", "preset_loop_0", "preset_loop_1"]
)
def test_preset_error__parent_loop(
self, config_file, output_options, youtube_video, parent_preset
):
with pytest.raises(ValidationException, match="preset loop detected"):
_ = Preset(
config=config_file,
name="test",
value={
"preset": parent_preset,
"youtube": youtube_video,
"output_options": output_options,
},
)
def test_preset_error__source_variable_does_not_exist(
self, config_file, output_options, youtube_video
):
with pytest.raises(
StringFormattingVariableNotFoundException,
match="Format variable 'dne_var' does not exist",
):
_ = Preset(
config=config_file,
name="test",
value={
"youtube": youtube_video,
"output_options": {"output_directory": "dir", "file_name": "{dne_var}"},
},
)
def test_preset_error__override_variable_does_not_exist(
self, config_file, output_options, youtube_video
):
with pytest.raises(
StringFormattingVariableNotFoundException,
match="Override variable 'dne_var' does not exist",
):
_ = Preset(
config=config_file,
name="test",
value={
"youtube": youtube_video,
"output_options": {"output_directory": "{dne_var}", "file_name": "file"},
},
)
def test_preset_error__dict_source_variable_does_not_exist(
self, config_file, output_options, youtube_video
):
with pytest.raises(
StringFormattingVariableNotFoundException,
match="Format variable 'dne_var' does not exist",
):
_ = Preset(
config=config_file,
name="test",
value={
"youtube": youtube_video,
"output_options": {"output_directory": "dir", "file_name": "file"},
"nfo_tags": {
"nfo_name": "the nfo name",
"nfo_root": "the root",
"tags": {"tag_a": "{dne_var}"},
},
},
)
def test_preset_error__dict_override_variable_does_not_exist(
self, config_file, output_options, youtube_video
):
with pytest.raises(
StringFormattingVariableNotFoundException,
match="Format variable 'dne_var' does not exist",
):
_ = Preset(
config=config_file,
name="test",
value={
"youtube": youtube_video,
"output_options": {"output_directory": "dir", "file_name": "file"},
"output_directory_nfo_tags": {
"nfo_name": "the nfo name",
"nfo_root": "the root",
"tags": {"tag_a": "{dne_var}"},
},
},
)
class TestPresetPartialValidate:
@classmethod
def _partial_validate(
cls, preset_dict: Dict, expected_error_message: Optional[str] = None
) -> None:
def _config_create() -> None:
_ = ConfigFile(
name="test_partial_validate",
value={
"configuration": {"working_directory": "."},
"presets": {"partial_preset": preset_dict},
},
)
if expected_error_message:
with pytest.raises(ValidationException, match=re.escape(expected_error_message)):
_config_create()
else:
_config_create()
@pytest.mark.parametrize(
"preset_dict",
[
{"nfo_tags": {"tags": {"key-1": "preset_0"}}},
{"output_directory_nfo_tags": {"nfo_root": "test"}},
{"output_directory": {"file_name": "test"}},
{"output_directory": {"keep_files_after": "today"}},
{"ytdl_options": {"format": "best"}},
],
)
def test_success(self, preset_dict: Dict):
self._partial_validate(
preset_dict,
)
def test_error__bad_preset_section(self):
self._partial_validate(
preset_dict={"does_not_exist": "lol"},
expected_error_message="Validation error in partial_preset: "
"'partial_preset' contains the field 'does_not_exist' which is not allowed. "
f"Allowed fields: {', '.join(sorted(PRESET_KEYS))}",
)
def test_error__multiple_sources(self):
self._partial_validate(
preset_dict={"youtube": {}, "generic": {}},
expected_error_message="Validation error in partial_preset: "
"Contains the sources generic, youtube but can only have one",
)
def test_error__no_download_strategy(self):
self._partial_validate(
preset_dict={"generic": {}},
expected_error_message="Validation error in partial_preset.generic: "
"missing the required field 'download_strategy'",
)
def test_error__bad_download_strategy(self):
self._partial_validate(
preset_dict={"generic": {"download_strategy": "fail"}},
expected_error_message="Validation error in partial_preset.generic: "
"Tried to use download strategy 'fail' with source 'generic', "
"which does not exist. Available download strategies: collection, source",
)
def test_error__bad_download_strategy_args(self):
self._partial_validate(
preset_dict={"generic": {"download_strategy": "collection", "bad_key": "nope"}},
expected_error_message="Validation error in partial_preset.generic: "
"'partial_preset.generic' contains the field 'bad_key' which is not allowed. "
"Allowed fields: urls",
)
@pytest.mark.parametrize(
"preset_dict",
[
{"nfo_tags": {"tags": {"key-1": {"attributes": {"test": "2"}}}}},
{"generic": {"urls": [{"variables_to_set": {"name": "value"}}]}},
],
)
def test_partial_validate__incomplete_list_item(self, preset_dict):
with pytest.raises(ValidationException):
_ = ConfigFile(
name="test_partial_validate",
value={
"configuration": {"working_directory": "."},
"presets": {"partial_preset": preset_dict},
},
)