-
-
Notifications
You must be signed in to change notification settings - Fork 2k
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
[Core] Fix PrettyFormatter exception on nested arguments #1200
[Core] Fix PrettyFormatter exception on nested arguments #1200
Conversation
Squashed all commits to this branch into one commit. |
I recommend you to rebase pull request branches instead of merging the master branch to a pull-request branch. My experience is that the latter confuses Github so it does not properly show only the changes of the pull request File Changed tab. |
Reverted accidental merge to master |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Empty. See next.
} | ||
} | ||
if (textStart != stepText.length()) { | ||
String text = stepText.substring(textStart, stepText.length()); | ||
if (beginIndex != stepText.length() && beginIndex >= 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
beginIndex >= 0 is not required here. We skip all nested capture groups (and all nested capture groups have a positive index).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Huh, you're right! I added it before, because it was throwing exception here also.. will update
StringBuilder result = new StringBuilder(textFormat.text(keyword)); | ||
for (Argument argument : arguments) { | ||
// can be null if the argument is missing. | ||
if (argument.getOffset() != null) { | ||
String text = stepText.substring(textStart, argument.getOffset()); | ||
int argumentOffset = argument.getOffset(); | ||
if (argumentOffset < beginIndex ) { // a nested argument starts before the enclosing argument ends; ignore it when formatting |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is okay to place line comments above the block or line they reference. Especially if the comment is long.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will do
Formats formats = new AnsiFormats(); | ||
Argument enclosingArg = new Argument(20, "and not yet confirmed"); | ||
Argument nestedArg = new Argument(-17, "not yet "); | ||
Argument nestedNestedArg = new Argument(-5, "yet "); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had forgotten to check if the examples were correct by writing an integration test. I have done so now.
In JdkPatternArgumentMatcherTest you can add this test to reproduce the examples:
@Test
public void canHandleNestedCaptureGroups() throws UnsupportedEncodingException {
assertVariables("the order is placed( and( not yet)? confirmed)?", "the order is placed and not yet confirmed",
" and not yet confirmed", 19,
" not yet", 23);
}
Important to note is that the indexes are not negative. They just come before the end of the previous capture group.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will do. Also, this answers my question of where to verify the regex actually does get parsed correctly etc... :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You've added the test but you didn't update the index values in the PrettyFormatterTest.
result.append(textFormat.text(text)); | ||
} | ||
// val can be null if the argument isn't there, for example @And("(it )?has something") | ||
if (argument.getVal() != null) { | ||
result.append(argFormat.text(argument.getVal())); | ||
textStart = argument.getOffset() + argument.getVal().length(); | ||
int argumentEnd = argument.getOffset() + argument.getVal().length(); // end of current argument; can be < 0 for nested argument | ||
beginIndex = argumentEnd; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is okay to combine both lines into a single statement.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I know (it was before). I added extra step to make it clearer (at least to me) what is going on. will change it back.
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
Summary
Fixed to ignore formatting for nested capture groups (arguments), as they are already formatted as an argument as part of the enclosing capture group (argument), thus no longer throwing StringIndexOutOfBoundsException which prevented additional scenarios/ features from running (#619).
Details
Added 2 tests to verify formatting of nested capture groups
Added 2 checks on variables passed to substring() to prevent StringIndexOutOfBoundsException (see more below).
Also did a minor refactor (=renamed these variables) for clarity.
Additionally, fixed a typo in PrettyFormatterTest
Motivation and Context
Nested capture groups could not be handled by the PrettyFormatter. Since each capture groups maps to an argument, this sort of gives an argument in an argument. A nested argument starts before the enclosing argument ends, throwing a StringIndexOutOfBoundsException on stepText.substring().
public String substring(int beginIndex, int endIndex) throws: IndexOutOfBoundsException - if the beginIndex is negative, or endIndex is larger than the length of this String object, or beginIndex is larger than endIndex.
The expected value for argument.offset is always negative for nested capture groups, as a nested argument starts before the previous (=enclosing) argument ends.
This means:
** Note: endIndex (argumentOffset) will not be larger than the length of this String object (stepText) -> no check needed
How Has This Been Tested?
Screenshots (if appropriate):
N/A
Types of changes
Checklist:
If necessary, add some documentation about PrettyFormatter (provided by @mpkorstanje ):
The pretty formatter creates a pretty looking text on the command line output. On windows this is white and plain, but when using a Unix Ansi compatible terminal this output is colored and has formatting.
Color and other formatting is enabled by printing a special escape sequence at the start of the part that should be colored. At the end of the markup a reset symbol is printed.
So the text
Given text arg1 text arg2
is rendered as "Given text arg1 text arg2".You can see an example of this in
should_mark_arguments_in_steps
.A nested capture group is a capture group inside a regex that is placed inside another capture group. For example:
the order is placed( and (not yet )? confirmed)?
This means that all these are valid steps:
The step
Given the order is placed and not yet confirmed
has two Arguments.And should be formatted as: "Given the order is placed and not yet confirmed". It is acceptable to completely skip the nested argument as the enclosing step has already been formatted from end to end.