Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Standardise Python to language agnostic errors #184

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions python/cucumber_tag_expressions/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -262,7 +264,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:
Expand All @@ -275,7 +280,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)

Expand Down
1 change: 0 additions & 1 deletion python/tests/data/test_errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
30 changes: 15 additions & 15 deletions python/tests/unit/test_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,41 +193,41 @@ 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 )."),
("( ( 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)

@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).
Expand All @@ -252,24 +252,24 @@ 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):
self.assert_parse_with_error_contains_message(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)
Expand Down
Loading