From 17b67f34a5dc19aa656020aa664cc6c802abd8c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Mon, 4 May 2020 15:21:57 +0200 Subject: [PATCH] Fix error with redundant line breaks This fixes an error with a repository, where an added file has \r\r\n as line breaks. This interesting combination is handled as a single line break by the diff operation, while Java's Scanner implementation handles this as two lines (the first one delimited by the first \r, the second one delimited by \r\n. This led to empty lines inside the diff, where we only expect lines that contain at least one character (' ', '+' or '-'), and this in turn led to an index out of bounds exception. Now we handle each combination of any kind of new line delimiter characters as a single delimiter. This should be safe, because, as mentioned earlier, we always expect at least one character in a line for a diff output. --- .../scm/repository/spi/GitHunkParser.java | 8 ++--- .../scm/repository/spi/GitHunkParserTest.java | 29 ++++++++++++++++++- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitHunkParser.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitHunkParser.java index 88eae483cf..197c1ed03a 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitHunkParser.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitHunkParser.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.repository.spi; import sonia.scm.repository.api.DiffLine; @@ -49,9 +49,9 @@ final class GitHunkParser { public List parse(String content) { List hunks = new ArrayList<>(); - try (Scanner scanner = new Scanner(content)) { - while (scanner.hasNextLine()) { - String line = scanner.nextLine(); + try (Scanner scanner = new Scanner(content).useDelimiter("[\n\r\u2028\u2029\u0085]+")) { + while (scanner.hasNext()) { + String line = scanner.next(); if (line.startsWith("@@")) { parseHeader(hunks, line); } else if (currentGitHunk != null) { diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitHunkParserTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitHunkParserTest.java index 4bd56a0b1f..fda99ed7bf 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitHunkParserTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitHunkParserTest.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.repository.spi; import org.junit.jupiter.api.Test; @@ -103,6 +103,15 @@ class GitHunkParserTest { "+added line\n" + "\\ No newline at end of file\n"; + private static final String MULTIPLE_LINE_BREAKS = "diff --git a/.editorconfig b/.editorconfig\n" + + "index ea2a3ba..2f02f32 100644\n" + + "--- a/.editorconfig\n" + + "+++ b/.editorconfig\n" + + "@@ -10,3 +10,4 @@\n" + + " indent_style = space\r\r\n" + + " indent_size = 2\r\r\n" + + " charset = utf-8\n"; + @Test void shouldParseHunks() { List hunks = new GitHunkParser().parse(DIFF_001); @@ -183,6 +192,24 @@ void shouldIgnoreNoNewlineLine() { assertThat(lastLine.getContent()).isEqualTo("added line"); } + @Test + void shouldHandleMultipleLineBreaks() { + List hunks = new GitHunkParser().parse(MULTIPLE_LINE_BREAKS); + + Hunk hunk = hunks.get(0); + + Iterator lines = hunk.iterator(); + + DiffLine line1 = lines.next(); + assertThat(line1.getOldLineNumber()).hasValue(10); + assertThat(line1.getNewLineNumber()).hasValue(10); + assertThat(line1.getContent()).isEqualTo("indent_style = space"); + + lines.next(); + lines.next(); + assertThat(lines.hasNext()).isFalse(); + } + private void assertHunk(Hunk hunk, int oldStart, int oldLineCount, int newStart, int newLineCount) { assertThat(hunk.getOldStart()).isEqualTo(oldStart); assertThat(hunk.getOldLineCount()).isEqualTo(oldLineCount);