Skip to content

Commit 97653a3

Browse files
gasparnagyjsa34
andauthored
Python: Handle empty lines in Description AST node and add test cases when there is only a comment between the scenario line and the first step (#378)
* Add test cases * fix approved results * [Py] Handle case where line_tokens in Description AST node can be an empty list * Add changelog for regression fix when a feature file only has a comment in the description --------- Co-authored-by: Jason Allen <jsa34@cam.ac.uk>
1 parent 09cf93b commit 97653a3

7 files changed

+35
-14
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ This document is formatted according to the principles of [Keep A CHANGELOG](htt
99
## [Unreleased]
1010
### Changed
1111
- [CI] Replace deprecated `::set-output`
12+
- [Python] Fix a regression when a feature file only has a comment in the description
1213

1314
## [32.0.0] - 2025-02-17
1415
### Changed

python/gherkin/ast_builder.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -268,15 +268,13 @@ def transform_node(
268268
return self.get_table_rows(node)
269269
elif node.rule_type == "Description":
270270
line_tokens = node.get_tokens("Other")
271+
tokens = list(line_tokens)
272+
271273
# Trim trailing empty lines
272-
last_non_empty = next(
273-
i for i, j in reversed(list(enumerate(line_tokens))) if j.matched_text
274-
)
275-
description = "\n".join(
276-
[token.matched_text for token in line_tokens[: last_non_empty + 1]]
277-
)
274+
while tokens and not tokens[-1].matched_text:
275+
tokens.pop()
278276

279-
return description
277+
return "\n".join(token.matched_text for token in tokens)
280278
elif node.rule_type == "Rule":
281279
header = cast(Union[AstNode, None], node.get_single("RuleHeader"))
282280
if not header:

testdata/good/descriptions_with_comments.feature

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,13 @@ with a comment in the middle
5252

5353
| foo |
5454
| bar |
55+
56+
Scenario: scenario with just a comment
57+
# comment
58+
Given the minimalism
59+
60+
Scenario: scenario with a comment with new lines around
61+
62+
# comment
63+
64+
Given the minimalism
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"gherkinDocument":{"comments":[{"location":{"column":1,"line":3},"text":" # comment"},{"location":{"column":1,"line":5},"text":" # comment 2"},{"location":{"column":1,"line":9},"text":" # comment"},{"location":{"column":1,"line":10},"text":" # comment 2"},{"location":{"column":1,"line":16},"text":"# comment"},{"location":{"column":1,"line":18},"text":"# comment 2"},{"location":{"column":1,"line":24},"text":" # comment"},{"location":{"column":1,"line":31},"text":" # comment"},{"location":{"column":1,"line":34},"text":" # comment"},{"location":{"column":1,"line":39},"text":"# comment"},{"location":{"column":1,"line":41},"text":"# comment 2"},{"location":{"column":1,"line":43},"text":"# comment 3"},{"location":{"column":1,"line":47},"text":"# comment"},{"location":{"column":1,"line":49},"text":"# comment"},{"location":{"column":1,"line":51},"text":"# comment"}],"feature":{"children":[{"scenario":{"description":" This description\n has two lines and two comments in the middle and is indented with two spaces","examples":[],"id":"1","keyword":"Scenario","location":{"column":3,"line":7},"name":"two lines","steps":[{"id":"0","keyword":"Given ","keywordType":"Context","location":{"column":5,"line":12},"text":"the minimalism"}],"tags":[]}},{"scenario":{"description":"This is a description without indentation\nand a comment in the middle and at the end","examples":[],"id":"3","keyword":"Scenario","location":{"column":1,"line":14},"name":"without indentation","steps":[{"id":"2","keyword":"Given ","keywordType":"Context","location":{"column":3,"line":20},"text":"the minimalism"}],"tags":[]}},{"scenario":{"description":" This description\n\n has an empty line and a comment in the middle","examples":[],"id":"5","keyword":"Scenario","location":{"column":3,"line":22},"name":"empty lines in the middle","steps":[{"id":"4","keyword":"Given ","keywordType":"Context","location":{"column":5,"line":27},"text":"the minimalism"}],"tags":[]}},{"scenario":{"description":" This description\n has an empty lines around","examples":[],"id":"7","keyword":"Scenario","location":{"column":3,"line":29},"name":"empty lines around","steps":[{"id":"6","keyword":"Given ","keywordType":"Context","location":{"column":5,"line":36},"text":"the minimalism"}],"tags":[]}},{"scenario":{"description":"This is a scenario outline description with comments\nin the middle and before and at the end","examples":[{"description":"This is an examples description\nwith a comment in the middle","id":"11","keyword":"Examples","location":{"column":3,"line":46},"name":"examples with description","tableBody":[{"cells":[{"location":{"column":7,"line":54},"value":"bar"}],"id":"10","location":{"column":5,"line":54}}],"tableHeader":{"cells":[{"location":{"column":7,"line":53},"value":"foo"}],"id":"9","location":{"column":5,"line":53}},"tags":[]}],"id":"12","keyword":"Scenario Outline","location":{"column":3,"line":38},"name":"scenario outline with a description","steps":[{"id":"8","keyword":"Given ","keywordType":"Context","location":{"column":5,"line":44},"text":"the minimalism"}],"tags":[]}}],"description":" This is a description\n with a comment in the middle and at the end","keyword":"Feature","language":"en","location":{"column":1,"line":1},"name":"Descriptions with comments everywhere","tags":[]},"uri":"../testdata/good/descriptions_with_comments.feature"}}
1+
{"gherkinDocument":{"comments":[{"location":{"column":1,"line":3},"text":" # comment"},{"location":{"column":1,"line":5},"text":" # comment 2"},{"location":{"column":1,"line":9},"text":" # comment"},{"location":{"column":1,"line":10},"text":" # comment 2"},{"location":{"column":1,"line":16},"text":"# comment"},{"location":{"column":1,"line":18},"text":"# comment 2"},{"location":{"column":1,"line":24},"text":" # comment"},{"location":{"column":1,"line":31},"text":" # comment"},{"location":{"column":1,"line":34},"text":" # comment"},{"location":{"column":1,"line":39},"text":"# comment"},{"location":{"column":1,"line":41},"text":"# comment 2"},{"location":{"column":1,"line":43},"text":"# comment 3"},{"location":{"column":1,"line":47},"text":"# comment"},{"location":{"column":1,"line":49},"text":"# comment"},{"location":{"column":1,"line":51},"text":"# comment"},{"location":{"column":1,"line":57},"text":" # comment"},{"location":{"column":1,"line":62},"text":" # comment"}],"feature":{"children":[{"scenario":{"description":" This description\n has two lines and two comments in the middle and is indented with two spaces","examples":[],"id":"1","keyword":"Scenario","location":{"column":3,"line":7},"name":"two lines","steps":[{"id":"0","keyword":"Given ","keywordType":"Context","location":{"column":5,"line":12},"text":"the minimalism"}],"tags":[]}},{"scenario":{"description":"This is a description without indentation\nand a comment in the middle and at the end","examples":[],"id":"3","keyword":"Scenario","location":{"column":1,"line":14},"name":"without indentation","steps":[{"id":"2","keyword":"Given ","keywordType":"Context","location":{"column":3,"line":20},"text":"the minimalism"}],"tags":[]}},{"scenario":{"description":" This description\n\n has an empty line and a comment in the middle","examples":[],"id":"5","keyword":"Scenario","location":{"column":3,"line":22},"name":"empty lines in the middle","steps":[{"id":"4","keyword":"Given ","keywordType":"Context","location":{"column":5,"line":27},"text":"the minimalism"}],"tags":[]}},{"scenario":{"description":" This description\n has an empty lines around","examples":[],"id":"7","keyword":"Scenario","location":{"column":3,"line":29},"name":"empty lines around","steps":[{"id":"6","keyword":"Given ","keywordType":"Context","location":{"column":5,"line":36},"text":"the minimalism"}],"tags":[]}},{"scenario":{"description":"This is a scenario outline description with comments\nin the middle and before and at the end","examples":[{"description":"This is an examples description\nwith a comment in the middle","id":"11","keyword":"Examples","location":{"column":3,"line":46},"name":"examples with description","tableBody":[{"cells":[{"location":{"column":7,"line":54},"value":"bar"}],"id":"10","location":{"column":5,"line":54}}],"tableHeader":{"cells":[{"location":{"column":7,"line":53},"value":"foo"}],"id":"9","location":{"column":5,"line":53}},"tags":[]}],"id":"12","keyword":"Scenario Outline","location":{"column":3,"line":38},"name":"scenario outline with a description","steps":[{"id":"8","keyword":"Given ","keywordType":"Context","location":{"column":5,"line":44},"text":"the minimalism"}],"tags":[]}},{"scenario":{"description":"","examples":[],"id":"14","keyword":"Scenario","location":{"column":3,"line":56},"name":"scenario with just a comment","steps":[{"id":"13","keyword":"Given ","keywordType":"Context","location":{"column":5,"line":58},"text":"the minimalism"}],"tags":[]}},{"scenario":{"description":"","examples":[],"id":"16","keyword":"Scenario","location":{"column":3,"line":60},"name":"scenario with a comment with new lines around","steps":[{"id":"15","keyword":"Given ","keywordType":"Context","location":{"column":5,"line":64},"text":"the minimalism"}],"tags":[]}}],"description":" This is a description\n with a comment in the middle and at the end","keyword":"Feature","language":"en","location":{"column":1,"line":1},"name":"Descriptions with comments everywhere","tags":[]},"uri":"../testdata/good/descriptions_with_comments.feature"}}
Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
{"pickle":{"astNodeIds":["1"],"id":"14","language":"en","name":"two lines","steps":[{"astNodeIds":["0"],"id":"13","text":"the minimalism","type":"Context"}],"tags":[],"uri":"../testdata/good/descriptions_with_comments.feature"}}
2-
{"pickle":{"astNodeIds":["3"],"id":"16","language":"en","name":"without indentation","steps":[{"astNodeIds":["2"],"id":"15","text":"the minimalism","type":"Context"}],"tags":[],"uri":"../testdata/good/descriptions_with_comments.feature"}}
3-
{"pickle":{"astNodeIds":["5"],"id":"18","language":"en","name":"empty lines in the middle","steps":[{"astNodeIds":["4"],"id":"17","text":"the minimalism","type":"Context"}],"tags":[],"uri":"../testdata/good/descriptions_with_comments.feature"}}
4-
{"pickle":{"astNodeIds":["7"],"id":"20","language":"en","name":"empty lines around","steps":[{"astNodeIds":["6"],"id":"19","text":"the minimalism","type":"Context"}],"tags":[],"uri":"../testdata/good/descriptions_with_comments.feature"}}
5-
{"pickle":{"astNodeIds":["12","10"],"id":"22","language":"en","name":"scenario outline with a description","steps":[{"astNodeIds":["8","10"],"id":"21","text":"the minimalism","type":"Context"}],"tags":[],"uri":"../testdata/good/descriptions_with_comments.feature"}}
1+
{"pickle":{"astNodeIds":["1"],"id":"18","language":"en","name":"two lines","steps":[{"astNodeIds":["0"],"id":"17","text":"the minimalism","type":"Context"}],"tags":[],"uri":"../testdata/good/descriptions_with_comments.feature"}}
2+
{"pickle":{"astNodeIds":["3"],"id":"20","language":"en","name":"without indentation","steps":[{"astNodeIds":["2"],"id":"19","text":"the minimalism","type":"Context"}],"tags":[],"uri":"../testdata/good/descriptions_with_comments.feature"}}
3+
{"pickle":{"astNodeIds":["5"],"id":"22","language":"en","name":"empty lines in the middle","steps":[{"astNodeIds":["4"],"id":"21","text":"the minimalism","type":"Context"}],"tags":[],"uri":"../testdata/good/descriptions_with_comments.feature"}}
4+
{"pickle":{"astNodeIds":["7"],"id":"24","language":"en","name":"empty lines around","steps":[{"astNodeIds":["6"],"id":"23","text":"the minimalism","type":"Context"}],"tags":[],"uri":"../testdata/good/descriptions_with_comments.feature"}}
5+
{"pickle":{"astNodeIds":["12","10"],"id":"26","language":"en","name":"scenario outline with a description","steps":[{"astNodeIds":["8","10"],"id":"25","text":"the minimalism","type":"Context"}],"tags":[],"uri":"../testdata/good/descriptions_with_comments.feature"}}
6+
{"pickle":{"astNodeIds":["14"],"id":"28","language":"en","name":"scenario with just a comment","steps":[{"astNodeIds":["13"],"id":"27","text":"the minimalism","type":"Context"}],"tags":[],"uri":"../testdata/good/descriptions_with_comments.feature"}}
7+
{"pickle":{"astNodeIds":["16"],"id":"30","language":"en","name":"scenario with a comment with new lines around","steps":[{"astNodeIds":["15"],"id":"29","text":"the minimalism","type":"Context"}],"tags":[],"uri":"../testdata/good/descriptions_with_comments.feature"}}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"source":{"data":"Feature: Descriptions with comments everywhere\n This is a description\n # comment\n with a comment in the middle and at the end\n # comment 2\n\n Scenario: two lines\n This description\n # comment\n # comment 2\n has two lines and two comments in the middle and is indented with two spaces\n Given the minimalism\n\nScenario: without indentation\nThis is a description without indentation\n# comment\nand a comment in the middle and at the end\n# comment 2\n\n Given the minimalism\n\n Scenario: empty lines in the middle\n This description\n # comment\n\n has an empty line and a comment in the middle\n Given the minimalism\n\n Scenario: empty lines around\n\n # comment\n This description\n has an empty lines around\n # comment\n\n Given the minimalism\n\n Scenario Outline: scenario outline with a description\n# comment\nThis is a scenario outline description with comments\n# comment 2\nin the middle and before and at the end\n# comment 3\n Given the minimalism\n\n Examples: examples with description\n# comment\nThis is an examples description\n# comment\nwith a comment in the middle\n# comment\n\n | foo |\n | bar |\n","mediaType":"text/x.cucumber.gherkin+plain","uri":"../testdata/good/descriptions_with_comments.feature"}}
1+
{"source":{"data":"Feature: Descriptions with comments everywhere\n This is a description\n # comment\n with a comment in the middle and at the end\n # comment 2\n\n Scenario: two lines\n This description\n # comment\n # comment 2\n has two lines and two comments in the middle and is indented with two spaces\n Given the minimalism\n\nScenario: without indentation\nThis is a description without indentation\n# comment\nand a comment in the middle and at the end\n# comment 2\n\n Given the minimalism\n\n Scenario: empty lines in the middle\n This description\n # comment\n\n has an empty line and a comment in the middle\n Given the minimalism\n\n Scenario: empty lines around\n\n # comment\n This description\n has an empty lines around\n # comment\n\n Given the minimalism\n\n Scenario Outline: scenario outline with a description\n# comment\nThis is a scenario outline description with comments\n# comment 2\nin the middle and before and at the end\n# comment 3\n Given the minimalism\n\n Examples: examples with description\n# comment\nThis is an examples description\n# comment\nwith a comment in the middle\n# comment\n\n | foo |\n | bar |\n\n Scenario: scenario with just a comment\n # comment\n Given the minimalism\n\n Scenario: scenario with a comment with new lines around\n\n # comment\n\n Given the minimalism ","mediaType":"text/x.cucumber.gherkin+plain","uri":"../testdata/good/descriptions_with_comments.feature"}}

testdata/good/descriptions_with_comments.feature.tokens

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,14 @@
5252
(52:1)Other://
5353
(53:5)TableRow://7:foo
5454
(54:5)TableRow://7:bar
55+
(55:1)Empty://
56+
(56:3)ScenarioLine:()Scenario/scenario with just a comment/
57+
(57:1)Comment:/ # comment/
58+
(58:5)StepLine:(Context)Given /the minimalism/
59+
(59:1)Empty://
60+
(60:3)ScenarioLine:()Scenario/scenario with a comment with new lines around/
61+
(61:1)Empty://
62+
(62:1)Comment:/ # comment/
63+
(63:1)Other://
64+
(64:5)StepLine:(Context)Given /the minimalism/
5565
EOF

0 commit comments

Comments
 (0)