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

[Core] Fix PrettyFormatter exception on nested arguments #1200

Merged
merged 3 commits into from
Aug 20, 2017
Merged

[Core] Fix PrettyFormatter exception on nested arguments #1200

merged 3 commits into from
Aug 20, 2017

Conversation

mlvandijk
Copy link
Member

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.

  • beginIndex = argument offset + length of argument
  • endIndex = argumentOffset

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:

  • beginIndex could be < 0, throwing an Exception -> Added check to verify beginIndex >= 0
  • beginIndex could be larger than endIndex -> Added check verify endIndex < beginIndex
    ** Note: endIndex (argumentOffset) will not be larger than the length of this String object (stepText) -> no check needed

How Has This Been Tested?

  1. Reproduce original bug by creating a test expecting StringIndexOutOfBoundsException. Removed this test once it failed after implementation of the fix.
  2. Added 2 tests to test that nested argument(s) is/are formatted as part of the enclosing argument (and no Exception is thrown).
  3. Clean/install cucumber-jvm core (i.e. checking all other tests still pass).

Screenshots (if appropriate):

N/A

Types of changes

  • Bug fix (non-breaking change which fixes an issue).
  • New feature (non-breaking change which adds functionality).
  • Breaking change (fix or feature that would cause existing functionality to not work as expected).

Checklist:

  • I've added tests for my code.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.

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:

Given the order is placed
Given the order is placed and confirmed
Given the order is placed and not yet confirmed

The step Given the order is placed and not yet confirmed has two Arguments.

new Argument(20, "and not yet confirmed")
new Argument(-21, "not yet")

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.

@mlvandijk mlvandijk requested a review from mpkorstanje August 17, 2017 18:09
@mlvandijk
Copy link
Member Author

Squashed all commits to this branch into one commit.
Additional commit to resolve merge conflict with master.

@brasmusson
Copy link
Contributor

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.

@mlvandijk
Copy link
Member Author

Reverted accidental merge to master
Rebased master to (under?) this branch.

Copy link
Contributor

@mpkorstanje mpkorstanje left a 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) {
Copy link
Contributor

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).

Copy link
Member Author

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
Copy link
Contributor

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.

Copy link
Member Author

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 ");
Copy link
Contributor

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.

Copy link
Member Author

@mlvandijk mlvandijk Aug 20, 2017

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... :)

Copy link
Contributor

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;
Copy link
Contributor

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.

Copy link
Member Author

@mlvandijk mlvandijk Aug 20, 2017

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.

@coveralls
Copy link

Coverage Status

Coverage increased (+0.01%) to 56.198% when pulling db9a533 on mlvandijk:pretty-formatter-nested-args into 161e765 on cucumber:master.

@coveralls
Copy link

Coverage Status

Coverage increased (+0.01%) to 56.198% when pulling 5b65317 on mlvandijk:pretty-formatter-nested-args into 161e765 on cucumber:master.

@mpkorstanje mpkorstanje merged commit 0adf669 into cucumber:master Aug 20, 2017
@coveralls
Copy link

Coverage Status

Coverage increased (+0.01%) to 56.198% when pulling d1e6c23 on mlvandijk:pretty-formatter-nested-args into 161e765 on cucumber:master.

@coveralls
Copy link

Coverage Status

Coverage increased (+0.01%) to 56.198% when pulling d1e6c23 on mlvandijk:pretty-formatter-nested-args into 161e765 on cucumber:master.

@lock
Copy link

lock bot commented Oct 24, 2018

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.

@lock lock bot locked as resolved and limited conversation to collaborators Oct 24, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants