From 5815349914b88d2aba7600ff980f5ecd863a3bd4 Mon Sep 17 00:00:00 2001 From: Jesse Bannon Date: Fri, 15 Dec 2023 23:41:38 -0800 Subject: [PATCH] more tests --- src/ytdl_sub/script/parser.py | 13 +++++++------ src/ytdl_sub/script/types/variable_dependency.py | 6 +++++- tests/unit/script/types/test_custom_function.py | 14 ++++++++++++++ tests/unit/script/types/test_float.py | 4 +++- tests/unit/script/types/test_map.py | 11 +++++++++++ tests/unit/script/types/test_string.py | 3 +++ 6 files changed, 43 insertions(+), 8 deletions(-) diff --git a/src/ytdl_sub/script/parser.py b/src/ytdl_sub/script/parser.py index 9ae87bb2..7711ae9a 100644 --- a/src/ytdl_sub/script/parser.py +++ b/src/ytdl_sub/script/parser.py @@ -101,7 +101,7 @@ def _is_function_name_char(char: str) -> bool: def _is_numeric_start(char: str) -> bool: - return char.isnumeric() or char == "-" + return char.isnumeric() or char in (".", "-") def _is_string_start_single_char(char: Optional[str]) -> bool: @@ -222,8 +222,9 @@ class _Parser: variable_start_pos = self._pos while ch := self._read(increment_pos=False): if ch.isspace() and not var_name: - self._pos += 1 - continue + raise InvalidCustomFunctionArgumentName( + "Custom function arguments, denoted by $, cannot have a space proceeding it." + ) if _is_breakable(ch): break @@ -457,7 +458,7 @@ class _Parser: while ch := self._read(increment_pos=False): if ch == "}": if key is not None: - raise MAP_KEY_WITH_NO_VALUE + raise MAP_KEY_WITH_NO_VALUE # key args are parsed immediately self._pos += 1 return UnresolvedMap(value=output) @@ -466,7 +467,7 @@ class _Parser: if in_comma: raise _UNEXPECTED_COMMA_ARGUMENT(ParsedArgType.MAP_KEY) if key is not None: - raise MAP_KEY_WITH_NO_VALUE + raise MAP_KEY_WITH_NO_VALUE # key args are parsed immediately if not output: raise _UNEXPECTED_COMMA_ARGUMENT(ParsedArgType.MAP_KEY) in_comma = True @@ -496,7 +497,7 @@ class _Parser: if isinstance(key, NonHashable): raise MAP_KEY_NOT_HASHABLE if len(value_args) > 1: - raise UNREACHABLE + raise MAP_KEY_MULTIPLE_VALUES output[key] = value_args[0] key = None diff --git a/src/ytdl_sub/script/types/variable_dependency.py b/src/ytdl_sub/script/types/variable_dependency.py index 37215a13..8cd86134 100644 --- a/src/ytdl_sub/script/types/variable_dependency.py +++ b/src/ytdl_sub/script/types/variable_dependency.py @@ -28,7 +28,11 @@ class VariableDependency(ABC): @property @abstractmethod def _iterable_arguments(self) -> List[Argument]: - pass + """ + Returns + ------- + Any arguments in the VariableDependency that may or may not need to be resolved. + """ def _recurse_get(self, ttype: Type[TypeT], subclass: bool = False) -> List[TypeT]: output: List[TypeT] = [] diff --git a/tests/unit/script/types/test_custom_function.py b/tests/unit/script/types/test_custom_function.py index 4e846a1b..e7b76e80 100644 --- a/tests/unit/script/types/test_custom_function.py +++ b/tests/unit/script/types/test_custom_function.py @@ -219,3 +219,17 @@ class TestCustomFunction: "output": "{%mul(%func1(1), 1)}", } ).resolve() + + def test_function_argument_errors_has_spaces(self): + with pytest.raises( + InvalidCustomFunctionArgumentName, + match=re.escape( + "Custom function arguments, denoted by $, cannot have a space proceeding it." + ), + ): + Script( + { + "%func1": "{%mul($ 1, $0)}", + "output": "{%mul(%func1(1), 1)}", + } + ) diff --git a/tests/unit/script/types/test_float.py b/tests/unit/script/types/test_float.py index 4056488a..e285ce17 100644 --- a/tests/unit/script/types/test_float.py +++ b/tests/unit/script/types/test_float.py @@ -6,7 +6,6 @@ from ytdl_sub.script.parser import NUMERICS_INVALID_CHAR from ytdl_sub.script.parser import NUMERICS_ONLY_ARGS from ytdl_sub.script.script import Script from ytdl_sub.script.script_output import ScriptOutput -from ytdl_sub.script.types.resolvable import Boolean from ytdl_sub.script.types.resolvable import Float from ytdl_sub.script.types.resolvable import String from ytdl_sub.script.utils.exceptions import InvalidSyntaxException @@ -37,6 +36,8 @@ class TestFloat: ("{%float( -1.535 )}", -1.535), ("{%float(0001.)}", 1.0), ("{%float( 0001. )}", 1.0), + ("{%float(.2)}", 0.2), + ("{%float(-.1)}", -0.1), ], ) def test_float(self, float_: str, expected_float: int): @@ -56,6 +57,7 @@ class TestFloat: "{%add(0, -1.0. )}", "{%add(0,0001.a)}", "{%add(0, 0001.- )}", + "{%add(0, ..3)}", ], ) def test_invalid_float(self, float_: str): diff --git a/tests/unit/script/types/test_map.py b/tests/unit/script/types/test_map.py index a894b6b5..3a6608cf 100644 --- a/tests/unit/script/types/test_map.py +++ b/tests/unit/script/types/test_map.py @@ -101,6 +101,7 @@ class TestMap: "{{'key': }}", "{{'key':}}", "{{'key': 'value', 'key2':}}", + "{{'key1': 'value1','value2'}}", "{{'key': 'value', 'key2': }}", "{{ 'key': 'value', 'key2':\n}}", "{{ 'key': ,\n}}", @@ -138,6 +139,16 @@ class TestMap: with pytest.raises(InvalidSyntaxException, match=re.escape(str(MAP_KEY_MULTIPLE_VALUES))): Script({"dict": value}).resolve() + @pytest.mark.parametrize( + "value", + [ + "{{'key1': 'value1',}}", + "{{'key1': 'value1' , }}", + ], + ) + def test_map_trailing_comma_okay(self, value: str): + assert Script({"dict": value}).resolve().get_native("dict") == {"key1": "value1"} + @pytest.mark.parametrize( "value", [ diff --git a/tests/unit/script/types/test_string.py b/tests/unit/script/types/test_string.py index 697b59fe..c3749845 100644 --- a/tests/unit/script/types/test_string.py +++ b/tests/unit/script/types/test_string.py @@ -50,6 +50,9 @@ class TestString: def test_string(self, string: str, expected_string: str): assert Script({"out": string}).resolve() == ScriptOutput({"out": String(expected_string)}) + def test_null_is_empty_string(self): + assert Script({"out": "{%string(null)}"}).resolve() == ScriptOutput({"out": String("")}) + @pytest.mark.parametrize( "string", [