function argument tests
This commit is contained in:
parent
79d9be3f23
commit
23c7b3acbf
4 changed files with 70 additions and 4 deletions
|
|
@ -9,6 +9,7 @@ from ytdl_sub.script.types.syntax_tree import SyntaxTree
|
||||||
from ytdl_sub.script.types.variable import Variable
|
from ytdl_sub.script.types.variable import Variable
|
||||||
from ytdl_sub.script.utils.exceptions import UNREACHABLE
|
from ytdl_sub.script.utils.exceptions import UNREACHABLE
|
||||||
from ytdl_sub.script.utils.exceptions import CycleDetected
|
from ytdl_sub.script.utils.exceptions import CycleDetected
|
||||||
|
from ytdl_sub.script.utils.exceptions import InvalidCustomFunctionArguments
|
||||||
from ytdl_sub.script.utils.name_validation import validate_variable_name
|
from ytdl_sub.script.utils.name_validation import validate_variable_name
|
||||||
|
|
||||||
# pylint: disable=missing-raises-doc
|
# pylint: disable=missing-raises-doc
|
||||||
|
|
@ -93,6 +94,21 @@ class Script:
|
||||||
deps=[],
|
deps=[],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def _ensure_custom_function_arguments_valid(self):
|
||||||
|
for custom_function_name, custom_function in self._functions.items():
|
||||||
|
indices = sorted([arg.index for arg in custom_function.function_arguments])
|
||||||
|
if indices != list(range(len(indices))):
|
||||||
|
if len(indices) == 1:
|
||||||
|
raise InvalidCustomFunctionArguments(
|
||||||
|
f"Custom function %{custom_function_name} has invalid function arguments: "
|
||||||
|
f"The argument must start with $0, not ${indices[0]}."
|
||||||
|
)
|
||||||
|
raise InvalidCustomFunctionArguments(
|
||||||
|
f"Custom function %{custom_function_name} has invalid function arguments: "
|
||||||
|
f"{', '.join(sorted(f'${idx}' for idx in indices))} "
|
||||||
|
f"do not increment from $0 to ${len(indices) - 1}."
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(self, overrides: Dict[str, str]):
|
def __init__(self, overrides: Dict[str, str]):
|
||||||
function_names: Set[str] = {
|
function_names: Set[str] = {
|
||||||
self._function_name(name) for name in overrides.keys() if self._is_function(name)
|
self._function_name(name) for name in overrides.keys() if self._is_function(name)
|
||||||
|
|
@ -126,6 +142,7 @@ class Script:
|
||||||
}
|
}
|
||||||
|
|
||||||
self._ensure_no_custom_function_cycles()
|
self._ensure_no_custom_function_cycles()
|
||||||
|
self._ensure_custom_function_arguments_valid()
|
||||||
self._ensure_no_variable_cycles()
|
self._ensure_no_variable_cycles()
|
||||||
|
|
||||||
def resolve(
|
def resolve(
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,10 @@ class Variable(NamedArgument):
|
||||||
class FunctionArgument(Variable):
|
class FunctionArgument(Variable):
|
||||||
"""Arguments for custom functions, i.e. $0, $1, etc"""
|
"""Arguments for custom functions, i.e. $0, $1, etc"""
|
||||||
|
|
||||||
|
index: int
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_idx(cls, idx: int, custom_function_name: Optional[str]) -> "FunctionArgument":
|
def from_idx(cls, idx: int, custom_function_name: Optional[str]) -> "FunctionArgument":
|
||||||
if custom_function_name:
|
if custom_function_name:
|
||||||
return FunctionArgument(name=f"${custom_function_name}___{idx}")
|
return FunctionArgument(name=f"${custom_function_name}___{idx}", index=idx)
|
||||||
return FunctionArgument(name=f"${idx}")
|
return FunctionArgument(name=f"${idx}", index=idx)
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,10 @@ class InvalidFunctionName(UserException):
|
||||||
"""Custom function name is invalid"""
|
"""Custom function name is invalid"""
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidCustomFunctionArguments(UserException):
|
||||||
|
"""Custom function arguments are invalid (i.e. they do not increment)"""
|
||||||
|
|
||||||
|
|
||||||
class InvalidCustomFunctionArgumentName(UserException):
|
class InvalidCustomFunctionArgumentName(UserException):
|
||||||
"""Custom function argument name (i.e. $0) is invalid"""
|
"""Custom function argument name (i.e. $0) is invalid"""
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,11 @@ import re
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from ytdl_sub.script.script import Script
|
from ytdl_sub.script.script import Script
|
||||||
from ytdl_sub.script.types.array import ResolvedArray
|
|
||||||
from ytdl_sub.script.types.resolvable import Integer
|
from ytdl_sub.script.types.resolvable import Integer
|
||||||
from ytdl_sub.script.utils.exceptions import CycleDetected
|
from ytdl_sub.script.utils.exceptions import CycleDetected
|
||||||
from ytdl_sub.script.utils.exceptions import FunctionDoesNotExist
|
from ytdl_sub.script.utils.exceptions import FunctionDoesNotExist
|
||||||
from ytdl_sub.script.utils.exceptions import InvalidCustomFunctionArgumentName
|
from ytdl_sub.script.utils.exceptions import InvalidCustomFunctionArgumentName
|
||||||
|
from ytdl_sub.script.utils.exceptions import InvalidCustomFunctionArguments
|
||||||
|
|
||||||
|
|
||||||
class TestCustomFunction:
|
class TestCustomFunction:
|
||||||
|
|
@ -90,7 +90,7 @@ class TestCustomFunction:
|
||||||
"$3.14",
|
"$3.14",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_custom_function_invalid_function_arguments(self, name: str):
|
def test_custom_function_invalid_function_argument_names(self, name: str):
|
||||||
with pytest.raises(
|
with pytest.raises(
|
||||||
InvalidCustomFunctionArgumentName,
|
InvalidCustomFunctionArgumentName,
|
||||||
match=re.escape(
|
match=re.escape(
|
||||||
|
|
@ -104,3 +104,46 @@ class TestCustomFunction:
|
||||||
"output": "{%func0(1)}",
|
"output": "{%func0(1)}",
|
||||||
}
|
}
|
||||||
).resolve()
|
).resolve()
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"argument",
|
||||||
|
[
|
||||||
|
"$1",
|
||||||
|
"$2",
|
||||||
|
"$3",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_custom_function_invalid_function_argument_single(self, argument: str):
|
||||||
|
with pytest.raises(
|
||||||
|
InvalidCustomFunctionArguments,
|
||||||
|
match=re.escape(
|
||||||
|
f"Custom function %func1 has invalid function arguments: "
|
||||||
|
f"The argument must start with $0, not {argument}."
|
||||||
|
),
|
||||||
|
):
|
||||||
|
Script(
|
||||||
|
{
|
||||||
|
"%func1": f"{{[{argument}]}}",
|
||||||
|
}
|
||||||
|
).resolve()
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"arguments",
|
||||||
|
[
|
||||||
|
"$0, $2",
|
||||||
|
"$1, $2, $3",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_custom_function_invalid_function_argument_out_of_order(self, arguments: str):
|
||||||
|
with pytest.raises(
|
||||||
|
InvalidCustomFunctionArguments,
|
||||||
|
match=re.escape(
|
||||||
|
f"Custom function %func1 has invalid function arguments: "
|
||||||
|
f"{arguments} do not increment from $0 to ${len(arguments.split(',')) - 1}."
|
||||||
|
),
|
||||||
|
):
|
||||||
|
Script(
|
||||||
|
{
|
||||||
|
"%func1": f"{{[{arguments}]}}",
|
||||||
|
}
|
||||||
|
).resolve()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue