From 1286aa841921b8e0ea04f2f0b02c3d21cc178f61 Mon Sep 17 00:00:00 2001 From: Kieran Ryan Date: Mon, 13 Jan 2025 18:13:33 +0000 Subject: [PATCH 1/4] debt: Enable Python error message tests --- python/tests/data/test_errors.py | 1 - 1 file changed, 1 deletion(-) diff --git a/python/tests/data/test_errors.py b/python/tests/data/test_errors.py index b3a6d3fb..6aea794d 100644 --- a/python/tests/data/test_errors.py +++ b/python/tests/data/test_errors.py @@ -39,7 +39,6 @@ def read_testdata(data_filename): # ----------------------------------------------------------------------------- this_testdata = read_testdata(TESTDATA_FILE) -@pytest.mark.skip(reason="TOO MANY DIFFERENCES: Error message here are more specific (IMHO)") @pytest.mark.parametrize("expression, error", this_testdata) def test_errors_with_datafile(expression, error): with pytest.raises(TagExpressionError) as exc_info: From fce5356cee0f9543821bb0e4e497d9c887905744 Mon Sep 17 00:00:00 2001 From: Kieran Ryan Date: Mon, 13 Jan 2025 18:54:25 +0000 Subject: [PATCH 2/4] refactor: Standardise Python open parenthesesis error --- python/cucumber_tag_expressions/parser.py | 5 ++++- python/tests/unit/test_parser.py | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/python/cucumber_tag_expressions/parser.py b/python/cucumber_tag_expressions/parser.py index 7db37e47..440eb7c5 100644 --- a/python/cucumber_tag_expressions/parser.py +++ b/python/cucumber_tag_expressions/parser.py @@ -275,7 +275,10 @@ def ensure_expected_token_type(token_type, index): last_operation = operations.pop() if last_operation is Token.OPEN_PARENTHESIS: # -- CASE: TOO MANY OPEN-PARENTHESIS - message = "Unclosed '(': Too many open-parens in: %s" % text + message = ( + 'Tag expression "%s" could not be parsed because of syntax error:' + ' Unmatched (.' % text + ) raise TagExpressionError(message) cls._push_expression(last_operation, expressions) diff --git a/python/tests/unit/test_parser.py b/python/tests/unit/test_parser.py index 91177ab8..291ece1e 100644 --- a/python/tests/unit/test_parser.py +++ b/python/tests/unit/test_parser.py @@ -194,7 +194,7 @@ def test_parse__with_escape_repr(self, text, expected): # -- BAD CASES: @pytest.mark.parametrize("text, error_message", [ ("( a and b ))", "Missing '(': Too few open-parens"), - ("( ( a and b )", "Unclosed '(': Too many open-parens"), + ("( ( a and b )", "Unmatched (."), ]) def test_parse__fails_with_unbalanced_parens(self, text, error_message): self.assert_parse_with_error_contains_message(text, error_message) From 7026d16f7b099da70cc939eb0435e9ec18c92f77 Mon Sep 17 00:00:00 2001 From: Kieran Ryan Date: Mon, 13 Jan 2025 21:12:35 +0000 Subject: [PATCH 3/4] debt: Align too few open parens error message --- python/cucumber_tag_expressions/parser.py | 5 ++++- python/tests/unit/test_parser.py | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/python/cucumber_tag_expressions/parser.py b/python/cucumber_tag_expressions/parser.py index 440eb7c5..00c2f576 100644 --- a/python/cucumber_tag_expressions/parser.py +++ b/python/cucumber_tag_expressions/parser.py @@ -262,7 +262,10 @@ def ensure_expected_token_type(token_type, index): if not operations: # -- CASE: TOO FEW OPEN-PARENTHESIS - message = "Missing '(': Too few open-parens in: %s" % text + message = ( + 'Tag expression "%s" could not be parsed because of syntax ' + 'error: Unmatched ).' % text + ) message = cls._make_error_description(message, parts, index) raise TagExpressionError(message) elif operations[-1] is Token.OPEN_PARENTHESIS: diff --git a/python/tests/unit/test_parser.py b/python/tests/unit/test_parser.py index 291ece1e..1e6108f9 100644 --- a/python/tests/unit/test_parser.py +++ b/python/tests/unit/test_parser.py @@ -193,7 +193,7 @@ def test_parse__with_escape_repr(self, text, expected): # -- BAD CASES: @pytest.mark.parametrize("text, error_message", [ - ("( a and b ))", "Missing '(': Too few open-parens"), + ("( a and b ))", "Unmatched )."), ("( ( a and b )", "Unmatched (."), ]) def test_parse__fails_with_unbalanced_parens(self, text, error_message): From 638f6ab0c79e68b1748d202055ef98a32809469e Mon Sep 17 00:00:00 2001 From: Kieran Ryan Date: Mon, 13 Jan 2025 21:37:34 +0000 Subject: [PATCH 4/4] debt: Align Python syntax error messages --- python/cucumber_tag_expressions/parser.py | 6 ++++-- python/tests/unit/test_parser.py | 26 +++++++++++------------ 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/python/cucumber_tag_expressions/parser.py b/python/cucumber_tag_expressions/parser.py index 00c2f576..09787987 100644 --- a/python/cucumber_tag_expressions/parser.py +++ b/python/cucumber_tag_expressions/parser.py @@ -221,8 +221,10 @@ def parse(cls, text): def ensure_expected_token_type(token_type, index): if expected_token_type != token_type: - message = "Syntax error. Expected %s after %s" % \ - (expected_token_type.name.lower(), last_part) + message = ( + 'Tag expression "%s" could not be parsed because of syntax ' + 'error: Expected %s.' % (text, expected_token_type.name.lower()) + ) message = cls._make_error_description(message, parts, index) raise TagExpressionError(message) diff --git a/python/tests/unit/test_parser.py b/python/tests/unit/test_parser.py index 1e6108f9..1741b645 100644 --- a/python/tests/unit/test_parser.py +++ b/python/tests/unit/test_parser.py @@ -200,34 +200,34 @@ def test_parse__fails_with_unbalanced_parens(self, text, error_message): self.assert_parse_with_error_contains_message(text, error_message) @pytest.mark.parametrize("text, error_message", [ - ("a not ( and )", "Syntax error. Expected operator after a"), + ("a not ( and )", "syntax error: Expected operator"), ]) def test_parse__fails_with_missing_operation_args(self, text, error_message): self.assert_parse_with_error_contains_message(text, error_message) @pytest.mark.parametrize("text, error_message", [ - ("or or", "Syntax error. Expected operand after BEGIN"), + ("or or", "syntax error: Expected operand"), ]) def test_parse__fails_with_only_operations(self, text, error_message): self.assert_parse_with_error_contains_message(text, error_message) @pytest.mark.parametrize("text, error_message", [ - ("a b", "Syntax error. Expected operator after a"), + ("a b", "syntax error: Expected operator"), ]) def test_parse__fails_for_args_without_operation(self, text, error_message): self.assert_parse_with_error_contains_message(text, error_message) @pytest.mark.parametrize("text, error_message", [ - ("(())", "Syntax error. Expected operand after ("), - ("(() ())", "Syntax error. Expected operand after ("), + ("(())", "syntax error: Expected operand"), + ("(() ())", "syntax error: Expected operand"), ]) def test_parse__fails_for_empty_parens_groups(self, text, error_message): self.assert_parse_with_error_contains_message(text, error_message) @pytest.mark.parametrize("text, expected", [ - ("a b or", "Syntax error. Expected operator after a"), - ("a and (b not)", "Syntax error. Expected operator after b"), - ("a and (b c) or", "Syntax error. Expected operator after b"), + ("a b or", "syntax error: Expected operator"), + ("a and (b not)", "syntax error: Expected operator"), + ("a and (b c) or", "syntax error: Expected operator"), ]) def test_parse__fails_with_rpn_notation(self, text, expected): # -- NOTE: RPN parsebility due to Shunting-yard algorithm (stack-based). @@ -252,14 +252,14 @@ def test_parse__fails_with_rpn_notation(self, text, expected): # -- BAD CASES: Too few operands @pytest.mark.parametrize("text, error_message", [ ("a and ", "and: Too few operands"), - (" and b", "Syntax error. Expected operand after BEGIN"), + (" and b", "syntax error: Expected operand"), ]) def test_parse__fails_and_operation_with_too_few_args(self, text, error_message): self.assert_parse_with_error_contains_message(text, error_message) @pytest.mark.parametrize("text, error_message", [ ("a or ", "or: Too few operands"), - (" or b", "Syntax error. Expected operand after BEGIN"), + (" or b", "syntax error: Expected operand"), ("a and b or ", "or: Too few operands"), ]) def test_parse__fails_or_operation_with_too_few_args(self, text, error_message): @@ -267,9 +267,9 @@ def test_parse__fails_or_operation_with_too_few_args(self, text, error_message): @pytest.mark.parametrize("text, error_message", [ ("not ", "not: Too few operands"), - ("not ()", "Syntax error. Expected operand after ("), - ("not () and b", "Syntax error. Expected operand after ("), - ("not () or b", "Syntax error. Expected operand after ("), + ("not ()", "syntax error: Expected operand"), + ("not () and b", "syntax error: Expected operand"), + ("not () or b", "syntax error: Expected operand"), ]) def test_parse__fails_not_operation_with_too_few_args(self, text, error_message): self.assert_parse_with_error_contains_message(text, error_message)