diff --git a/src/ytdl_sub/script/parser.py b/src/ytdl_sub/script/parser.py index 5d6ee489..d00a9488 100644 --- a/src/ytdl_sub/script/parser.py +++ b/src/ytdl_sub/script/parser.py @@ -73,6 +73,10 @@ def _is_numeric_start(char: str) -> bool: return char.isnumeric() or char == "-" +def _is_breakable(char: str) -> bool: + return char in ["}", ",", ")", "]"] or char.isspace() + + class _Parser: def __init__(self, text: str): self._text = text @@ -118,7 +122,7 @@ class _Parser: if ch.isspace() and not var_name: self._pos += 1 continue - if ch in ["}", ",", ")", "]"] or ch.isspace(): + if _is_breakable(ch): break is_lower = ch.isascii() and ch.islower() @@ -146,7 +150,7 @@ class _Parser: if ch.isspace() and not var_name: self._pos += 1 continue - if ch in ["}", ",", ")", "]"] or ch.isspace(): + if _is_breakable(ch): break is_numeric = ch.isnumeric() @@ -185,8 +189,11 @@ class _Parser: elif ch.isnumeric(): self._pos += 1 numeric_string += ch - else: + elif _is_breakable(ch): break + else: + self._set_highlight_position() + raise NUMERICS_INVALID_CHAR if numeric_string == "." or numeric_string == "-": raise NUMERICS_INVALID_CHAR diff --git a/tests/unit/script/types/test_float.py b/tests/unit/script/types/test_float.py new file mode 100644 index 00000000..d00ae412 --- /dev/null +++ b/tests/unit/script/types/test_float.py @@ -0,0 +1,62 @@ +import re +from typing import Tuple + +import pytest + +from ytdl_sub.script.parser import NUMERICS_INVALID_CHAR +from ytdl_sub.script.parser import NUMERICS_ONLY_ARGS +from ytdl_sub.script.parser import UNEXPECTED_CHAR_ARGUMENT +from ytdl_sub.script.parser import UNEXPECTED_COMMA_ARGUMENT +from ytdl_sub.script.parser import ArgumentParser +from ytdl_sub.script.script import Script +from ytdl_sub.script.types.array import ResolvedArray +from ytdl_sub.script.types.resolvable import Float +from ytdl_sub.script.types.resolvable import Integer +from ytdl_sub.script.types.resolvable import String +from ytdl_sub.script.utils.exceptions import InvalidSyntaxException + + +class TestFloat: + @pytest.mark.parametrize( + "integer", + [ + "{1.0}", + "{ 1.2 }", + "{-1.4}", + "{ -1.5 }", + "{0001.2}", + "{ 0001.5 }", + ], + ) + def test_float_not_arg(self, integer: str): + with pytest.raises(InvalidSyntaxException, match=re.escape(str(NUMERICS_ONLY_ARGS))): + Script({"float": integer}).resolve() + + @pytest.mark.parametrize( + "float_, expected_float", + [ + ("{%float(1.1)}", 1.1), + ("{%float( 1.2345 )}", 1.2345), + ("{%float(-1.34)}", -1.34), + ("{%float( -1.535 )}", -1.535), + ("{%float(0001.)}", 1.0), + ("{%float( 0001. )}", 1.0), + ], + ) + def test_float(self, float_: str, expected_float: int): + assert Script({"float": float_}).resolve() == {"float": Float(expected_float)} + + @pytest.mark.parametrize( + "float_", + [ + "{%add(0, --1.0)}", + "{%add(0, 1-.0 )}", + "{%add(0,-1.0.)}", + "{%add(0, -1.0. )}", + "{%add(0,0001.a)}", + "{%add(0, 0001.- )}", + ], + ) + def test_invalid_float(self, float_: str): + with pytest.raises(InvalidSyntaxException, match=re.escape(str(NUMERICS_INVALID_CHAR))): + Script({"float": float_}).resolve()