From df462ce2650415b39007b37674d7ddc17a476054 Mon Sep 17 00:00:00 2001 From: Jesse Bannon Date: Fri, 10 Nov 2023 09:50:56 -0800 Subject: [PATCH] more formal map tests --- src/ytdl_sub/script/parser.py | 36 ++++++++++++++------- tests/unit/script/types/test_map.py | 49 +++++++++++++++++++++++++---- 2 files changed, 68 insertions(+), 17 deletions(-) diff --git a/src/ytdl_sub/script/parser.py b/src/ytdl_sub/script/parser.py index 30a24d4d..d316a3fd 100644 --- a/src/ytdl_sub/script/parser.py +++ b/src/ytdl_sub/script/parser.py @@ -21,6 +21,13 @@ from ytdl_sub.validators.string_formatter_validators import is_valid_source_vari # pylint: disable=invalid-name +UNEXPECTED_ARGUMENT = InvalidSyntaxException("Unexpected comma when parsing arguments") +MAP_KEY_WITH_NO_VALUE = InvalidSyntaxException("Map has a key with no value") +MAP_KEY_MULTIPLE_VALUES = InvalidSyntaxException( + "Map key has multiple values when there should only be one" +) +MAP_MISSING_KEY = InvalidSyntaxException("Map has a missing key") + class _Parser: def __init__(self, text: str): @@ -189,7 +196,7 @@ class _Parser: comma_count += 1 if argument_index != comma_count: self._set_highlight_position() - raise InvalidSyntaxException("Unexpected comma when parsing arguments") + raise UNEXPECTED_ARGUMENT self._pos += 1 else: @@ -243,32 +250,39 @@ class _Parser: while ch := self._read(increment_pos=False): if ch == "}": if key is not None: - raise InvalidSyntaxException("Map has a key with no value") + raise MAP_KEY_WITH_NO_VALUE self._pos += 1 return UnresolvedMap(value=output) elif ch == ",": if in_comma: - raise StringFormattingException("Comma followed by comma") + raise UNEXPECTED_ARGUMENT if key is not None: - raise InvalidSyntaxException("Map has a key with no value") - if output is None: - raise InvalidSyntaxException("Map has an extra comma") + raise MAP_KEY_WITH_NO_VALUE + if not output: + raise UNEXPECTED_ARGUMENT in_comma = True self._pos += 1 elif key is None: self._set_highlight_position() in_comma = False - key_args = self._parse_args(breaking_chars=":") - if len(key_args) != 1: - raise StringFormattingException("Lazy parsing but got mlutiple args") + key_args = self._parse_args(breaking_chars=":}") + + if len(key_args) == 0 and self._read(increment_pos=False) == "}": + continue # will return the map next iteration + if len(key_args) == 0: + raise MAP_MISSING_KEY + if len(key_args) > 1: + raise MAP_KEY_MULTIPLE_VALUES key = key_args[0] elif key is not None and ch == ":": self._set_highlight_position() self._pos += 1 value_args = self._parse_args(breaking_chars=",}") - if len(value_args) != 1: - raise InvalidSyntaxException("Map has a key with no value") + if len(value_args) == 0: + raise MAP_KEY_WITH_NO_VALUE + if len(value_args) > 1: + raise StringFormattingException("map has key with multiple values") output[key] = value_args[0] key = None diff --git a/tests/unit/script/types/test_map.py b/tests/unit/script/types/test_map.py index cce577b7..e75eb703 100644 --- a/tests/unit/script/types/test_map.py +++ b/tests/unit/script/types/test_map.py @@ -2,6 +2,10 @@ import re import pytest +from ytdl_sub.script.parser import MAP_KEY_MULTIPLE_VALUES +from ytdl_sub.script.parser import MAP_KEY_WITH_NO_VALUE +from ytdl_sub.script.parser import MAP_MISSING_KEY +from ytdl_sub.script.parser import UNEXPECTED_ARGUMENT from ytdl_sub.script.script import Script from ytdl_sub.script.types.map import ResolvedMap from ytdl_sub.script.types.resolvable import Float @@ -57,8 +61,17 @@ class TestMap: ) } - def test_empty_map(self): - assert Script({"map": "{{}}"}).resolve() == {"map": ResolvedMap({})} + @pytest.mark.parametrize( + "empty_map", + [ + "{{}}", + "{{ }}", + "{{ }}", + "{{\n}}", + ], + ) + def test_empty_map(self, empty_map: str): + assert Script({"map": empty_map}).resolve() == {"map": ResolvedMap({})} @pytest.mark.parametrize( "value", @@ -72,18 +85,42 @@ class TestMap: ], ) def test_key_has_no_value(self, value: str): - with pytest.raises(InvalidSyntaxException, match=re.escape("Map has a key with no value")): + with pytest.raises(InvalidSyntaxException, match=re.escape(str(MAP_KEY_WITH_NO_VALUE))): Script({"map": value}).resolve() @pytest.mark.parametrize( "value", [ + "{{,}}", "{{ , }}", + "{{'key':'value',,}}", "{{'key': 'value', ,}}", ], ) def test_map_unexpected_comma(self, value: str): - with pytest.raises( - InvalidSyntaxException, match=re.escape("Unexpected comma when parsing arguments") - ): + with pytest.raises(InvalidSyntaxException, match=re.escape(str(UNEXPECTED_ARGUMENT))): + Script({"map": value}).resolve() + + @pytest.mark.parametrize( + "value", + [ + "{{'key1','key2'}}", + "{{'key1' , 'key2'}}", + "{{ 'key1', 'key2': 'value' }}", + ], + ) + def test_map_multiple_keys(self, value: str): + with pytest.raises(InvalidSyntaxException, match=re.escape(str(MAP_KEY_MULTIPLE_VALUES))): + Script({"map": value}).resolve() + + @pytest.mark.parametrize( + "value", + [ + "{{:}}", + "{{ : }}", + "{{ : 'value' }}", + ], + ) + def test_map_missing_key(self, value: str): + with pytest.raises(InvalidSyntaxException, match=re.escape(str(MAP_MISSING_KEY))): Script({"map": value}).resolve()