ytdl-sub/tests/unit/script/functions/test_map_functions.py
Jesse Bannon e92b1cd12a
[BACKEND][HUGE] Function Support in variable syntax (#838)
A complete gutting of the internals of ytdl-sub to support functions in our variable syntax, in addition to being able to access a yt-dlp entry's .info.json fields using functions. Functionally, ytdl-sub should still look and behave the same from a user-perspective.

With so many lines of code changed (+8927, -2708), no doubt there will be new issues. Please make a GH issue or reach out on Discord if your config/subscriptions break in any way/shape/form.

Details on how to use function support will come soon in the form of proper documentation in our readthedocs.
2023-12-18 16:08:15 -08:00

140 lines
4.3 KiB
Python

import re
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
from ytdl_sub.script.utils.exceptions import KeyDoesNotExistRuntimeException
from ytdl_sub.script.utils.exceptions import KeyNotHashableRuntimeException
class TestMapFunctions:
def test_map_get(self):
output = (
Script(
{
"input_map": "{{'key': 'value'}}",
"output": "{%map_get(input_map, 'key')}",
}
)
.resolve(update=True)
.get("output")
.native
)
assert output == "value"
def test_map_get_optional(self):
output = (
Script(
{
"input_map": "{{'key': 'value'}}",
"output": "{%map_get(input_map, 'dne', 'optional_value')}",
}
)
.resolve(update=True)
.get("output")
.native
)
assert output == "optional_value"
def test_map_get_errors_missing_key(self):
with pytest.raises(
KeyDoesNotExistRuntimeException,
match=re.escape("Tried to call %map_get with key dne, but it does not exist"),
):
Script(
{
"input_map": "{{'key': 'value'}}",
"output": "{%map_get(input_map, 'dne')}",
}
).resolve()
def test_map_get_errors_key_not_hashable(self):
with pytest.raises(
KeyNotHashableRuntimeException,
match=re.escape("Tried to use Array as a Map key, but it is not hashable."),
):
Script(
{
"non_hashable_key": "{%array([1, 2, ['nest']])}",
"input_map": "{{'key': 'value'}}",
"output": "{ %map_get( input_map, %array_at(non_hashable_key, 2)) }",
}
).resolve()
@pytest.mark.parametrize(
"contains_value, expected_value",
[
("'key'", True),
("'dne'", False),
("%string(%array_at(['dne', 'key'], 1))", True),
],
)
def test_map_contains(self, contains_value: str, expected_value: bool):
output = (
Script(
{
"input_map": "{{'key': 'value'}}",
"output": f"{{%map_contains(input_map, {contains_value})}}",
}
)
.resolve(update=True)
.get("output")
.native
)
assert output == expected_value
def test_map_apply(self):
output = (
Script(
{
"%custom_func": "{[%upper($0), %lower($1)]}",
"map1": "{{'Key1': 'Value1', 'Key2': 'Value2'}}",
"output": "{%map_apply(map1, %custom_func)}",
}
)
.resolve(update=True)
.get("output")
.native
)
assert output == [["KEY1", "value1"], ["KEY2", "value2"]]
def test_map_enumerate(self):
output = (
Script(
{
"%custom_func": "{[$0, %upper($1), %lower($2)]}",
"map1": "{{'Key1': 'Value1', 'Key2': 'Value2'}}",
"output": "{%map_enumerate(map1, %custom_func)}",
}
)
.resolve(update=True)
.get("output")
.native
)
assert output == [[0, "KEY1", "value1"], [1, "KEY2", "value2"]]
def test_map_size(self):
output = single_variable_output("{%map_size({'key': 'value', 1: 3})}")
assert output == 2
def test_cast_map(self):
output = (
Script(
{
"array_test": "{ [1, 2, {'key': 'value'}] }",
"output": "{ %map( %array_at(array_test, 2) )}",
}
)
.resolve(update=True)
.get("output")
.native
)
assert output == {"key": "value"}
def test_cast_map_errors_cannot_cast(self):
with pytest.raises(
FunctionRuntimeException, match="Tried and failed to cast Integer as a Map"
):
single_variable_output("{%map(1)}")