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

Fix: Define Steps produces incorrect cucumber expression for step definition (#28) #29

Merged

Conversation

clrudolphi
Copy link
Contributor

🤔 What's changed?

Modified the set of character escapes conducted within the CucumberExpressionSkeletonProvider such that the default set of characters needing escaping are escaped (such as was done within the Regex skeleton provider.

⚡️ What's your motivation?

This addresses the problem identified in GH28 in which empty parentheses resulted in an improper cucumber expression.

🏷️ What kind of change is this?

  • 🐛 Bug fix (non-breaking change which fixes a defect)

♻️ Anything particular you want feedback on?

@gasparnagy please confirm that these character escapes won't cause other problems with Cucumber expressions and they remain compliant with Cucumber syntax and semantics.

📋 Checklist:

  • [X ] I've changed the behaviour of the code
    • [ X] I have added/updated tests to cover my changes.
  • My change requires a change to the documentation.
    • I have updated the documentation accordingly.
  • Users should know about my change
    • [X ] I have added an entry to the "[vNext]" section of the CHANGELOG, linking to this pull request & included my GitHub handle to the release contributors list.

This text was originally taken from the template of the Cucumber project, then edited by hand. You can modify the template here.

@clrudolphi clrudolphi requested a review from gasparnagy June 19, 2024 21:11
@clrudolphi
Copy link
Contributor Author

@gasparnagy please review. My regex skills are not as good as yours.

Copy link
Contributor

@gasparnagy gasparnagy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thx! Please check my comments and the ref for the cucumber expression syntax specs.

CHANGELOG.md Show resolved Hide resolved
@@ -28,7 +28,7 @@ protected override string GetExpression(AnalyzedStepText stepText)

private string EscapeCucumberExpression(string text)
{
var escapedCukeEx = text.Replace(@"\", @"\\").Replace(@"{", @"\{").Replace("(", @"\");
var escapedCukeEx = Regex.Escape(text).Replace("\"", "\"\"").Replace(@"\ ", @" ");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code supposed to produce valid cucumber expressions and cucumber expressions are different from regex from the escaping perspective.

The cucumber expression escaping is defined at https://github.com/cucumber/cucumber-expressions?tab=readme-ov-file#escaping and it only allows escaping for: {, (, / and \.

Therefore we cannot use Regex.Escape(text) as it uses the regex escaping that is far more greedy than necessary. I think we would just need to fix the original code to match the specs: the .Replace("(", @"\") is clearly buggy, as it should be .Replace("(", @"\(") and the escaping for / is missing (so one more replace).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the reference.
Two follow-up questions then:

  1. In the original code, lines 31 and 32 both contain a Replace(@"", @"\"). Is that intentional?
  2. When escaping the forward slash ('/'), C# doesn't recognize @"/" as a valid escape sequence. I will attempt testing without escaping it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re: question 2 above, in my experimentation, I see now that / is meant to convey alternatives and so the use of a / in an example text fed into our snippet provider should treat that as a literal and should be escaped.
Since C# doesn't recognize that as a proper escape sequence, should the snippet provider generate the string as a strictly literal string (with the prepended @ sign)? Such as:

        [Given(@"I have {int} cucumber\(s) in my \/ belly")]

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I see that number 1 and 2 are related. When I leave line 32 as originally written, the example I'm using in number 2 is generated as

        [Given("I have {int} cucumber\\(s) in my \\/ belly")]

which is handled gracefully by the C# compiler without the prepended @ sign.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@clrudolphi I agree. Let's keep it this way. Switching over to @ strings (verbatim string) just complicates the things.

When I invoke the "Define Steps" command
Then the define steps dialog should be opened with the following step definition skeletons
| type | expression |
| When | I call the integer\\.ToString\\(\\) method |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The proper escaped version of I call the integer.ToString() method would be I call the integer.ToString\() method (the . should not be escaped). See above.

Maybe we can find a better example, so that it shows all escaped characters, like When I use (parenthesis), {curly braces} and/or \ backslash, where the escaped should be When I use \(parenthesis), \{curly braces} and\/or \\ backslash

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the Regex snippet provider behaving correctly as-is? It does escape the period, which if I'm not mistaken is required because it could otherwise be mistaken for a Regex pattern character. Correct?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, correct.

@clrudolphi clrudolphi changed the title Proposed fix for GH28 Fix: Define Steps produces incorrect cucumber expression for step definition (#28) Jun 20, 2024
@clrudolphi clrudolphi requested a review from gasparnagy June 20, 2024 15:41
@gasparnagy gasparnagy marked this pull request as ready for review June 20, 2024 18:44
Copy link
Contributor

@gasparnagy gasparnagy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thx!

@gasparnagy gasparnagy merged commit e4b903f into reqnroll:main Jun 20, 2024
1 check passed
@clrudolphi clrudolphi deleted the GH28_IncorrectRegexGeneratedWithParens branch June 25, 2024 15:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants