Implement preview fix endpoint
Change-Id: I70366164d89bb798b435e31d2670261676b9fc04
diff --git a/Documentation/rest-api-changes.txt b/Documentation/rest-api-changes.txt
index 5055007..d6a7092 100644
--- a/Documentation/rest-api-changes.txt
+++ b/Documentation/rest-api-changes.txt
@@ -5356,6 +5356,17 @@
The `context` parameter can be specified to control the number of lines of surrounding context
in the diff. Valid values are `ALL` or number of lines.
+[[preview-fix]]
+=== Preview fix
+--
+'GET /changes/<<change-id,\{change-id\}>>/revisions/<<revision-id,\{revision-id\}>>/fixes/<<fix-id,\{fix-id\}>>/preview'
+--
+
+Gets the diffs of all files for a certain <<fix-id,\{fix-id\}>>.
+As response, a map of link:#diff-info[DiffInfo] entities is returned that describes the diffs.
+
+Each link:#diff-info[DiffInfo] is the differences between the patch set indicated by revision-id and a virtual patch set with the applied fix.
+
[[get-blame]]
=== Get Blame
--
diff --git a/java/com/google/gerrit/acceptance/BUILD b/java/com/google/gerrit/acceptance/BUILD
index cb3524a..e4a993c 100644
--- a/java/com/google/gerrit/acceptance/BUILD
+++ b/java/com/google/gerrit/acceptance/BUILD
@@ -90,6 +90,7 @@
"//java/com/google/gerrit/pgm:daemon",
"//java/com/google/gerrit/pgm/http/jetty",
"//java/com/google/gerrit/pgm/util",
+ "//java/com/google/gerrit/server/fixes/testing",
"//java/com/google/gerrit/server/group/testing",
"//java/com/google/gerrit/server/project/testing:project-test-util",
"//java/com/google/gerrit/testing:gerrit-test-util",
diff --git a/java/com/google/gerrit/extensions/common/testing/DiffInfoSubject.java b/java/com/google/gerrit/extensions/common/testing/DiffInfoSubject.java
index 8853a30..e258134 100644
--- a/java/com/google/gerrit/extensions/common/testing/DiffInfoSubject.java
+++ b/java/com/google/gerrit/extensions/common/testing/DiffInfoSubject.java
@@ -18,12 +18,15 @@
import static com.google.gerrit.extensions.common.testing.FileMetaSubject.fileMetas;
import static com.google.gerrit.truth.ListSubject.elements;
+import com.google.common.truth.BooleanSubject;
import com.google.common.truth.ComparableSubject;
import com.google.common.truth.FailureMetadata;
+import com.google.common.truth.IterableSubject;
import com.google.common.truth.Subject;
import com.google.gerrit.extensions.common.ChangeType;
import com.google.gerrit.extensions.common.DiffInfo;
import com.google.gerrit.extensions.common.DiffInfo.ContentEntry;
+import com.google.gerrit.extensions.common.DiffInfo.IntraLineStatus;
import com.google.gerrit.truth.ListSubject;
public class DiffInfoSubject extends Subject {
@@ -60,4 +63,24 @@
isNotNull();
return check("metaB").about(fileMetas()).that(diffInfo.metaB);
}
+
+ public ComparableSubject<IntraLineStatus> intralineStatus() {
+ isNotNull();
+ return check("intralineStatus").that(diffInfo.intralineStatus);
+ }
+
+ public IterableSubject webLinks() {
+ isNotNull();
+ return check("webLinks").that(diffInfo.webLinks);
+ }
+
+ public BooleanSubject binary() {
+ isNotNull();
+ return check("binary").that(diffInfo.binary);
+ }
+
+ public IterableSubject diffHeader() {
+ isNotNull();
+ return check("diffHeader").that(diffInfo.diffHeader);
+ }
}
diff --git a/java/com/google/gerrit/extensions/common/testing/FileMetaSubject.java b/java/com/google/gerrit/extensions/common/testing/FileMetaSubject.java
index fb09a1f..0953bfe 100644
--- a/java/com/google/gerrit/extensions/common/testing/FileMetaSubject.java
+++ b/java/com/google/gerrit/extensions/common/testing/FileMetaSubject.java
@@ -18,6 +18,8 @@
import com.google.common.truth.FailureMetadata;
import com.google.common.truth.IntegerSubject;
+import com.google.common.truth.IterableSubject;
+import com.google.common.truth.StringSubject;
import com.google.common.truth.Subject;
import com.google.gerrit.extensions.common.DiffInfo.FileMeta;
@@ -42,4 +44,24 @@
isNotNull();
return check("totalLineCount()").that(fileMeta.lines);
}
+
+ public StringSubject name() {
+ isNotNull();
+ return check("name").that(fileMeta.name);
+ }
+
+ public StringSubject commitId() {
+ isNotNull();
+ return check("commitId").that(fileMeta.commitId);
+ }
+
+ public StringSubject contentType() {
+ isNotNull();
+ return check("contentType").that(fileMeta.contentType);
+ }
+
+ public IterableSubject webLinks() {
+ isNotNull();
+ return check("webLinks").that(fileMeta.webLinks);
+ }
}
diff --git a/java/com/google/gerrit/server/config/GerritGlobalModule.java b/java/com/google/gerrit/server/config/GerritGlobalModule.java
index 2a0466f..edf8864 100644
--- a/java/com/google/gerrit/server/config/GerritGlobalModule.java
+++ b/java/com/google/gerrit/server/config/GerritGlobalModule.java
@@ -158,6 +158,7 @@
import com.google.gerrit.server.notedb.NoteDbModule;
import com.google.gerrit.server.patch.PatchListCacheImpl;
import com.google.gerrit.server.patch.PatchScriptFactory;
+import com.google.gerrit.server.patch.PatchScriptFactoryForAutoFix;
import com.google.gerrit.server.patch.PatchSetInfoFactory;
import com.google.gerrit.server.permissions.PermissionCollection;
import com.google.gerrit.server.permissions.SectionSortCache;
@@ -261,6 +262,7 @@
factory(LabelsJson.Factory.class);
factory(MergeUtil.Factory.class);
factory(PatchScriptFactory.Factory.class);
+ factory(PatchScriptFactoryForAutoFix.Factory.class);
factory(ProjectState.Factory.class);
factory(RevisionJson.Factory.class);
factory(InboundEmailRejectionSender.Factory.class);
diff --git a/java/com/google/gerrit/server/fixes/FixCalculator.java b/java/com/google/gerrit/server/fixes/FixCalculator.java
new file mode 100644
index 0000000..5d9d2c2
--- /dev/null
+++ b/java/com/google/gerrit/server/fixes/FixCalculator.java
@@ -0,0 +1,366 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.fixes;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import com.google.common.collect.ImmutableList;
+import com.google.gerrit.entities.Comment;
+import com.google.gerrit.entities.FixReplacement;
+import com.google.gerrit.extensions.restapi.ResourceConflictException;
+import com.google.gerrit.jgit.diff.ReplaceEdit;
+import com.google.gerrit.server.patch.Text;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import org.eclipse.jgit.diff.Edit;
+
+/**
+ * Produces final version of an input content with all fixes applied together with list of edits.
+ */
+public class FixCalculator {
+ private static final Comparator<FixReplacement> ASC_RANGE_FIX_REPLACEMENT_COMPARATOR =
+ Comparator.comparing(fixReplacement -> fixReplacement.range);
+
+ private FixCalculator() {}
+
+ /**
+ * Returns a result of applying fixes to an original content.
+ *
+ * @param originalContent is a text to which fixes must be applied
+ * @param fixReplacements is a list of fixes to be applied
+ * @throws ResourceConflictException if the fixReplacements contains invalid data (for example, if
+ * an item points to an invalid range or if some ranges are intersected).
+ */
+ public static String getNewFileContent(
+ String originalContent, List<FixReplacement> fixReplacements)
+ throws ResourceConflictException {
+ FixResult fixResult = calculateFix(new Text(originalContent.getBytes(UTF_8)), fixReplacements);
+ return fixResult.text.getString(0, fixResult.text.size(), false);
+ }
+
+ /**
+ * Returns a result of applying fixes to an original content and list of applied edits.
+ *
+ * @param originalText is a text to which fixes must be applied
+ * @param fixReplacements is a list of fixes to be applied
+ * @return {@link FixResult}
+ * @throws ResourceConflictException if the fixReplacements contains invalid data (for example, if
+ * an item points to an invalid range or if some ranges are intersected).
+ */
+ public static FixResult calculateFix(Text originalText, List<FixReplacement> fixReplacements)
+ throws ResourceConflictException {
+ List<FixReplacement> sortedReplacements = new ArrayList<>(fixReplacements);
+ sortedReplacements.sort(ASC_RANGE_FIX_REPLACEMENT_COMPARATOR);
+ if (!sortedReplacements.isEmpty() && sortedReplacements.get(0).range.startLine <= 0) {
+ throw new ResourceConflictException(
+ String.format(
+ "Cannot calculate fix replacement for range %s",
+ toString(sortedReplacements.get(0).range)));
+ }
+ ContentBuilder builder = new ContentBuilder(originalText);
+ for (FixReplacement fixReplacement : sortedReplacements) {
+ try {
+ builder.addReplacement(fixReplacement);
+ } catch (IndexOutOfBoundsException e) {
+ throw new ResourceConflictException(
+ String.format(
+ "Cannot calculate fix replacement for range %s", toString(fixReplacement.range)),
+ e);
+ }
+ }
+ return builder.build();
+ }
+
+ private static String toString(Comment.Range range) {
+ return String.format(
+ "(%s:%s - %s:%s)", range.startLine, range.startChar, range.endLine, range.endChar);
+ }
+
+ private static class ContentBuilder {
+ private static class FixRegion {
+ int startSrcLine;
+ int startDstLine;
+ int startSrcPos;
+ int startDstPos;
+ List<Edit> internalEdits;
+
+ FixRegion() {
+ this.internalEdits = new ArrayList<>();
+ }
+ }
+
+ private final ContentProcessor contentProcessor;
+ final ImmutableList.Builder<Edit> edits;
+ FixRegion currentRegion;
+
+ ContentBuilder(Text src) {
+ this.contentProcessor = new ContentProcessor(src);
+ this.edits = new ImmutableList.Builder<>();
+ }
+
+ void addReplacement(FixReplacement replacement) {
+ if (shouldStartNewEdit(replacement)) {
+ finishExistingEdit();
+ }
+ // processSrcContent expects that line number is 0-based,
+ // but replacement.range.startLine is 1-based, so subtract 1
+ processSrcContent(replacement.range.startLine - 1, replacement.range.startChar, true);
+ processReplacement(replacement);
+ }
+
+ Text getNewText() {
+ return new Text(contentProcessor.sb.toString().getBytes(UTF_8));
+ }
+
+ void finish() {
+ finishExistingEdit();
+ if (contentProcessor.hasMoreLines()) {
+ contentProcessor.appendLinesToEndOfContent();
+ }
+ }
+
+ public FixResult build() {
+ finish();
+ return new FixResult(edits.build(), this.getNewText());
+ }
+
+ private void finishExistingEdit() {
+ if (contentProcessor.srcPosition.column > 0 || contentProcessor.dstPosition.column > 0) {
+ contentProcessor.processToEndOfLine(true);
+ }
+ if (currentRegion != null) {
+ int endSrc = contentProcessor.srcPosition.line;
+ if (contentProcessor.srcPosition.column > 0) {
+ endSrc++;
+ }
+ int endDst = contentProcessor.dstPosition.line;
+ if (contentProcessor.dstPosition.column > 0) {
+ endDst++;
+ }
+ ReplaceEdit edit =
+ new ReplaceEdit(
+ currentRegion.startSrcLine,
+ endSrc,
+ currentRegion.startDstLine,
+ endDst,
+ currentRegion.internalEdits);
+ currentRegion = null;
+ edits.add(edit);
+ }
+ }
+
+ private boolean shouldStartNewEdit(FixReplacement replacement) {
+ if (currentRegion == null) {
+ return true;
+ }
+ // New edit must be started if there is at least one unchanged line after the last edit
+ // Subtract 1 from replacement.range.startLine because it is a 1-based line number,
+ // and contentProcessor.srcPosition.line is a 0-based line number
+ return replacement.range.startLine - 1 > contentProcessor.srcPosition.line + 1;
+ }
+
+ private void processSrcContent(int toLine, int toColumn, boolean append)
+ throws IndexOutOfBoundsException {
+ // toLine >= currentSrcLineIndex
+ if (toLine == contentProcessor.srcPosition.line) {
+ contentProcessor.processLineToColumn(toColumn, append);
+ } else {
+ contentProcessor.processToEndOfLine(append);
+ contentProcessor.processMultiline(toLine, append);
+ contentProcessor.processLineToColumn(toColumn, append);
+ }
+ }
+
+ private void processReplacement(FixReplacement fix) {
+ if (currentRegion == null) {
+ currentRegion = new FixRegion();
+ currentRegion.startSrcLine = contentProcessor.srcPosition.line;
+ currentRegion.startSrcPos = contentProcessor.srcPosition.getLineStartPos();
+ currentRegion.startDstLine = contentProcessor.dstPosition.line;
+ currentRegion.startDstPos = contentProcessor.dstPosition.getLineStartPos();
+ }
+ int srcStartPos = contentProcessor.srcPosition.textPos;
+ int dstStartPos = contentProcessor.dstPosition.textPos;
+ contentProcessor.appendReplacement(fix.replacement);
+ processSrcContent(fix.range.endLine - 1, fix.range.endChar, false);
+
+ currentRegion.internalEdits.add(
+ new Edit(
+ srcStartPos - currentRegion.startSrcPos,
+ contentProcessor.srcPosition.textPos - currentRegion.startSrcPos,
+ dstStartPos - currentRegion.startDstPos,
+ contentProcessor.dstPosition.textPos - currentRegion.startDstPos));
+ }
+ }
+
+ private static class ContentProcessor {
+ static class ContentPosition {
+ int line;
+ int column;
+ int textPos;
+
+ void appendMultilineContent(int lineCount, int charCount) {
+ line += lineCount;
+ column = 0;
+ textPos += charCount;
+ }
+
+ void appendLineEndedWithEOLMark(int charCount) {
+ textPos += charCount;
+ line++;
+ column = 0;
+ }
+
+ void appendStringWithoutEOLMark(int charCount) {
+ textPos += charCount;
+ column += charCount;
+ }
+
+ int getLineStartPos() {
+ return textPos - column;
+ }
+ }
+
+ private final StringBuilder sb;
+ final ContentPosition srcPosition;
+ final ContentPosition dstPosition;
+ String currentSrcLine;
+ Text src;
+ boolean endOfSource;
+
+ ContentProcessor(Text src) {
+ this.src = src;
+ sb = new StringBuilder(src.size());
+ srcPosition = new ContentPosition();
+ dstPosition = new ContentPosition();
+ endOfSource = src.size() == 0;
+ }
+
+ void processMultiline(int toLine, boolean append) {
+ if (endOfSource || toLine <= srcPosition.line) {
+ return;
+ }
+ int fromLine = srcPosition.line;
+ String lines = src.getString(fromLine, toLine, false);
+ int lineCount = toLine - fromLine;
+ int charCount = lines.length();
+ srcPosition.appendMultilineContent(lineCount, charCount);
+
+ if (append) {
+ sb.append(lines);
+ dstPosition.appendMultilineContent(lineCount, charCount);
+ }
+ currentSrcLine = null;
+ endOfSource = srcPosition.line >= src.size();
+ }
+
+ void processToEndOfLine(boolean append) {
+ if (endOfSource) {
+ return;
+ }
+ String srcLine = getCurrentSrcLine();
+ int from = srcPosition.column;
+ int charCount = srcLine.length() - from;
+ boolean lastLineNoEOLMark = srcPosition.line >= src.size() - 1 && src.isMissingNewlineAtEnd();
+ if (!lastLineNoEOLMark) {
+ srcPosition.appendLineEndedWithEOLMark(charCount);
+ endOfSource = srcPosition.line >= src.size();
+ } else {
+ srcPosition.appendStringWithoutEOLMark(charCount);
+ endOfSource = true;
+ }
+ if (append) {
+ sb.append(srcLine, from, srcLine.length());
+ if (!lastLineNoEOLMark) {
+ dstPosition.appendLineEndedWithEOLMark(charCount);
+ } else {
+ dstPosition.appendStringWithoutEOLMark(charCount);
+ }
+ }
+ currentSrcLine = null;
+ }
+
+ void processLineToColumn(int to, boolean append) throws IndexOutOfBoundsException {
+ if (to == 0) {
+ return;
+ }
+ String srcLine = getCurrentSrcLine();
+ if (to > srcLine.length()) {
+ throw new IndexOutOfBoundsException("Parameter to is out of string");
+ } else if (to == srcLine.length()) {
+ if (srcPosition.line < src.size() - 1 || !src.isMissingNewlineAtEnd()) {
+ throw new IndexOutOfBoundsException("The processLineToColumn shouldn't add end of line");
+ }
+ }
+ int from = srcPosition.column;
+ int charCount = to - from;
+ srcPosition.appendStringWithoutEOLMark(charCount);
+ if (append) {
+ sb.append(srcLine, from, to);
+ dstPosition.appendStringWithoutEOLMark(charCount);
+ }
+ }
+
+ void appendLinesToEndOfContent() {
+ processMultiline(src.size(), true);
+ }
+
+ void appendReplacement(String replacement) {
+ if (replacement.length() == 0) {
+ return;
+ }
+ sb.append(replacement);
+ int lastNewLinePos = -1;
+ int newLineMarkCount = 0;
+ while (true) {
+ int index = replacement.indexOf('\n', lastNewLinePos + 1);
+ if (index < 0) {
+ break;
+ }
+ lastNewLinePos = index;
+ newLineMarkCount++;
+ }
+ if (newLineMarkCount > 0) {
+ dstPosition.appendMultilineContent(newLineMarkCount, lastNewLinePos + 1);
+ }
+ dstPosition.appendStringWithoutEOLMark(replacement.length() - lastNewLinePos - 1);
+ }
+
+ boolean hasMoreLines() {
+ return !endOfSource;
+ }
+
+ private String getCurrentSrcLine() {
+ if (currentSrcLine == null) {
+ currentSrcLine = src.getString(srcPosition.line, srcPosition.line + 1, false);
+ }
+ return currentSrcLine;
+ }
+ }
+
+ /** The result of applying fix to a file content */
+ public static class FixResult {
+ /** List of edits to transform an original text to a final text (with all fixes applied) */
+ public final ImmutableList<Edit> edits;
+ /** Final text with all applied fixes */
+ public final Text text;
+
+ FixResult(ImmutableList<Edit> edits, Text text) {
+ this.edits = edits;
+ this.text = text;
+ }
+ }
+}
diff --git a/java/com/google/gerrit/server/fixes/FixReplacementInterpreter.java b/java/com/google/gerrit/server/fixes/FixReplacementInterpreter.java
index 9d6df7d..32c2450 100644
--- a/java/com/google/gerrit/server/fixes/FixReplacementInterpreter.java
+++ b/java/com/google/gerrit/server/fixes/FixReplacementInterpreter.java
@@ -18,7 +18,6 @@
import static java.util.stream.Collectors.groupingBy;
import com.google.gerrit.common.RawInputUtil;
-import com.google.gerrit.entities.Comment;
import com.google.gerrit.entities.FixReplacement;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.BinaryResult;
@@ -96,7 +95,8 @@
throws BadRequestException, ResourceNotFoundException, IOException,
ResourceConflictException {
String fileContent = getFileContent(repository, projectState, patchSetCommitId, filePath);
- String newFileContent = getNewFileContent(fileContent, fixReplacements);
+ String newFileContent = FixCalculator.getNewFileContent(fileContent, fixReplacements);
+
return new ChangeFileContentModification(filePath, RawInputUtil.create(newFileContent));
}
@@ -108,48 +108,4 @@
return fileContent.asString();
}
}
-
- private static String getNewFileContent(String fileContent, List<FixReplacement> fixReplacements)
- throws ResourceConflictException {
- List<FixReplacement> sortedReplacements = new ArrayList<>(fixReplacements);
- sortedReplacements.sort(ASC_RANGE_FIX_REPLACEMENT_COMPARATOR);
-
- LineIdentifier lineIdentifier = new LineIdentifier(fileContent);
- StringModifier fileContentModifier = new StringModifier(fileContent);
- for (FixReplacement fixReplacement : sortedReplacements) {
- Comment.Range range = fixReplacement.range;
- try {
- int startLineIndex = lineIdentifier.getStartIndexOfLine(range.startLine);
- int startLineLength = lineIdentifier.getLengthOfLine(range.startLine);
-
- int endLineIndex = lineIdentifier.getStartIndexOfLine(range.endLine);
- int endLineLength = lineIdentifier.getLengthOfLine(range.endLine);
-
- if (range.startChar > startLineLength || range.endChar > endLineLength) {
- throw new ResourceConflictException(
- String.format(
- "Range %s refers to a non-existent offset (start line length: %s,"
- + " end line length: %s)",
- toString(range), startLineLength, endLineLength));
- }
-
- int startIndex = startLineIndex + range.startChar;
- int endIndex = endLineIndex + range.endChar;
- fileContentModifier.replace(startIndex, endIndex, fixReplacement.replacement);
- } catch (StringIndexOutOfBoundsException e) {
- // Most of the StringIndexOutOfBoundsException should never occur because we reject fix
- // replacements for invalid ranges. However, we can't cover all cases for efficiency
- // reasons. For instance, we don't determine the number of lines in a file. That's why we
- // need to map this exception and thus provide a meaningful error.
- throw new ResourceConflictException(
- String.format("Cannot apply fix replacement for range %s", toString(range)), e);
- }
- }
- return fileContentModifier.getResult();
- }
-
- private static String toString(Comment.Range range) {
- return String.format(
- "(%s:%s - %s:%s)", range.startLine, range.startChar, range.endLine, range.endChar);
- }
}
diff --git a/java/com/google/gerrit/server/fixes/LineIdentifier.java b/java/com/google/gerrit/server/fixes/LineIdentifier.java
deleted file mode 100644
index 3d09c34..0000000
--- a/java/com/google/gerrit/server/fixes/LineIdentifier.java
+++ /dev/null
@@ -1,110 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.server.fixes;
-
-import static java.util.Objects.requireNonNull;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * An identifier of lines in a string. Lines are sequences of characters which are separated by any
- * Unicode linebreak sequence as defined by the regular expression {@code \R}. If data for several
- * lines is requested, calls which are ordered according to ascending line numbers are the most
- * efficient.
- */
-class LineIdentifier {
-
- private static final Pattern LINE_SEPARATOR_PATTERN = Pattern.compile("\\R");
- private final Matcher lineSeparatorMatcher;
-
- private int nextLineNumber;
- private int nextLineStartIndex;
- private int currentLineStartIndex;
- private int currentLineEndIndex;
-
- LineIdentifier(String string) {
- requireNonNull(string);
- lineSeparatorMatcher = LINE_SEPARATOR_PATTERN.matcher(string);
- reset();
- }
-
- /**
- * Returns the start index of the indicated line within the given string. Start indices are
- * zero-based while line numbers are one-based.
- *
- * <p><b>Note:</b> Requesting data for several lines is more efficient if those calls occur with
- * increasing line number.
- *
- * @param lineNumber the line whose start index should be determined
- * @return the start index of the line
- * @throws StringIndexOutOfBoundsException if the line number is negative, zero or greater than
- * the identified number of lines
- */
- public int getStartIndexOfLine(int lineNumber) {
- findLine(lineNumber);
- return currentLineStartIndex;
- }
-
- /**
- * Returns the length of the indicated line in the given string. The character(s) used to separate
- * lines aren't included in the count. Line numbers are one-based.
- *
- * <p><b>Note:</b> Requesting data for several lines is more efficient if those calls occur with
- * increasing line number.
- *
- * @param lineNumber the line whose length should be determined
- * @return the length of the line
- * @throws StringIndexOutOfBoundsException if the line number is negative, zero or greater than
- * the identified number of lines
- */
- public int getLengthOfLine(int lineNumber) {
- findLine(lineNumber);
- return currentLineEndIndex - currentLineStartIndex;
- }
-
- private void findLine(int targetLineNumber) {
- if (targetLineNumber <= 0) {
- throw new StringIndexOutOfBoundsException("Line number must be positive");
- }
- if (targetLineNumber < nextLineNumber) {
- reset();
- }
- while (nextLineNumber < targetLineNumber + 1 && lineSeparatorMatcher.find()) {
- currentLineStartIndex = nextLineStartIndex;
- currentLineEndIndex = lineSeparatorMatcher.start();
- nextLineStartIndex = lineSeparatorMatcher.end();
- nextLineNumber++;
- }
-
- // End of string
- if (nextLineNumber == targetLineNumber) {
- currentLineStartIndex = nextLineStartIndex;
- currentLineEndIndex = lineSeparatorMatcher.regionEnd();
- }
- if (nextLineNumber < targetLineNumber) {
- throw new StringIndexOutOfBoundsException(
- String.format("Line %d isn't available", targetLineNumber));
- }
- }
-
- private void reset() {
- nextLineNumber = 1;
- nextLineStartIndex = 0;
- currentLineStartIndex = 0;
- currentLineEndIndex = 0;
- lineSeparatorMatcher.reset();
- }
-}
diff --git a/java/com/google/gerrit/server/fixes/testing/BUILD b/java/com/google/gerrit/server/fixes/testing/BUILD
new file mode 100644
index 0000000..cccf7a5
--- /dev/null
+++ b/java/com/google/gerrit/server/fixes/testing/BUILD
@@ -0,0 +1,19 @@
+load("@rules_java//java:defs.bzl", "java_library")
+
+package(default_visibility = ["//visibility:public"])
+
+java_library(
+ name = "testing",
+ testonly = True,
+ srcs = glob(["*.java"]),
+ deps = [
+ "//java/com/google/gerrit/common:server",
+ "//java/com/google/gerrit/entities",
+ "//java/com/google/gerrit/jgit",
+ "//java/com/google/gerrit/server",
+ "//java/com/google/gerrit/truth",
+ "//lib:guava",
+ "//lib:jgit",
+ "//lib/truth",
+ ],
+)
diff --git a/java/com/google/gerrit/server/fixes/testing/FixResultSubject.java b/java/com/google/gerrit/server/fixes/testing/FixResultSubject.java
new file mode 100644
index 0000000..21f96cd
--- /dev/null
+++ b/java/com/google/gerrit/server/fixes/testing/FixResultSubject.java
@@ -0,0 +1,49 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.fixes.testing;
+
+import static com.google.common.truth.Truth.assertAbout;
+import static com.google.gerrit.server.fixes.testing.GitEditSubject.gitEdits;
+import static com.google.gerrit.truth.ListSubject.elements;
+
+import com.google.common.truth.FailureMetadata;
+import com.google.common.truth.StringSubject;
+import com.google.common.truth.Subject;
+import com.google.gerrit.server.fixes.FixCalculator.FixResult;
+import com.google.gerrit.truth.ListSubject;
+import org.eclipse.jgit.diff.Edit;
+
+public class FixResultSubject extends Subject {
+ public static FixResultSubject assertThat(FixResult fixResult) {
+ return assertAbout(FixResultSubject::new).that(fixResult);
+ }
+
+ private final FixResult fixResult;
+
+ private FixResultSubject(FailureMetadata failureMetadata, FixResult fixResult) {
+ super(failureMetadata, fixResult);
+ this.fixResult = fixResult;
+ }
+
+ public StringSubject text() {
+ isNotNull();
+ return check("text").that(fixResult.text.getString(0, fixResult.text.size(), false));
+ }
+
+ public ListSubject<GitEditSubject, Edit> edits() {
+ isNotNull();
+ return check("edits").about(elements()).thatCustom(fixResult.edits, gitEdits());
+ }
+}
diff --git a/java/com/google/gerrit/server/fixes/testing/GitEditSubject.java b/java/com/google/gerrit/server/fixes/testing/GitEditSubject.java
new file mode 100644
index 0000000..53b88b1
--- /dev/null
+++ b/java/com/google/gerrit/server/fixes/testing/GitEditSubject.java
@@ -0,0 +1,87 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.fixes.testing;
+
+import static com.google.common.truth.Truth.assertAbout;
+import static com.google.gerrit.truth.ListSubject.elements;
+
+import com.google.common.truth.FailureMetadata;
+import com.google.common.truth.Subject;
+import com.google.gerrit.jgit.diff.ReplaceEdit;
+import com.google.gerrit.truth.ListSubject;
+import org.eclipse.jgit.diff.Edit;
+import org.eclipse.jgit.diff.Edit.Type;
+
+public class GitEditSubject extends Subject {
+
+ public static GitEditSubject assertThat(Edit edit) {
+ return assertAbout(gitEdits()).that(edit);
+ }
+
+ public static Subject.Factory<GitEditSubject, Edit> gitEdits() {
+ return GitEditSubject::new;
+ }
+
+ private final Edit edit;
+
+ private GitEditSubject(FailureMetadata failureMetadata, Edit edit) {
+ super(failureMetadata, edit);
+ this.edit = edit;
+ }
+
+ public void hasRegions(int beginA, int endA, int beginB, int endB) {
+ isNotNull();
+ check("beginA").that(edit.getBeginA()).isEqualTo(beginA);
+ check("endA").that(edit.getEndA()).isEqualTo(endA);
+ check("beginB").that(edit.getBeginB()).isEqualTo(beginB);
+ check("endB").that(edit.getEndB()).isEqualTo(endB);
+ }
+
+ public void hasType(Type type) {
+ isNotNull();
+ check("getType").that(edit.getType()).isEqualTo(type);
+ }
+
+ public void isInsert(int insertPos, int beginB, int insertedLength) {
+ isNotNull();
+ hasType(Type.INSERT);
+ hasRegions(insertPos, insertPos, beginB, beginB + insertedLength);
+ }
+
+ public void isDelete(int deletePos, int deletedLength, int posB) {
+ isNotNull();
+ hasType(Type.DELETE);
+ hasRegions(deletePos, deletePos + deletedLength, posB, posB);
+ }
+
+ public void isReplace(int originalPos, int originalLength, int newPos, int newLength) {
+ isNotNull();
+ hasType(Type.REPLACE);
+ hasRegions(originalPos, originalPos + originalLength, newPos, newPos + newLength);
+ }
+
+ public void isEmpty() {
+ isNotNull();
+ hasType(Type.EMPTY);
+ }
+
+ public ListSubject<GitEditSubject, Edit> internalEdits() {
+ isNotNull();
+ isInstanceOf(ReplaceEdit.class);
+ return check("internalEdits")
+ .about(elements())
+ .thatCustom(((ReplaceEdit) edit).getInternalEdits(), gitEdits());
+ }
+}
diff --git a/java/com/google/gerrit/server/patch/PatchScriptBuilder.java b/java/com/google/gerrit/server/patch/PatchScriptBuilder.java
index b5842a9..92df794 100644
--- a/java/com/google/gerrit/server/patch/PatchScriptBuilder.java
+++ b/java/com/google/gerrit/server/patch/PatchScriptBuilder.java
@@ -22,9 +22,13 @@
import com.google.gerrit.common.data.PatchScript;
import com.google.gerrit.common.data.PatchScript.DisplayMethod;
import com.google.gerrit.entities.Change;
+import com.google.gerrit.entities.FixReplacement;
import com.google.gerrit.entities.Patch;
import com.google.gerrit.entities.Patch.ChangeType;
+import com.google.gerrit.entities.Patch.PatchType;
import com.google.gerrit.extensions.client.DiffPreferencesInfo;
+import com.google.gerrit.extensions.restapi.ResourceConflictException;
+import com.google.gerrit.server.fixes.FixCalculator;
import com.google.gerrit.server.mime.FileTypeRegistry;
import com.google.gerrit.server.patch.DiffContentCalculator.DiffCalculatorResult;
import com.google.gerrit.server.patch.DiffContentCalculator.TextSource;
@@ -32,6 +36,7 @@
import eu.medsea.mimeutil.MimeType;
import eu.medsea.mimeutil.MimeUtil2;
import java.io.IOException;
+import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
@@ -90,9 +95,7 @@
ResolvedSides sides =
resolveSides(
git, sidesResolver, oldName(change), newName(change), list.getOldId(), list.getNewId());
- PatchSide a = sides.a;
- PatchSide b = sides.b;
- return build(a, b, change, comments, history);
+ return build(sides.a, sides.b, change, comments, history);
}
private ResolvedSides resolveSides(
@@ -111,6 +114,45 @@
}
}
+ PatchScript toPatchScript(
+ Repository git, ObjectId baseId, String fileName, List<FixReplacement> fixReplacements)
+ throws IOException, ResourceConflictException {
+ SidesResolver sidesResolver = new SidesResolver(git, ComparisonType.againstOtherPatchSet());
+ PatchSide a = resolveSideA(git, sidesResolver, fileName, baseId);
+ FixCalculator.FixResult fixResult = FixCalculator.calculateFix(a.src, fixReplacements);
+ PatchSide b =
+ new PatchSide(
+ null,
+ fileName,
+ ObjectId.zeroId(),
+ a.mode,
+ fixResult.text.getContent(),
+ fixResult.text,
+ a.mimeType,
+ a.displayMethod,
+ a.fileMode);
+
+ PatchFileChange change =
+ new PatchFileChange(
+ fixResult.edits,
+ ImmutableSet.of(),
+ ImmutableList.of(),
+ fileName,
+ fileName,
+ ChangeType.MODIFIED,
+ PatchType.UNIFIED);
+
+ return build(a, b, change, null, null);
+ }
+
+ private PatchSide resolveSideA(
+ Repository git, SidesResolver sidesResolver, String path, ObjectId baseId)
+ throws IOException {
+ try (ObjectReader reader = git.newObjectReader()) {
+ return sidesResolver.resolve(registry, reader, path, null, baseId, true);
+ }
+ }
+
private PatchScript build(
PatchSide a,
PatchSide b,
diff --git a/java/com/google/gerrit/server/patch/PatchScriptFactoryForAutoFix.java b/java/com/google/gerrit/server/patch/PatchScriptFactoryForAutoFix.java
new file mode 100644
index 0000000..cf07190
--- /dev/null
+++ b/java/com/google/gerrit/server/patch/PatchScriptFactoryForAutoFix.java
@@ -0,0 +1,134 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.patch;
+
+import static com.google.common.base.Preconditions.checkState;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.flogger.FluentLogger;
+import com.google.gerrit.common.data.PatchScript;
+import com.google.gerrit.entities.Change;
+import com.google.gerrit.entities.FixReplacement;
+import com.google.gerrit.entities.PatchSet;
+import com.google.gerrit.extensions.client.DiffPreferencesInfo;
+import com.google.gerrit.extensions.restapi.AuthException;
+import com.google.gerrit.extensions.restapi.ResourceConflictException;
+import com.google.gerrit.server.git.LargeObjectException;
+import com.google.gerrit.server.notedb.ChangeNotes;
+import com.google.gerrit.server.permissions.ChangePermission;
+import com.google.gerrit.server.permissions.PermissionBackend;
+import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.gerrit.server.project.InvalidChangeOperationException;
+import com.google.gerrit.server.project.NoSuchChangeException;
+import com.google.gerrit.server.project.ProjectCache;
+import com.google.inject.Provider;
+import com.google.inject.assistedinject.Assisted;
+import com.google.inject.assistedinject.AssistedInject;
+import java.io.IOException;
+import java.util.concurrent.Callable;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Repository;
+
+public class PatchScriptFactoryForAutoFix implements Callable<PatchScript> {
+
+ private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+
+ public interface Factory {
+
+ PatchScriptFactoryForAutoFix create(
+ Repository git,
+ ChangeNotes notes,
+ String fileName,
+ PatchSet patchSet,
+ ImmutableList<FixReplacement> fixReplacements,
+ DiffPreferencesInfo diffPrefs);
+ }
+
+ private final PermissionBackend permissionBackend;
+ private final ProjectCache projectCache;
+ private final Change.Id changeId;
+ private final ChangeNotes notes;
+ private final Provider<PatchScriptBuilder> builderFactory;
+ private final Repository git;
+ private final PatchSet patchSet;
+ private final String fileName;
+ private final DiffPreferencesInfo diffPrefs;
+ private final ImmutableList<FixReplacement> fixReplacements;
+
+ @AssistedInject
+ PatchScriptFactoryForAutoFix(
+ Provider<PatchScriptBuilder> builderFactory,
+ PermissionBackend permissionBackend,
+ ProjectCache projectCache,
+ @Assisted Repository git,
+ @Assisted ChangeNotes notes,
+ @Assisted String fileName,
+ @Assisted PatchSet patchSet,
+ @Assisted ImmutableList<FixReplacement> fixReplacements,
+ @Assisted DiffPreferencesInfo diffPrefs) {
+ this.notes = notes;
+ this.permissionBackend = permissionBackend;
+ this.projectCache = projectCache;
+ this.changeId = patchSet.id().changeId();
+ this.git = git;
+ this.patchSet = patchSet;
+ this.fileName = fileName;
+ this.fixReplacements = fixReplacements;
+ this.builderFactory = builderFactory;
+ this.diffPrefs = diffPrefs;
+ }
+
+ @Override
+ public PatchScript call()
+ throws LargeObjectException, AuthException, InvalidChangeOperationException, IOException,
+ PermissionBackendException {
+
+ try {
+ permissionBackend.currentUser().change(notes).check(ChangePermission.READ);
+ } catch (AuthException e) {
+ throw new NoSuchChangeException(changeId);
+ }
+
+ if (!projectCache.checkedGet(notes.getProjectName()).statePermitsRead()) {
+ throw new NoSuchChangeException(changeId);
+ }
+
+ return createPatchScript();
+ }
+
+ private PatchScript createPatchScript() throws LargeObjectException {
+ checkState(patchSet.id().get() != 0, "edit not supported for left side");
+ PatchScriptBuilder b = newBuilder();
+ try {
+ ObjectId baseId = patchSet.commitId();
+ return b.toPatchScript(git, baseId, fileName, fixReplacements);
+ } catch (ResourceConflictException e) {
+ logger.atSevere().withCause(e).log("AutoFix replacements is not valid");
+ throw new IllegalStateException("AutoFix replacements is not valid", e);
+ } catch (IOException e) {
+ logger.atSevere().withCause(e).log("File content unavailable");
+ throw new NoSuchChangeException(notes.getChangeId(), e);
+ } catch (org.eclipse.jgit.errors.LargeObjectException err) {
+ throw new LargeObjectException("File content is too large", err);
+ }
+ }
+
+ private PatchScriptBuilder newBuilder() {
+ PatchScriptBuilder b = builderFactory.get();
+ b.setChange(notes.getChange());
+ b.setDiffPrefs(diffPrefs);
+ return b;
+ }
+}
diff --git a/java/com/google/gerrit/server/restapi/change/GetFixPreview.java b/java/com/google/gerrit/server/restapi/change/GetFixPreview.java
index db89819..0666756 100644
--- a/java/com/google/gerrit/server/restapi/change/GetFixPreview.java
+++ b/java/com/google/gerrit/server/restapi/change/GetFixPreview.java
@@ -14,20 +14,129 @@
package com.google.gerrit.server.restapi.change;
+import static java.util.stream.Collectors.groupingBy;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.collect.ImmutableList;
+import com.google.gerrit.common.data.PatchScript;
+import com.google.gerrit.entities.Change;
+import com.google.gerrit.entities.FixReplacement;
+import com.google.gerrit.entities.PatchSet;
+import com.google.gerrit.extensions.client.DiffPreferencesInfo;
import com.google.gerrit.extensions.common.DiffInfo;
+import com.google.gerrit.extensions.common.DiffWebLinkInfo;
+import com.google.gerrit.extensions.common.WebLinkInfo;
+import com.google.gerrit.extensions.restapi.AuthException;
+import com.google.gerrit.extensions.restapi.ResourceConflictException;
+import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestReadView;
import com.google.gerrit.server.change.FixResource;
+import com.google.gerrit.server.diff.DiffInfoCreator;
+import com.google.gerrit.server.diff.DiffSide;
+import com.google.gerrit.server.diff.DiffSide.Type;
+import com.google.gerrit.server.diff.DiffWebLinksProvider;
+import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.git.LargeObjectException;
+import com.google.gerrit.server.notedb.ChangeNotes;
+import com.google.gerrit.server.patch.PatchScriptFactoryForAutoFix;
+import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.gerrit.server.project.InvalidChangeOperationException;
+import com.google.gerrit.server.project.NoSuchChangeException;
+import com.google.gerrit.server.project.ProjectCache;
+import com.google.gerrit.server.project.ProjectState;
+import com.google.inject.Inject;
import com.google.inject.Singleton;
+import java.io.IOException;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
+import org.eclipse.jgit.lib.Repository;
@Singleton
public class GetFixPreview implements RestReadView<FixResource> {
+ private final ProjectCache projectCache;
+ private final GitRepositoryManager repoManager;
+ private final PatchScriptFactoryForAutoFix.Factory patchScriptFactoryFactory;
+
+ @Inject
+ GetFixPreview(
+ ProjectCache projectCache,
+ GitRepositoryManager repoManager,
+ PatchScriptFactoryForAutoFix.Factory patchScriptFactoryFactory) {
+ this.projectCache = projectCache;
+ this.repoManager = repoManager;
+ this.patchScriptFactoryFactory = patchScriptFactoryFactory;
+ }
+
@Override
- public Response<Map<String, DiffInfo>> apply(FixResource resource) {
+ public Response<Map<String, DiffInfo>> apply(FixResource resource)
+ throws PermissionBackendException, ResourceNotFoundException, ResourceConflictException,
+ AuthException, IOException, InvalidChangeOperationException {
Map<String, DiffInfo> result = new HashMap<>();
+ PatchSet patchSet = resource.getRevisionResource().getPatchSet();
+ ChangeNotes notes = resource.getRevisionResource().getNotes();
+ Change change = notes.getChange();
+ ProjectState state = projectCache.get(change.getProject());
+ Map<String, List<FixReplacement>> fixReplacementsPerFilePath =
+ resource.getFixReplacements().stream()
+ .collect(groupingBy(fixReplacement -> fixReplacement.path));
+ try {
+ try (Repository git = repoManager.openRepository(notes.getProjectName())) {
+ for (Map.Entry<String, List<FixReplacement>> entry :
+ fixReplacementsPerFilePath.entrySet()) {
+ String fileName = entry.getKey();
+ DiffInfo diffInfo =
+ getFixPreviewForSingleFile(
+ git, patchSet, state, notes, fileName, ImmutableList.copyOf(entry.getValue()));
+ result.put(fileName, diffInfo);
+ }
+ }
+ } catch (NoSuchChangeException e) {
+ throw new ResourceNotFoundException(e.getMessage(), e);
+ } catch (LargeObjectException e) {
+ throw new ResourceConflictException(e.getMessage(), e);
+ }
return Response.ok(result);
}
+
+ private DiffInfo getFixPreviewForSingleFile(
+ Repository git,
+ PatchSet patchSet,
+ ProjectState state,
+ ChangeNotes notes,
+ String fileName,
+ ImmutableList<FixReplacement> fixReplacements)
+ throws PermissionBackendException, AuthException, LargeObjectException,
+ InvalidChangeOperationException, IOException {
+ PatchScriptFactoryForAutoFix psf =
+ patchScriptFactoryFactory.create(
+ git, notes, fileName, patchSet, fixReplacements, DiffPreferencesInfo.defaults());
+ PatchScript ps = psf.call();
+
+ DiffSide sideA =
+ DiffSide.create(
+ ps.getFileInfoA(),
+ MoreObjects.firstNonNull(ps.getOldName(), ps.getNewName()),
+ Type.SIDE_A);
+ DiffSide sideB = DiffSide.create(ps.getFileInfoB(), ps.getNewName(), DiffSide.Type.SIDE_B);
+
+ DiffInfoCreator diffInfoCreator =
+ new DiffInfoCreator(state, new DiffWebLinksProviderImpl(), true);
+ return diffInfoCreator.create(ps, sideA, sideB);
+ }
+
+ private static class DiffWebLinksProviderImpl implements DiffWebLinksProvider {
+
+ @Override
+ public ImmutableList<DiffWebLinkInfo> getDiffLinks() {
+ return ImmutableList.of();
+ }
+
+ @Override
+ public ImmutableList<WebLinkInfo> getFileWebLinks(Type fileInfoType) {
+ return ImmutableList.of();
+ }
+ }
}
diff --git a/javatests/com/google/gerrit/acceptance/api/revision/RobotCommentsIT.java b/javatests/com/google/gerrit/acceptance/api/revision/RobotCommentsIT.java
index db1e99b7..abf0279 100644
--- a/javatests/com/google/gerrit/acceptance/api/revision/RobotCommentsIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/revision/RobotCommentsIT.java
@@ -16,6 +16,7 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.gerrit.acceptance.PushOneCommit.SUBJECT;
+import static com.google.gerrit.extensions.common.testing.DiffInfoSubject.assertThat;
import static com.google.gerrit.extensions.common.testing.EditInfoSubject.assertThat;
import static com.google.gerrit.extensions.common.testing.RobotCommentInfoSubject.assertThatList;
import static com.google.gerrit.testing.GerritJUnit.assertThrows;
@@ -31,7 +32,9 @@
import com.google.gerrit.extensions.api.changes.ReviewInput.RobotCommentInput;
import com.google.gerrit.extensions.client.Comment;
import com.google.gerrit.extensions.common.ChangeInfo;
+import com.google.gerrit.extensions.common.ChangeType;
import com.google.gerrit.extensions.common.DiffInfo;
+import com.google.gerrit.extensions.common.DiffInfo.IntraLineStatus;
import com.google.gerrit.extensions.common.EditInfo;
import com.google.gerrit.extensions.common.FixReplacementInfo;
import com.google.gerrit.extensions.common.FixSuggestionInfo;
@@ -50,9 +53,12 @@
import java.util.Objects;
import java.util.Optional;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
public class RobotCommentsIT extends AbstractDaemonTest {
+ private static final String PLAIN_TEXT_CONTENT_TYPE = "text/plain";
+
private static final String FILE_NAME = "file_to_fix.txt";
private static final String FILE_NAME2 = "another_file_to_fix.txt";
private static final String FILE_CONTENT =
@@ -61,6 +67,7 @@
private static final String FILE_CONTENT2 = "1st line\n2nd line\n3rd line\n";
private String changeId;
+ private String commitId;
private FixReplacementInfo fixReplacementInfo;
private FixSuggestionInfo fixSuggestionInfo;
private RobotCommentInput withFixRobotCommentInput;
@@ -75,6 +82,7 @@
ImmutableMap.of(FILE_NAME, FILE_CONTENT, FILE_NAME2, FILE_CONTENT2));
PushOneCommit.Result changeResult = push.to("refs/for/master");
changeId = changeResult.getChangeId();
+ commitId = changeResult.getCommit().getName();
fixReplacementInfo = createFixReplacementInfo();
fixSuggestionInfo = createFixSuggestionInfo(fixReplacementInfo);
@@ -971,15 +979,130 @@
}
@Test
+ @Ignore
+ public void getFixPreviewForNonExistingFile() throws Exception {
+ // Not implemented yet.
+ fixReplacementInfo.path = "a_non_existent_file.txt";
+ fixReplacementInfo.range = createRange(1, 0, 2, 0);
+ fixReplacementInfo.replacement = "Modified content\n";
+
+ addRobotComment(changeId, withFixRobotCommentInput);
+ List<RobotCommentInfo> robotCommentInfos = getRobotComments();
+ List<String> fixIds = getFixIds(robotCommentInfos);
+ String fixId = Iterables.getOnlyElement(fixIds);
+
+ assertThrows(
+ BadRequestException.class,
+ () -> gApi.changes().id(changeId).current().getFixPreview(fixId));
+ }
+
+ @Test
public void getFixPreview() throws Exception {
+ FixReplacementInfo fixReplacementInfoFile1 = new FixReplacementInfo();
+ fixReplacementInfoFile1.path = FILE_NAME;
+ fixReplacementInfoFile1.replacement = "some replacement code";
+ fixReplacementInfoFile1.range = createRange(3, 9, 8, 4);
+
+ FixReplacementInfo fixReplacementInfoFile2 = new FixReplacementInfo();
+ fixReplacementInfoFile2.path = FILE_NAME2;
+ fixReplacementInfoFile2.replacement = "New line\n";
+ fixReplacementInfoFile2.range = createRange(2, 0, 2, 0);
+
+ fixSuggestionInfo = createFixSuggestionInfo(fixReplacementInfoFile1, fixReplacementInfoFile2);
+
+ withFixRobotCommentInput = createRobotCommentInput(fixSuggestionInfo);
+
addRobotComment(changeId, withFixRobotCommentInput);
List<RobotCommentInfo> robotCommentInfos = getRobotComments();
List<String> fixIds = getFixIds(robotCommentInfos);
String fixId = Iterables.getOnlyElement(fixIds);
- Map<String, DiffInfo> result = gApi.changes().id(changeId).current().getFixPreview(fixId);
- assertThat(result).isEmpty();
+ Map<String, DiffInfo> fixPreview = gApi.changes().id(changeId).current().getFixPreview(fixId);
+ assertThat(fixPreview).hasSize(2);
+ assertThat(fixPreview).containsKey(FILE_NAME);
+ assertThat(fixPreview).containsKey(FILE_NAME2);
+
+ DiffInfo diff = fixPreview.get(FILE_NAME);
+ assertThat(diff).intralineStatus().isEqualTo(IntraLineStatus.OK);
+ assertThat(diff).webLinks().isNull();
+ assertThat(diff).binary().isNull();
+ assertThat(diff).diffHeader().isNull();
+ assertThat(diff).changeType().isEqualTo(ChangeType.MODIFIED);
+ assertThat(diff).metaA().totalLineCount().isEqualTo(11);
+ assertThat(diff).metaA().name().isEqualTo(FILE_NAME);
+ assertThat(diff).metaA().commitId().isEqualTo(commitId);
+ assertThat(diff).metaA().contentType().isEqualTo(PLAIN_TEXT_CONTENT_TYPE);
+ assertThat(diff).metaA().webLinks().isNull();
+ assertThat(diff).metaB().totalLineCount().isEqualTo(6);
+ assertThat(diff).metaB().name().isEqualTo(FILE_NAME);
+ assertThat(diff).metaB().commitId().isNull();
+ assertThat(diff).metaB().contentType().isEqualTo(PLAIN_TEXT_CONTENT_TYPE);
+ assertThat(diff).metaB().webLinks().isNull();
+
+ assertThat(diff).content().hasSize(3);
+ assertThat(diff)
+ .content()
+ .element(0)
+ .commonLines()
+ .containsExactly("First line", "Second line");
+ assertThat(diff).content().element(0).linesOfA().isNull();
+ assertThat(diff).content().element(0).linesOfB().isNull();
+
+ assertThat(diff).content().element(1).commonLines().isNull();
+ assertThat(diff)
+ .content()
+ .element(1)
+ .linesOfA()
+ .containsExactly(
+ "Third line", "Fourth line", "Fifth line", "Sixth line", "Seventh line", "Eighth line");
+ assertThat(diff)
+ .content()
+ .element(1)
+ .linesOfB()
+ .containsExactly("Third linsome replacement codeth line");
+
+ assertThat(diff)
+ .content()
+ .element(2)
+ .commonLines()
+ .containsExactly("Ninth line", "Tenth line", "");
+ assertThat(diff).content().element(2).linesOfA().isNull();
+ assertThat(diff).content().element(2).linesOfB().isNull();
+
+ DiffInfo diff2 = fixPreview.get(FILE_NAME2);
+ assertThat(diff2).intralineStatus().isEqualTo(IntraLineStatus.OK);
+ assertThat(diff2).webLinks().isNull();
+ assertThat(diff2).binary().isNull();
+ assertThat(diff2).diffHeader().isNull();
+ assertThat(diff2).changeType().isEqualTo(ChangeType.MODIFIED);
+ assertThat(diff2).metaA().totalLineCount().isEqualTo(4);
+ assertThat(diff2).metaA().name().isEqualTo(FILE_NAME2);
+ assertThat(diff2).metaA().commitId().isEqualTo(commitId);
+ assertThat(diff2).metaA().contentType().isEqualTo(PLAIN_TEXT_CONTENT_TYPE);
+ assertThat(diff2).metaA().webLinks().isNull();
+ assertThat(diff2).metaB().totalLineCount().isEqualTo(5);
+ assertThat(diff2).metaB().name().isEqualTo(FILE_NAME2);
+ assertThat(diff2).metaB().commitId().isNull();
+ assertThat(diff2).metaA().contentType().isEqualTo(PLAIN_TEXT_CONTENT_TYPE);
+ assertThat(diff2).metaB().webLinks().isNull();
+
+ assertThat(diff2).content().hasSize(3);
+ assertThat(diff2).content().element(0).commonLines().containsExactly("1st line");
+ assertThat(diff2).content().element(0).linesOfA().isNull();
+ assertThat(diff2).content().element(0).linesOfB().isNull();
+
+ assertThat(diff2).content().element(1).commonLines().isNull();
+ assertThat(diff2).content().element(1).linesOfA().isNull();
+ assertThat(diff2).content().element(1).linesOfB().containsExactly("New line");
+
+ assertThat(diff2)
+ .content()
+ .element(2)
+ .commonLines()
+ .containsExactly("2nd line", "3rd line", "");
+ assertThat(diff2).content().element(2).linesOfA().isNull();
+ assertThat(diff2).content().element(2).linesOfB().isNull();
}
private static RobotCommentInput createRobotCommentInputWithMandatoryFields() {
diff --git a/javatests/com/google/gerrit/server/BUILD b/javatests/com/google/gerrit/server/BUILD
index 59ed018..022813b 100644
--- a/javatests/com/google/gerrit/server/BUILD
+++ b/javatests/com/google/gerrit/server/BUILD
@@ -55,6 +55,7 @@
"//java/com/google/gerrit/server/account/externalids/testing",
"//java/com/google/gerrit/server/cache/serialize",
"//java/com/google/gerrit/server/cache/testing",
+ "//java/com/google/gerrit/server/fixes/testing",
"//java/com/google/gerrit/server/git/receive:ref_cache",
"//java/com/google/gerrit/server/ioutil",
"//java/com/google/gerrit/server/logging",
diff --git a/javatests/com/google/gerrit/server/fixes/LineIdentifierTest.java b/javatests/com/google/gerrit/server/fixes/LineIdentifierTest.java
deleted file mode 100644
index ba80c02..0000000
--- a/javatests/com/google/gerrit/server/fixes/LineIdentifierTest.java
+++ /dev/null
@@ -1,255 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.server.fixes;
-
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.gerrit.testing.GerritJUnit.assertThrows;
-
-import org.junit.Test;
-
-public class LineIdentifierTest {
- @Test
- public void lineNumberMustBePositive() {
- LineIdentifier lineIdentifier = new LineIdentifier("First line\nSecond line");
- StringIndexOutOfBoundsException thrown =
- assertThrows(
- StringIndexOutOfBoundsException.class, () -> lineIdentifier.getStartIndexOfLine(0));
- assertThat(thrown).hasMessageThat().contains("positive");
- }
-
- @Test
- public void lineNumberMustIndicateAnAvailableLine() {
- LineIdentifier lineIdentifier = new LineIdentifier("First line\nSecond line");
- StringIndexOutOfBoundsException thrown =
- assertThrows(
- StringIndexOutOfBoundsException.class, () -> lineIdentifier.getStartIndexOfLine(3));
- assertThat(thrown).hasMessageThat().contains("Line 3 isn't available");
- }
-
- @Test
- public void startIndexOfFirstLineIsRecognized() {
- LineIdentifier lineIdentifier = new LineIdentifier("12345678\n123\n1234567");
- int startIndex = lineIdentifier.getStartIndexOfLine(1);
- assertThat(startIndex).isEqualTo(0);
- }
-
- @Test
- public void lengthOfFirstLineIsCorrect() {
- LineIdentifier lineIdentifier = new LineIdentifier("12345678\n123\n1234567");
- int lineLength = lineIdentifier.getLengthOfLine(1);
- assertThat(lineLength).isEqualTo(8);
- }
-
- @Test
- public void startIndexOfSecondLineIsRecognized() {
- LineIdentifier lineIdentifier = new LineIdentifier("12345678\n123\n1234567");
- int startIndex = lineIdentifier.getStartIndexOfLine(2);
- assertThat(startIndex).isEqualTo(9);
- }
-
- @Test
- public void lengthOfSecondLineIsCorrect() {
- LineIdentifier lineIdentifier = new LineIdentifier("12345678\n123\n1234567");
- int lineLength = lineIdentifier.getLengthOfLine(2);
- assertThat(lineLength).isEqualTo(3);
- }
-
- @Test
- public void startIndexOfLastLineIsRecognized() {
- LineIdentifier lineIdentifier = new LineIdentifier("12345678\n123\n1234567");
- int startIndex = lineIdentifier.getStartIndexOfLine(3);
- assertThat(startIndex).isEqualTo(13);
- }
-
- @Test
- public void lengthOfLastLineIsCorrect() {
- LineIdentifier lineIdentifier = new LineIdentifier("12345678\n123\n1234567");
- int lineLength = lineIdentifier.getLengthOfLine(3);
- assertThat(lineLength).isEqualTo(7);
- }
-
- @Test
- public void emptyFirstLineIsRecognized() {
- LineIdentifier lineIdentifier = new LineIdentifier("\n123\n1234567");
- int startIndex = lineIdentifier.getStartIndexOfLine(1);
- assertThat(startIndex).isEqualTo(0);
- }
-
- @Test
- public void lengthOfEmptyFirstLineIsCorrect() {
- LineIdentifier lineIdentifier = new LineIdentifier("\n123\n1234567");
- int lineLength = lineIdentifier.getLengthOfLine(1);
- assertThat(lineLength).isEqualTo(0);
- }
-
- @Test
- public void emptyIntermediaryLineIsRecognized() {
- LineIdentifier lineIdentifier = new LineIdentifier("12345678\n\n1234567");
- int startIndex = lineIdentifier.getStartIndexOfLine(2);
- assertThat(startIndex).isEqualTo(9);
- }
-
- @Test
- public void lengthOfEmptyIntermediaryLineIsCorrect() {
- LineIdentifier lineIdentifier = new LineIdentifier("12345678\n\n1234567");
- int lineLength = lineIdentifier.getLengthOfLine(2);
- assertThat(lineLength).isEqualTo(0);
- }
-
- @Test
- public void lineAfterIntermediaryLineIsRecognized() {
- LineIdentifier lineIdentifier = new LineIdentifier("12345678\n\n1234567");
- int startIndex = lineIdentifier.getStartIndexOfLine(3);
- assertThat(startIndex).isEqualTo(10);
- }
-
- @Test
- public void emptyLastLineIsRecognized() {
- LineIdentifier lineIdentifier = new LineIdentifier("12345678\n123\n");
- int startIndex = lineIdentifier.getStartIndexOfLine(3);
- assertThat(startIndex).isEqualTo(13);
- }
-
- @Test
- public void lengthOfEmptyLastLineIsCorrect() {
- LineIdentifier lineIdentifier = new LineIdentifier("12345678\n123\n");
- int lineLength = lineIdentifier.getLengthOfLine(3);
- assertThat(lineLength).isEqualTo(0);
- }
-
- @Test
- public void startIndexOfSingleLineIsRecognized() {
- LineIdentifier lineIdentifier = new LineIdentifier("12345678");
- int startIndex = lineIdentifier.getStartIndexOfLine(1);
- assertThat(startIndex).isEqualTo(0);
- }
-
- @Test
- public void lengthOfSingleLineIsCorrect() {
- LineIdentifier lineIdentifier = new LineIdentifier("12345678");
- int lineLength = lineIdentifier.getLengthOfLine(1);
- assertThat(lineLength).isEqualTo(8);
- }
-
- @Test
- public void startIndexOfSingleEmptyLineIsRecognized() {
- LineIdentifier lineIdentifier = new LineIdentifier("");
- int startIndex = lineIdentifier.getStartIndexOfLine(1);
- assertThat(startIndex).isEqualTo(0);
- }
-
- @Test
- public void lengthOfSingleEmptyLineIsCorrect() {
- LineIdentifier lineIdentifier = new LineIdentifier("");
- int lineLength = lineIdentifier.getLengthOfLine(1);
- assertThat(lineLength).isEqualTo(0);
- }
-
- @Test
- public void lookingUpSubsequentLinesIsPossible() {
- LineIdentifier lineIdentifier = new LineIdentifier("12345678\n123\n1234567\n12");
-
- int firstLineStartIndex = lineIdentifier.getStartIndexOfLine(1);
- assertThat(firstLineStartIndex).isEqualTo(0);
-
- int secondLineStartIndex = lineIdentifier.getStartIndexOfLine(2);
- assertThat(secondLineStartIndex).isEqualTo(9);
- }
-
- @Test
- public void lookingUpNotSubsequentLinesInAscendingOrderIsPossible() {
- LineIdentifier lineIdentifier = new LineIdentifier("12345678\n123\n1234567\n12");
-
- int firstLineStartIndex = lineIdentifier.getStartIndexOfLine(1);
- assertThat(firstLineStartIndex).isEqualTo(0);
-
- int fourthLineStartIndex = lineIdentifier.getStartIndexOfLine(4);
- assertThat(fourthLineStartIndex).isEqualTo(21);
- }
-
- @Test
- public void lookingUpNotSubsequentLinesInDescendingOrderIsPossible() {
- LineIdentifier lineIdentifier = new LineIdentifier("12345678\n123\n1234567\n12");
-
- int fourthLineStartIndex = lineIdentifier.getStartIndexOfLine(4);
- assertThat(fourthLineStartIndex).isEqualTo(21);
-
- int secondLineStartIndex = lineIdentifier.getStartIndexOfLine(2);
- assertThat(secondLineStartIndex).isEqualTo(9);
- }
-
- @Test
- public void linesSeparatedByOnlyCarriageReturnAreRecognized() {
- LineIdentifier lineIdentifier = new LineIdentifier("12345678\r123\r12");
- int startIndex = lineIdentifier.getStartIndexOfLine(2);
- assertThat(startIndex).isEqualTo(9);
- }
-
- @Test
- public void lengthOfLinesSeparatedByOnlyCarriageReturnIsCorrect() {
- LineIdentifier lineIdentifier = new LineIdentifier("12345678\r123\r12");
- int lineLength = lineIdentifier.getLengthOfLine(2);
- assertThat(lineLength).isEqualTo(3);
- }
-
- @Test
- public void linesSeparatedByLineFeedAndCarriageReturnAreRecognized() {
- LineIdentifier lineIdentifier = new LineIdentifier("12345678\r\n123\r\n12");
- int startIndex = lineIdentifier.getStartIndexOfLine(2);
- assertThat(startIndex).isEqualTo(10);
- }
-
- @Test
- public void lengthOfLinesSeparatedByLineFeedAndCarriageReturnIsCorrect() {
- LineIdentifier lineIdentifier = new LineIdentifier("12345678\r\n123\r\n12");
- int lineLength = lineIdentifier.getLengthOfLine(2);
- assertThat(lineLength).isEqualTo(3);
- }
-
- @Test
- public void linesSeparatedByMixtureOfCarriageReturnAndLineFeedAreRecognized() {
- LineIdentifier lineIdentifier = new LineIdentifier("12345678\r123\r\n12\n123456\r\n1234");
- int startIndex = lineIdentifier.getStartIndexOfLine(5);
- assertThat(startIndex).isEqualTo(25);
- }
-
- @Test
- public void linesSeparatedBySomeUnicodeLinebreakCharacterAreRecognized() {
- LineIdentifier lineIdentifier = new LineIdentifier("12345678\u2029123\u202912");
- int startIndex = lineIdentifier.getStartIndexOfLine(2);
- assertThat(startIndex).isEqualTo(9);
- }
-
- @Test
- public void lengthOfLinesSeparatedBySomeUnicodeLinebreakCharacterIsCorrect() {
- LineIdentifier lineIdentifier = new LineIdentifier("12345678\u2029123\u202912");
- int lineLength = lineIdentifier.getLengthOfLine(2);
- assertThat(lineLength).isEqualTo(3);
- }
-
- @Test
- public void blanksAreNotInterpretedAsLineSeparators() {
- LineIdentifier lineIdentifier = new LineIdentifier("1 2345678\n123\n12");
- int startIndex = lineIdentifier.getStartIndexOfLine(2);
- assertThat(startIndex).isEqualTo(10);
- }
-
- @Test
- public void tabsAreNotInterpretedAsLineSeparators() {
- LineIdentifier lineIdentifier = new LineIdentifier("123\t45678\n123\n12");
- int startIndex = lineIdentifier.getStartIndexOfLine(2);
- assertThat(startIndex).isEqualTo(10);
- }
-}
diff --git a/javatests/com/google/gerrit/server/fixes/fixCalculator/EmptyContentTest.java b/javatests/com/google/gerrit/server/fixes/fixCalculator/EmptyContentTest.java
new file mode 100644
index 0000000..51fbc67
--- /dev/null
+++ b/javatests/com/google/gerrit/server/fixes/fixCalculator/EmptyContentTest.java
@@ -0,0 +1,68 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.fixes.fixCalculator;
+
+import static com.google.gerrit.server.fixes.testing.FixResultSubject.assertThat;
+import static com.google.gerrit.server.fixes.testing.GitEditSubject.assertThat;
+
+import com.google.gerrit.server.fixes.FixCalculator.FixResult;
+import org.eclipse.jgit.diff.Edit;
+import org.junit.Test;
+
+public class EmptyContentTest {
+ @Test
+ public void insertSingleLineNoEOL() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement("", 1, 0, 1, 0, "Abc");
+ assertThat(fixResult).text().isEqualTo("Abc");
+ assertThat(fixResult).edits().onlyElement();
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isInsert(0, 0, 1);
+ assertThat(edit).internalEdits().onlyElement().isInsert(0, 0, 3);
+ }
+
+ @Test
+ public void insertSingleLineWithEOL() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement("", 1, 0, 1, 0, "Abc\n");
+ assertThat(fixResult).text().isEqualTo("Abc\n");
+ assertThat(fixResult).edits().onlyElement();
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isInsert(0, 0, 1);
+ assertThat(edit).internalEdits().onlyElement().isInsert(0, 0, 4);
+ }
+
+ @Test
+ public void insertMultilineNoEOL() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement("", 1, 0, 1, 0, "Abc\nDEFGH");
+ assertThat(fixResult).text().isEqualTo("Abc\nDEFGH");
+ assertThat(fixResult).edits().onlyElement();
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isInsert(0, 0, 2);
+ assertThat(edit).internalEdits().onlyElement().isInsert(0, 0, 9);
+ }
+
+ @Test
+ public void insertMultilineWithEOL() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement("", 1, 0, 1, 0, "Abc\nDEFGH\n");
+ assertThat(fixResult).text().isEqualTo("Abc\nDEFGH\n");
+ assertThat(fixResult).edits().onlyElement();
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isInsert(0, 0, 2);
+ assertThat(edit).internalEdits().onlyElement().isInsert(0, 0, 10);
+ }
+}
diff --git a/javatests/com/google/gerrit/server/fixes/fixCalculator/FixCalculatorVariousTest.java b/javatests/com/google/gerrit/server/fixes/fixCalculator/FixCalculatorVariousTest.java
new file mode 100644
index 0000000..861af3e
--- /dev/null
+++ b/javatests/com/google/gerrit/server/fixes/fixCalculator/FixCalculatorVariousTest.java
@@ -0,0 +1,168 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.fixes.fixCalculator;
+
+import static com.google.gerrit.server.fixes.testing.FixResultSubject.assertThat;
+import static com.google.gerrit.server.fixes.testing.GitEditSubject.assertThat;
+import static com.google.gerrit.testing.GerritJUnit.assertThrows;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import com.google.common.collect.ImmutableList;
+import com.google.gerrit.entities.Comment.Range;
+import com.google.gerrit.entities.FixReplacement;
+import com.google.gerrit.extensions.restapi.ResourceConflictException;
+import com.google.gerrit.server.fixes.FixCalculator;
+import com.google.gerrit.server.fixes.FixCalculator.FixResult;
+import com.google.gerrit.server.patch.Text;
+import org.eclipse.jgit.diff.Edit;
+import org.junit.Test;
+
+public class FixCalculatorVariousTest {
+ private static final String multilineContentString =
+ "First line\nSecond line\nThird line\nFourth line\nFifth line\n";
+ private static final Text multilineContent = new Text(multilineContentString.getBytes(UTF_8));
+
+ public static FixResult calculateFixSingleReplacement(
+ String content, int startLine, int startChar, int endLine, int endChar, String replacement)
+ throws ResourceConflictException {
+ FixReplacement fixReplacement =
+ new FixReplacement(
+ "AnyPath", new Range(startLine, startChar, endLine, endChar), replacement);
+ return FixCalculator.calculateFix(
+ new Text(content.getBytes(UTF_8)), ImmutableList.of(fixReplacement));
+ }
+
+ @Test
+ public void lineNumberMustBePositive() {
+ assertThrows(
+ ResourceConflictException.class,
+ () -> calculateFixSingleReplacement("First line\nSecond line", 0, 0, 0, 0, "Abc"));
+ }
+
+ @Test
+ public void insertAtTheEndOfSingleLineContentHasEOLMarkInvalidPosition() throws Exception {
+ assertThrows(
+ ResourceConflictException.class,
+ () -> calculateFixSingleReplacement("First line\n", 1, 11, 1, 11, "Abc"));
+ }
+
+ @Test
+ public void severalChangesInTheSameLineNonSorted() throws Exception {
+ FixReplacement replace = new FixReplacement("path", new Range(2, 1, 2, 3), "ABC");
+ FixReplacement insert = new FixReplacement("path", new Range(2, 5, 2, 5), "DEFG");
+ FixReplacement delete = new FixReplacement("path", new Range(2, 7, 2, 9), "");
+ FixResult result =
+ FixCalculator.calculateFix(multilineContent, ImmutableList.of(replace, delete, insert));
+ assertThat(result)
+ .text()
+ .isEqualTo("First line\nSABConDEFGd ne\nThird line\nFourth line\nFifth line\n");
+ assertThat(result).edits().hasSize(1);
+ Edit edit = result.edits.get(0);
+ assertThat(edit).isReplace(1, 1, 1, 1);
+ assertThat(edit).internalEdits().hasSize(3);
+ assertThat(edit).internalEdits().element(0).isReplace(1, 2, 1, 3);
+ assertThat(edit).internalEdits().element(1).isInsert(5, 6, 4);
+ assertThat(edit).internalEdits().element(2).isDelete(7, 2, 12);
+ }
+
+ @Test
+ public void severalChangesInConsecutiveLines() throws Exception {
+ FixReplacement replace = new FixReplacement("path", new Range(2, 1, 2, 3), "ABC");
+ FixReplacement insert = new FixReplacement("path", new Range(3, 5, 3, 5), "DEFG");
+ FixReplacement delete = new FixReplacement("path", new Range(4, 7, 4, 9), "");
+ FixResult result =
+ FixCalculator.calculateFix(multilineContent, ImmutableList.of(replace, insert, delete));
+ assertThat(result)
+ .text()
+ .isEqualTo("First line\nSABCond line\nThirdDEFG line\nFourth ne\nFifth line\n");
+ assertThat(result).edits().hasSize(1);
+ Edit edit = result.edits.get(0);
+ assertThat(edit).isReplace(1, 3, 1, 3);
+ assertThat(edit).internalEdits().hasSize(3);
+ assertThat(edit).internalEdits().element(0).isReplace(1, 2, 1, 3);
+ assertThat(edit).internalEdits().element(1).isInsert(17, 18, 4);
+ assertThat(edit).internalEdits().element(2).isDelete(30, 2, 35);
+ }
+
+ @Test
+ public void severalChangesInNonConsecutiveLines() throws Exception {
+ FixReplacement replace = new FixReplacement("path", new Range(1, 1, 1, 3), "ABC");
+ FixReplacement insert = new FixReplacement("path", new Range(3, 5, 3, 5), "DEFG");
+ FixReplacement delete = new FixReplacement("path", new Range(5, 9, 6, 0), "");
+ FixResult result =
+ FixCalculator.calculateFix(multilineContent, ImmutableList.of(replace, insert, delete));
+ assertThat(result)
+ .text()
+ .isEqualTo("FABCst line\nSecond line\nThirdDEFG line\nFourth line\nFifth lin");
+ assertThat(result).edits().hasSize(3);
+ assertThat(result).edits().element(0).isReplace(0, 1, 0, 1);
+ assertThat(result).edits().element(0).internalEdits().onlyElement().isReplace(1, 2, 1, 3);
+ assertThat(result).edits().element(1).isReplace(2, 1, 2, 1);
+ assertThat(result).edits().element(1).internalEdits().onlyElement().isInsert(5, 5, 4);
+ assertThat(result).edits().element(2).isReplace(4, 1, 4, 1);
+ assertThat(result).edits().element(2).internalEdits().onlyElement().isDelete(9, 2, 9);
+ }
+
+ @Test
+ public void multipleChanges() throws Exception {
+ String str =
+ "First line\nSecond line\nThird line\nFourth line\nFifth line\nSixth line"
+ + "\nSeventh line\nEighth line\nNinth line\nTenth line\n";
+ Text content = new Text(str.getBytes(UTF_8));
+
+ FixReplacement multiLineReplace =
+ new FixReplacement("path", new Range(1, 2, 3, 3), "AB\nC\nDEFG\nQ\n");
+ FixReplacement multiLineDelete = new FixReplacement("path", new Range(4, 8, 5, 8), "");
+ FixReplacement singleLineInsert = new FixReplacement("path", new Range(5, 10, 5, 10), "QWERTY");
+
+ FixReplacement singleLineReplace = new FixReplacement("path", new Range(7, 3, 7, 7), "XY");
+ FixReplacement multiLineInsert =
+ new FixReplacement("path", new Range(8, 7, 8, 7), "KLMNO\nASDF");
+
+ FixReplacement singleLineDelete = new FixReplacement("path", new Range(10, 3, 10, 7), "");
+
+ FixResult result =
+ FixCalculator.calculateFix(
+ content,
+ ImmutableList.of(
+ multiLineReplace,
+ multiLineDelete,
+ singleLineInsert,
+ singleLineReplace,
+ multiLineInsert,
+ singleLineDelete));
+ assertThat(result)
+ .text()
+ .isEqualTo(
+ "FiAB\nC\nDEFG\nQ\nrd line\nFourth lneQWERTY\nSixth line\nSevXY line\nEighth KLMNO\nASDFline\nNinth line\nTenine\n");
+ assertThat(result).edits().hasSize(3);
+ assertThat(result).edits().element(0).isReplace(0, 5, 0, 6);
+ assertThat(result)
+ .edits()
+ .element(0)
+ .internalEdits()
+ .containsExactly(
+ new Edit(2, 26, 2, 14), new Edit(42, 54, 30, 30), new Edit(56, 56, 32, 38));
+
+ assertThat(result).edits().element(1).isReplace(6, 2, 7, 3);
+ assertThat(result)
+ .edits()
+ .element(1)
+ .internalEdits()
+ .containsExactly(new Edit(3, 7, 3, 5), new Edit(20, 20, 18, 28));
+ assertThat(result).edits().element(2).isReplace(9, 1, 11, 1);
+ assertThat(result).edits().element(2).internalEdits().onlyElement().isDelete(3, 4, 3);
+ }
+}
diff --git a/javatests/com/google/gerrit/server/fixes/fixCalculator/MultilineContentNoEOLTest.java b/javatests/com/google/gerrit/server/fixes/fixCalculator/MultilineContentNoEOLTest.java
new file mode 100644
index 0000000..dd36e3a
--- /dev/null
+++ b/javatests/com/google/gerrit/server/fixes/fixCalculator/MultilineContentNoEOLTest.java
@@ -0,0 +1,337 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.fixes.fixCalculator;
+
+import static com.google.gerrit.server.fixes.testing.FixResultSubject.assertThat;
+import static com.google.gerrit.server.fixes.testing.GitEditSubject.assertThat;
+
+import com.google.gerrit.server.fixes.FixCalculator.FixResult;
+import org.eclipse.jgit.diff.Edit;
+import org.junit.Test;
+
+public class MultilineContentNoEOLTest {
+
+ @Test
+ public void insertSingleLineNoEOLAtStart() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line", 1, 0, 1, 0, "Abc");
+ assertThat(fixResult).text().isEqualTo("AbcFirst line\nSecond line\nThird line");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 1);
+ assertThat(edit).internalEdits().onlyElement().isInsert(0, 0, 3);
+ }
+
+ @Test
+ public void insertSingleLineNoEOLInTheMiddle() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line", 2, 5, 2, 5, "Abc");
+ assertThat(fixResult).text().isEqualTo("First line\nSeconAbcd line\nThird line");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(1, 1, 1, 1);
+ assertThat(edit).internalEdits().onlyElement().isInsert(5, 5, 3);
+ }
+
+ @Test
+ public void insertSingleLineNoEOLAtEnd() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line", 3, 10, 3, 10, "Abc");
+ assertThat(fixResult).text().isEqualTo("First line\nSecond line\nThird lineAbc");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(2, 1, 2, 1);
+ assertThat(edit).internalEdits().onlyElement().isInsert(10, 10, 3);
+ }
+
+ @Test
+ public void insertSingleLineWithEOLAtStart() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line", 1, 0, 1, 0, "Abc\n");
+ assertThat(fixResult).text().isEqualTo("Abc\nFirst line\nSecond line\nThird line");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isInsert(0, 0, 1);
+ assertThat(edit).internalEdits().onlyElement().isInsert(0, 0, 4);
+ }
+
+ @Test
+ public void insertSingleLineWithEOLInTheMiddle() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line", 2, 5, 2, 5, "Abc\n");
+ assertThat(fixResult).text().isEqualTo("First line\nSeconAbc\nd line\nThird line");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(1, 1, 1, 2);
+ assertThat(edit).internalEdits().onlyElement().isInsert(5, 5, 4);
+ }
+
+ @Test
+ public void insertSingleLineWithEOLAtEnd() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line", 3, 10, 3, 10, "Abc\n");
+ assertThat(fixResult).text().isEqualTo("First line\nSecond line\nThird lineAbc\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(2, 1, 2, 1);
+ assertThat(edit).internalEdits().onlyElement().isInsert(10, 10, 4);
+ }
+
+ @Test
+ public void insertMultilineLineWithEOLAtStart() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line", 1, 0, 1, 0, "Abc\nDefgh\n");
+ assertThat(fixResult).text().isEqualTo("Abc\nDefgh\nFirst line\nSecond line\nThird line");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isInsert(0, 0, 2);
+ assertThat(edit).internalEdits().onlyElement().isInsert(0, 0, 10);
+ }
+
+ @Test
+ public void insertMultilineLineWithEOLInTheMiddle() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line", 2, 5, 2, 5, "Abc\nDefgh\n");
+ assertThat(fixResult).text().isEqualTo("First line\nSeconAbc\nDefgh\nd line\nThird line");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(1, 1, 1, 3);
+ assertThat(edit).internalEdits().onlyElement().isInsert(5, 5, 10);
+ }
+
+ @Test
+ public void insertMultilineLineWithEOLAtEnd() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line", 3, 10, 3, 10, "Abc\nDefgh\n");
+ assertThat(fixResult).text().isEqualTo("First line\nSecond line\nThird lineAbc\nDefgh\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(2, 1, 2, 2);
+ assertThat(edit).internalEdits().onlyElement().isInsert(10, 10, 10);
+ }
+
+ @Test
+ public void replaceWithSingleLineNoEOLAtStart() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line", 1, 0, 1, 2, "Abc");
+ assertThat(fixResult).text().isEqualTo("Abcrst line\nSecond line\nThird line");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 1);
+ assertThat(edit).internalEdits().onlyElement().isReplace(0, 2, 0, 3);
+ }
+
+ @Test
+ public void replaceWithSingleLineNoEOLInTheMiddle() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line", 2, 3, 2, 5, "Abc");
+ assertThat(fixResult).text().isEqualTo("First line\nSecAbcd line\nThird line");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(1, 1, 1, 1);
+ assertThat(edit).internalEdits().onlyElement().isReplace(3, 2, 3, 3);
+ }
+
+ @Test
+ public void replaceWithSingleLineNoEOLAtEnd() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line", 3, 8, 3, 10, "Abc");
+ assertThat(fixResult).text().isEqualTo("First line\nSecond line\nThird liAbc");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(2, 1, 2, 1);
+ assertThat(edit).internalEdits().onlyElement().isReplace(8, 2, 8, 3);
+ }
+
+ @Test
+ public void replaceWithSingleLineWithEOLAtStart() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line", 1, 0, 1, 2, "Abc\n");
+ assertThat(fixResult).text().isEqualTo("Abc\nrst line\nSecond line\nThird line");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 2);
+ assertThat(edit).internalEdits().onlyElement().isReplace(0, 2, 0, 4);
+ }
+
+ @Test
+ public void replaceWithSingleLineWithEOLInTheMiddle() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line", 2, 3, 2, 5, "Abc\n");
+ assertThat(fixResult).text().isEqualTo("First line\nSecAbc\nd line\nThird line");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(1, 1, 1, 2);
+ assertThat(edit).internalEdits().onlyElement().isReplace(3, 2, 3, 4);
+ }
+
+ @Test
+ public void replaceWithSingleLineWithEOLAtEnd() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line", 3, 8, 3, 10, "Abc\n");
+ assertThat(fixResult).text().isEqualTo("First line\nSecond line\nThird liAbc\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(2, 1, 2, 1);
+ assertThat(edit).internalEdits().onlyElement().isReplace(8, 2, 8, 4);
+ }
+
+ @Test
+ public void replaceMultilineLineWithEOLAtStart() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line", 1, 0, 1, 2, "Abc\nDefgh\n");
+ assertThat(fixResult).text().isEqualTo("Abc\nDefgh\nrst line\nSecond line\nThird line");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 3);
+ assertThat(edit).internalEdits().onlyElement().isReplace(0, 2, 0, 10);
+ }
+
+ @Test
+ public void replaceMultilineLineWithEOLInTheMiddle() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line", 2, 3, 2, 5, "Abc\nDefgh\n");
+ assertThat(fixResult).text().isEqualTo("First line\nSecAbc\nDefgh\nd line\nThird line");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(1, 1, 1, 3);
+ assertThat(edit).internalEdits().onlyElement().isReplace(3, 2, 3, 10);
+ }
+
+ @Test
+ public void replaceMultilineLineWithEOLAtEnd() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line", 3, 8, 3, 10, "Abc\nDefgh\n");
+ assertThat(fixResult).text().isEqualTo("First line\nSecond line\nThird liAbc\nDefgh\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(2, 1, 2, 2);
+ assertThat(edit).internalEdits().onlyElement().isReplace(8, 2, 8, 10);
+ }
+
+ @Test
+ public void replaceMultilineLineNoEOLAtStart() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line", 1, 0, 1, 2, "Abc\nDefgh");
+ assertThat(fixResult).text().isEqualTo("Abc\nDefghrst line\nSecond line\nThird line");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 2);
+ assertThat(edit).internalEdits().onlyElement().isReplace(0, 2, 0, 9);
+ }
+
+ @Test
+ public void replaceMultilineLineNoEOLInTheMiddle() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line", 2, 3, 2, 5, "Abc\nDefgh");
+ assertThat(fixResult).text().isEqualTo("First line\nSecAbc\nDefghd line\nThird line");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(1, 1, 1, 2);
+ assertThat(edit).internalEdits().onlyElement().isReplace(3, 2, 3, 9);
+ }
+
+ @Test
+ public void replaceMultilineLineNoEOLAtEnd() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line", 3, 8, 3, 10, "Abc\nDefgh");
+ assertThat(fixResult).text().isEqualTo("First line\nSecond line\nThird liAbc\nDefgh");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(2, 1, 2, 2);
+ assertThat(edit).internalEdits().onlyElement().isReplace(8, 2, 8, 9);
+ }
+
+ @Test
+ public void replaceWholeContent() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line", 1, 0, 3, 10, "Abc");
+ assertThat(fixResult).text().isEqualTo("Abc");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 3, 0, 1);
+ assertThat(edit).internalEdits().onlyElement().isReplace(0, 33, 0, 3);
+ }
+
+ @Test
+ public void deleteWholeContent() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line", 1, 0, 3, 10, "");
+ assertThat(fixResult).text().isEqualTo("");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isDelete(0, 3, 0);
+ assertThat(edit).internalEdits().onlyElement().isDelete(0, 33, 0);
+ }
+
+ @Test
+ public void deleteAtStart() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line", 1, 0, 1, 4, "");
+ assertThat(fixResult).text().isEqualTo("t line\nSecond line\nThird line");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 1);
+ assertThat(edit).internalEdits().onlyElement().isDelete(0, 4, 0);
+ }
+
+ @Test
+ public void deleteInTheMiddle() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line", 1, 5, 3, 1, "");
+ assertThat(fixResult).text().isEqualTo("Firsthird line");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 3, 0, 1);
+ assertThat(edit).internalEdits().onlyElement().isDelete(5, 19, 5);
+ }
+
+ @Test
+ public void deleteAtEnd() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line", 3, 7, 3, 10, "");
+ assertThat(fixResult).text().isEqualTo("First line\nSecond line\nThird l");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(2, 1, 2, 1);
+ assertThat(edit).internalEdits().onlyElement().isDelete(7, 3, 7);
+ }
+}
diff --git a/javatests/com/google/gerrit/server/fixes/fixCalculator/MultilineContentWithEOLTest.java b/javatests/com/google/gerrit/server/fixes/fixCalculator/MultilineContentWithEOLTest.java
new file mode 100644
index 0000000..a2868c8
--- /dev/null
+++ b/javatests/com/google/gerrit/server/fixes/fixCalculator/MultilineContentWithEOLTest.java
@@ -0,0 +1,337 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.fixes.fixCalculator;
+
+import static com.google.gerrit.server.fixes.testing.FixResultSubject.assertThat;
+import static com.google.gerrit.server.fixes.testing.GitEditSubject.assertThat;
+
+import com.google.gerrit.server.fixes.FixCalculator.FixResult;
+import org.eclipse.jgit.diff.Edit;
+import org.junit.Test;
+
+public class MultilineContentWithEOLTest {
+
+ @Test
+ public void insertSingleLineNoEOLAtStart() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line\n", 1, 0, 1, 0, "Abc");
+ assertThat(fixResult).text().isEqualTo("AbcFirst line\nSecond line\nThird line\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 1);
+ assertThat(edit).internalEdits().onlyElement().isInsert(0, 0, 3);
+ }
+
+ @Test
+ public void insertSingleLineNoEOLInTheMiddle() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line\n", 2, 5, 2, 5, "Abc");
+ assertThat(fixResult).text().isEqualTo("First line\nSeconAbcd line\nThird line\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(1, 1, 1, 1);
+ assertThat(edit).internalEdits().onlyElement().isInsert(5, 5, 3);
+ }
+
+ @Test
+ public void insertSingleLineNoEOLAtEnd() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line\n", 4, 0, 4, 0, "Abc");
+ assertThat(fixResult).text().isEqualTo("First line\nSecond line\nThird line\nAbc");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isInsert(3, 3, 1);
+ assertThat(edit).internalEdits().onlyElement().isInsert(0, 0, 3);
+ }
+
+ @Test
+ public void insertSingleLineWithEOLAtStart() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line\n", 1, 0, 1, 0, "Abc\n");
+ assertThat(fixResult).text().isEqualTo("Abc\nFirst line\nSecond line\nThird line\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isInsert(0, 0, 1);
+ assertThat(edit).internalEdits().onlyElement().isInsert(0, 0, 4);
+ }
+
+ @Test
+ public void insertSingleLineWithEOLInTheMiddle() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line\n", 2, 5, 2, 5, "Abc\n");
+ assertThat(fixResult).text().isEqualTo("First line\nSeconAbc\nd line\nThird line\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(1, 1, 1, 2);
+ assertThat(edit).internalEdits().onlyElement().isInsert(5, 5, 4);
+ }
+
+ @Test
+ public void insertSingleLineWithEOLAtEnd() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line\n", 4, 0, 4, 0, "Abc\n");
+ assertThat(fixResult).text().isEqualTo("First line\nSecond line\nThird line\nAbc\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isInsert(3, 3, 1);
+ assertThat(edit).internalEdits().onlyElement().isInsert(0, 0, 4);
+ }
+
+ @Test
+ public void insertMultilineLineWithEOLAtStart() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line\n", 1, 0, 1, 0, "Abc\nDefgh\n");
+ assertThat(fixResult).text().isEqualTo("Abc\nDefgh\nFirst line\nSecond line\nThird line\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isInsert(0, 0, 2);
+ assertThat(edit).internalEdits().onlyElement().isInsert(0, 0, 10);
+ }
+
+ @Test
+ public void insertMultilineLineWithEOLInTheMiddle() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line\n", 2, 5, 2, 5, "Abc\nDefgh\n");
+ assertThat(fixResult).text().isEqualTo("First line\nSeconAbc\nDefgh\nd line\nThird line\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(1, 1, 1, 3);
+ assertThat(edit).internalEdits().onlyElement().isInsert(5, 5, 10);
+ }
+
+ @Test
+ public void insertMultilineLineWithEOLAtEnd() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line\n", 4, 0, 4, 0, "Abc\nDefgh\n");
+ assertThat(fixResult).text().isEqualTo("First line\nSecond line\nThird line\nAbc\nDefgh\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isInsert(3, 3, 2);
+ assertThat(edit).internalEdits().onlyElement().isInsert(0, 0, 10);
+ }
+
+ @Test
+ public void replaceWithSingleLineNoEOLAtStart() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line\n", 1, 0, 1, 2, "Abc");
+ assertThat(fixResult).text().isEqualTo("Abcrst line\nSecond line\nThird line\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 1);
+ assertThat(edit).internalEdits().onlyElement().isReplace(0, 2, 0, 3);
+ }
+
+ @Test
+ public void replaceWithSingleLineNoEOLInTheMiddle() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line\n", 2, 3, 2, 5, "Abc");
+ assertThat(fixResult).text().isEqualTo("First line\nSecAbcd line\nThird line\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(1, 1, 1, 1);
+ assertThat(edit).internalEdits().onlyElement().isReplace(3, 2, 3, 3);
+ }
+
+ @Test
+ public void replaceWithSingleLineNoEOLAtEnd() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line\n", 3, 9, 4, 0, "Abc");
+ assertThat(fixResult).text().isEqualTo("First line\nSecond line\nThird linAbc");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(2, 1, 2, 1);
+ assertThat(edit).internalEdits().onlyElement().isReplace(9, 2, 9, 3);
+ }
+
+ @Test
+ public void replaceWithSingleLineWithEOLAtStart() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line\n", 1, 0, 1, 2, "Abc\n");
+ assertThat(fixResult).text().isEqualTo("Abc\nrst line\nSecond line\nThird line\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 2);
+ assertThat(edit).internalEdits().onlyElement().isReplace(0, 2, 0, 4);
+ }
+
+ @Test
+ public void replaceWithSingleLineWithEOLInTheMiddle() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line\n", 2, 3, 2, 5, "Abc\n");
+ assertThat(fixResult).text().isEqualTo("First line\nSecAbc\nd line\nThird line\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(1, 1, 1, 2);
+ assertThat(edit).internalEdits().onlyElement().isReplace(3, 2, 3, 4);
+ }
+
+ @Test
+ public void replaceWithSingleLineWithEOLAtEnd() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line\n", 3, 9, 4, 0, "Abc\n");
+ assertThat(fixResult).text().isEqualTo("First line\nSecond line\nThird linAbc\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(2, 1, 2, 1);
+ assertThat(edit).internalEdits().onlyElement().isReplace(9, 2, 9, 4);
+ }
+
+ @Test
+ public void replaceMultilineLineWithEOLAtStart() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line\n", 1, 0, 1, 2, "Abc\nDefgh\n");
+ assertThat(fixResult).text().isEqualTo("Abc\nDefgh\nrst line\nSecond line\nThird line\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 3);
+ assertThat(edit).internalEdits().onlyElement().isReplace(0, 2, 0, 10);
+ }
+
+ @Test
+ public void replaceMultilineLineWithEOLInTheMiddle() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line\n", 2, 3, 2, 5, "Abc\nDefgh\n");
+ assertThat(fixResult).text().isEqualTo("First line\nSecAbc\nDefgh\nd line\nThird line\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(1, 1, 1, 3);
+ assertThat(edit).internalEdits().onlyElement().isReplace(3, 2, 3, 10);
+ }
+
+ @Test
+ public void replaceMultilineLineWithEOLAtEnd() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line\n", 3, 9, 4, 0, "Abc\nDefgh\n");
+ assertThat(fixResult).text().isEqualTo("First line\nSecond line\nThird linAbc\nDefgh\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(2, 1, 2, 2);
+ assertThat(edit).internalEdits().onlyElement().isReplace(9, 2, 9, 10);
+ }
+
+ @Test
+ public void replaceMultilineLineNoEOLAtStart() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line\n", 1, 0, 1, 2, "Abc\nDefgh");
+ assertThat(fixResult).text().isEqualTo("Abc\nDefghrst line\nSecond line\nThird line\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 2);
+ assertThat(edit).internalEdits().onlyElement().isReplace(0, 2, 0, 9);
+ }
+
+ @Test
+ public void replaceMultilineLineNoEOLInTheMiddle() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line\n", 2, 3, 2, 5, "Abc\nDefgh");
+ assertThat(fixResult).text().isEqualTo("First line\nSecAbc\nDefghd line\nThird line\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(1, 1, 1, 2);
+ assertThat(edit).internalEdits().onlyElement().isReplace(3, 2, 3, 9);
+ }
+
+ @Test
+ public void replaceMultilineLineNoEOLAtEnd() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line\n", 3, 9, 4, 0, "Abc\nDefgh");
+ assertThat(fixResult).text().isEqualTo("First line\nSecond line\nThird linAbc\nDefgh");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(2, 1, 2, 2);
+ assertThat(edit).internalEdits().onlyElement().isReplace(9, 2, 9, 9);
+ }
+
+ @Test
+ public void replaceWholeContent() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line\n", 1, 0, 4, 0, "Abc");
+ assertThat(fixResult).text().isEqualTo("Abc");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 3, 0, 1);
+ assertThat(edit).internalEdits().onlyElement().isReplace(0, 34, 0, 3);
+ }
+
+ @Test
+ public void deleteWholeContent() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line\n", 1, 0, 4, 0, "");
+ assertThat(fixResult).text().isEqualTo("");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isDelete(0, 3, 0);
+ assertThat(edit).internalEdits().onlyElement().isDelete(0, 34, 0);
+ }
+
+ @Test
+ public void deleteAtStart() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line\n", 1, 0, 1, 4, "");
+ assertThat(fixResult).text().isEqualTo("t line\nSecond line\nThird line\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 1);
+ assertThat(edit).internalEdits().onlyElement().isDelete(0, 4, 0);
+ }
+
+ @Test
+ public void deleteInTheMiddle() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line\n", 1, 5, 3, 1, "");
+ assertThat(fixResult).text().isEqualTo("Firsthird line\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 3, 0, 1);
+ assertThat(edit).internalEdits().onlyElement().isDelete(5, 19, 5);
+ }
+
+ @Test
+ public void deleteAtEnd() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\nSecond line\nThird line\n", 3, 7, 4, 0, "");
+ assertThat(fixResult).text().isEqualTo("First line\nSecond line\nThird l");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(2, 1, 2, 1);
+ assertThat(edit).internalEdits().onlyElement().isDelete(7, 4, 7);
+ }
+}
diff --git a/javatests/com/google/gerrit/server/fixes/fixCalculator/OneLineContentNoEOLTest.java b/javatests/com/google/gerrit/server/fixes/fixCalculator/OneLineContentNoEOLTest.java
new file mode 100644
index 0000000..3de4ef7
--- /dev/null
+++ b/javatests/com/google/gerrit/server/fixes/fixCalculator/OneLineContentNoEOLTest.java
@@ -0,0 +1,320 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.fixes.fixCalculator;
+
+import static com.google.gerrit.server.fixes.testing.FixResultSubject.assertThat;
+import static com.google.gerrit.server.fixes.testing.GitEditSubject.assertThat;
+
+import com.google.gerrit.server.fixes.FixCalculator.FixResult;
+import org.eclipse.jgit.diff.Edit;
+import org.junit.Test;
+
+public class OneLineContentNoEOLTest {
+
+ @Test
+ public void insertSingleLineNoEOLAtStart() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement("First line", 1, 0, 1, 0, "Abc");
+ assertThat(fixResult).text().isEqualTo("AbcFirst line");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 1);
+ assertThat(edit).internalEdits().onlyElement().isInsert(0, 0, 3);
+ }
+
+ @Test
+ public void insertSingleLineNoEOLInTheMiddle() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement("First line", 1, 5, 1, 5, "Abc");
+ assertThat(fixResult).text().isEqualTo("FirstAbc line");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 1);
+ assertThat(edit).internalEdits().onlyElement().isInsert(5, 5, 3);
+ }
+
+ @Test
+ public void insertSingleLineNoEOLAtEnd() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement("First line", 1, 10, 1, 10, "Abc");
+ assertThat(fixResult).text().isEqualTo("First lineAbc");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 1);
+ assertThat(edit).internalEdits().onlyElement().isInsert(10, 10, 3);
+ }
+
+ @Test
+ public void insertSingleLineWithEOLAtStart() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement("First line", 1, 0, 1, 0, "Abc\n");
+ assertThat(fixResult).text().isEqualTo("Abc\nFirst line");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isInsert(0, 0, 1);
+ assertThat(edit).internalEdits().onlyElement().isInsert(0, 0, 4);
+ }
+
+ @Test
+ public void insertSingleLineWithEOLInTheMiddle() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement("First line", 1, 5, 1, 5, "Abc\n");
+ assertThat(fixResult).text().isEqualTo("FirstAbc\n line");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 2);
+ assertThat(edit).internalEdits().onlyElement().isInsert(5, 5, 4);
+ }
+
+ @Test
+ public void insertSingleLineWithEOLAtEnd() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement("First line", 1, 10, 1, 10, "Abc\n");
+ assertThat(fixResult).text().isEqualTo("First lineAbc\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 1);
+ assertThat(edit).internalEdits().onlyElement().isInsert(10, 10, 4);
+ }
+
+ @Test
+ public void insertMultilineLineWithEOLAtStart() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line", 1, 0, 1, 0, "Abc\nDefgh\n");
+ assertThat(fixResult).text().isEqualTo("Abc\nDefgh\nFirst line");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isInsert(0, 0, 2);
+ assertThat(edit).internalEdits().onlyElement().isInsert(0, 0, 10);
+ }
+
+ @Test
+ public void insertMultilineLineWithEOLInTheMiddle() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line", 1, 5, 1, 5, "Abc\nDefgh\n");
+ assertThat(fixResult).text().isEqualTo("FirstAbc\nDefgh\n line");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 3);
+ assertThat(edit).internalEdits().onlyElement().isInsert(5, 5, 10);
+ }
+
+ @Test
+ public void insertMultilineLineWithEOLAtEnd() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line", 1, 10, 1, 10, "Abc\nDefgh\n");
+ assertThat(fixResult).text().isEqualTo("First lineAbc\nDefgh\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 2);
+ assertThat(edit).internalEdits().onlyElement().isInsert(10, 10, 10);
+ }
+
+ @Test
+ public void replaceWithSingleLineNoEOLAtStart() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement("First line", 1, 0, 1, 2, "Abc");
+ assertThat(fixResult).text().isEqualTo("Abcrst line");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 1);
+ assertThat(edit).internalEdits().onlyElement().isReplace(0, 2, 0, 3);
+ }
+
+ @Test
+ public void replaceWithSingleLineNoEOLInTheMiddle() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement("First line", 1, 3, 1, 5, "Abc");
+ assertThat(fixResult).text().isEqualTo("FirAbc line");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 1);
+ assertThat(edit).internalEdits().onlyElement().isReplace(3, 2, 3, 3);
+ }
+
+ @Test
+ public void replaceWithSingleLineNoEOLAtEnd() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement("First line", 1, 8, 1, 10, "Abc");
+ assertThat(fixResult).text().isEqualTo("First liAbc");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 1);
+ assertThat(edit).internalEdits().onlyElement().isReplace(8, 2, 8, 3);
+ }
+
+ @Test
+ public void replaceWithSingleLineWithEOLAtStart() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement("First line", 1, 0, 1, 2, "Abc\n");
+ assertThat(fixResult).text().isEqualTo("Abc\nrst line");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 2);
+ assertThat(edit).internalEdits().onlyElement().isReplace(0, 2, 0, 4);
+ }
+
+ @Test
+ public void replaceWithSingleLineWithEOLInTheMiddle() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement("First line", 1, 3, 1, 5, "Abc\n");
+ assertThat(fixResult).text().isEqualTo("FirAbc\n line");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 2);
+ assertThat(edit).internalEdits().onlyElement().isReplace(3, 2, 3, 4);
+ }
+
+ @Test
+ public void replaceWithSingleLineWithEOLAtEnd() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement("First line", 1, 8, 1, 10, "Abc\n");
+ assertThat(fixResult).text().isEqualTo("First liAbc\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 1);
+ assertThat(edit).internalEdits().onlyElement().isReplace(8, 2, 8, 4);
+ }
+
+ @Test
+ public void replaceMultilineLineWithEOLAtStart() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line", 1, 0, 1, 2, "Abc\nDefgh\n");
+ assertThat(fixResult).text().isEqualTo("Abc\nDefgh\nrst line");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 3);
+ assertThat(edit).internalEdits().onlyElement().isReplace(0, 2, 0, 10);
+ }
+
+ @Test
+ public void replaceMultilineLineWithEOLInTheMiddle() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line", 1, 3, 1, 5, "Abc\nDefgh\n");
+ assertThat(fixResult).text().isEqualTo("FirAbc\nDefgh\n line");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 3);
+ assertThat(edit).internalEdits().onlyElement().isReplace(3, 2, 3, 10);
+ }
+
+ @Test
+ public void replaceMultilineLineWithEOLAtEnd() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line", 1, 8, 1, 10, "Abc\nDefgh\n");
+ assertThat(fixResult).text().isEqualTo("First liAbc\nDefgh\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 2);
+ assertThat(edit).internalEdits().onlyElement().isReplace(8, 2, 8, 10);
+ }
+
+ @Test
+ public void replaceMultilineLineNoEOLAtStart() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line", 1, 0, 1, 2, "Abc\nDefgh");
+ assertThat(fixResult).text().isEqualTo("Abc\nDefghrst line");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 2);
+ assertThat(edit).internalEdits().onlyElement().isReplace(0, 2, 0, 9);
+ }
+
+ @Test
+ public void replaceMultilineLineNoEOLInTheMiddle() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line", 1, 3, 1, 5, "Abc\nDefgh");
+ assertThat(fixResult).text().isEqualTo("FirAbc\nDefgh line");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 2);
+ assertThat(edit).internalEdits().onlyElement().isReplace(3, 2, 3, 9);
+ }
+
+ @Test
+ public void replaceMultilineLineNoEOLAtEnd() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line", 1, 8, 1, 10, "Abc\nDefgh");
+ assertThat(fixResult).text().isEqualTo("First liAbc\nDefgh");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 2);
+ assertThat(edit).internalEdits().onlyElement().isReplace(8, 2, 8, 9);
+ }
+
+ @Test
+ public void replaceWholeContent() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement("First line", 1, 0, 1, 10, "Abc");
+ assertThat(fixResult).text().isEqualTo("Abc");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 1);
+ assertThat(edit).internalEdits().onlyElement().isReplace(0, 10, 0, 3);
+ }
+
+ @Test
+ public void deleteWholeContent() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement("First line", 1, 0, 1, 10, "");
+ assertThat(fixResult).text().isEqualTo("");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isDelete(0, 1, 0);
+ assertThat(edit).internalEdits().onlyElement().isDelete(0, 10, 0);
+ }
+
+ @Test
+ public void deleteAtStart() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement("First line", 1, 0, 1, 4, "");
+ assertThat(fixResult).text().isEqualTo("t line");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 1);
+ assertThat(edit).internalEdits().onlyElement().isDelete(0, 4, 0);
+ }
+
+ @Test
+ public void deleteInTheMiddle() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement("First line", 1, 5, 1, 8, "");
+ assertThat(fixResult).text().isEqualTo("Firstne");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 1);
+ assertThat(edit).internalEdits().onlyElement().isDelete(5, 3, 5);
+ }
+
+ @Test
+ public void deleteAtEnd() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement("First line", 1, 7, 1, 10, "");
+ assertThat(fixResult).text().isEqualTo("First l");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 1);
+ assertThat(edit).internalEdits().onlyElement().isDelete(7, 3, 7);
+ }
+}
diff --git a/javatests/com/google/gerrit/server/fixes/fixCalculator/OneLineContentWithEOLTest.java b/javatests/com/google/gerrit/server/fixes/fixCalculator/OneLineContentWithEOLTest.java
new file mode 100644
index 0000000..bae714b
--- /dev/null
+++ b/javatests/com/google/gerrit/server/fixes/fixCalculator/OneLineContentWithEOLTest.java
@@ -0,0 +1,320 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.fixes.fixCalculator;
+
+import static com.google.gerrit.server.fixes.testing.FixResultSubject.assertThat;
+import static com.google.gerrit.server.fixes.testing.GitEditSubject.assertThat;
+
+import com.google.gerrit.server.fixes.FixCalculator.FixResult;
+import org.eclipse.jgit.diff.Edit;
+import org.junit.Test;
+
+public class OneLineContentWithEOLTest {
+
+ @Test
+ public void insertSingleLineNoEOLAtStart() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement("First line\n", 1, 0, 1, 0, "Abc");
+ assertThat(fixResult).text().isEqualTo("AbcFirst line\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 1);
+ assertThat(edit).internalEdits().onlyElement().isInsert(0, 0, 3);
+ }
+
+ @Test
+ public void insertSingleLineNoEOLInTheMiddle() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement("First line\n", 1, 5, 1, 5, "Abc");
+ assertThat(fixResult).text().isEqualTo("FirstAbc line\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 1);
+ assertThat(edit).internalEdits().onlyElement().isInsert(5, 5, 3);
+ }
+
+ @Test
+ public void insertSingleLineNoEOLAtEnd() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement("First line\n", 2, 0, 2, 0, "Abc");
+ assertThat(fixResult).text().isEqualTo("First line\nAbc");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isInsert(1, 1, 1);
+ assertThat(edit).internalEdits().onlyElement().isInsert(0, 0, 3);
+ }
+
+ @Test
+ public void insertSingleLineWithEOLAtStart() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement("First line\n", 1, 0, 1, 0, "Abc\n");
+ assertThat(fixResult).text().isEqualTo("Abc\nFirst line\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isInsert(0, 0, 1);
+ assertThat(edit).internalEdits().onlyElement().isInsert(0, 0, 4);
+ }
+
+ @Test
+ public void insertSingleLineWithEOLInTheMiddle() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement("First line\n", 1, 5, 1, 5, "Abc\n");
+ assertThat(fixResult).text().isEqualTo("FirstAbc\n line\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 2);
+ assertThat(edit).internalEdits().onlyElement().isInsert(5, 5, 4);
+ }
+
+ @Test
+ public void insertSingleLineWithEOLAtEnd() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement("First line\n", 2, 0, 2, 0, "Abc\n");
+ assertThat(fixResult).text().isEqualTo("First line\nAbc\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isInsert(1, 1, 1);
+ assertThat(edit).internalEdits().onlyElement().isInsert(0, 0, 4);
+ }
+
+ @Test
+ public void insertMultilineLineWithEOLAtStart() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\n", 1, 0, 1, 0, "Abc\nDefgh\n");
+ assertThat(fixResult).text().isEqualTo("Abc\nDefgh\nFirst line\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isInsert(0, 0, 2);
+ assertThat(edit).internalEdits().onlyElement().isInsert(0, 0, 10);
+ }
+
+ @Test
+ public void insertMultilineLineWithEOLInTheMiddle() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\n", 1, 5, 1, 5, "Abc\nDefgh\n");
+ assertThat(fixResult).text().isEqualTo("FirstAbc\nDefgh\n line\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 3);
+ assertThat(edit).internalEdits().onlyElement().isInsert(5, 5, 10);
+ }
+
+ @Test
+ public void insertMultilineLineWithEOLAtEnd() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\n", 2, 0, 2, 0, "Abc\nDefgh\n");
+ assertThat(fixResult).text().isEqualTo("First line\nAbc\nDefgh\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isInsert(1, 1, 2);
+ assertThat(edit).internalEdits().onlyElement().isInsert(0, 0, 10);
+ }
+
+ @Test
+ public void replaceWithSingleLineNoEOLAtStart() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement("First line\n", 1, 0, 1, 2, "Abc");
+ assertThat(fixResult).text().isEqualTo("Abcrst line\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 1);
+ assertThat(edit).internalEdits().onlyElement().isReplace(0, 2, 0, 3);
+ }
+
+ @Test
+ public void replaceWithSingleLineNoEOLInTheMiddle() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement("First line\n", 1, 3, 1, 5, "Abc");
+ assertThat(fixResult).text().isEqualTo("FirAbc line\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 1);
+ assertThat(edit).internalEdits().onlyElement().isReplace(3, 2, 3, 3);
+ }
+
+ @Test
+ public void replaceWithSingleLineNoEOLAtEnd() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement("First line\n", 1, 9, 2, 0, "Abc");
+ assertThat(fixResult).text().isEqualTo("First linAbc");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 1);
+ assertThat(edit).internalEdits().onlyElement().isReplace(9, 2, 9, 3);
+ }
+
+ @Test
+ public void replaceWithSingleLineWithEOLAtStart() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement("First line\n", 1, 0, 1, 2, "Abc\n");
+ assertThat(fixResult).text().isEqualTo("Abc\nrst line\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 2);
+ assertThat(edit).internalEdits().onlyElement().isReplace(0, 2, 0, 4);
+ }
+
+ @Test
+ public void replaceWithSingleLineWithEOLInTheMiddle() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement("First line\n", 1, 3, 1, 5, "Abc\n");
+ assertThat(fixResult).text().isEqualTo("FirAbc\n line\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 2);
+ assertThat(edit).internalEdits().onlyElement().isReplace(3, 2, 3, 4);
+ }
+
+ @Test
+ public void replaceWithSingleLineWithEOLAtEnd() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement("First line\n", 1, 8, 2, 0, "Abc\n");
+ assertThat(fixResult).text().isEqualTo("First liAbc\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 1);
+ assertThat(edit).internalEdits().onlyElement().isReplace(8, 3, 8, 4);
+ }
+
+ @Test
+ public void replaceMultilineLineWithEOLAtStart() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\n", 1, 0, 1, 2, "Abc\nDefgh\n");
+ assertThat(fixResult).text().isEqualTo("Abc\nDefgh\nrst line\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 3);
+ assertThat(edit).internalEdits().onlyElement().isReplace(0, 2, 0, 10);
+ }
+
+ @Test
+ public void replaceMultilineLineWithEOLInTheMiddle() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\n", 1, 3, 1, 5, "Abc\nDefgh\n");
+ assertThat(fixResult).text().isEqualTo("FirAbc\nDefgh\n line\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 3);
+ assertThat(edit).internalEdits().onlyElement().isReplace(3, 2, 3, 10);
+ }
+
+ @Test
+ public void replaceMultilineLineWithEOLAtEnd() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\n", 1, 8, 2, 0, "Abc\nDefgh\n");
+ assertThat(fixResult).text().isEqualTo("First liAbc\nDefgh\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 2);
+ assertThat(edit).internalEdits().onlyElement().isReplace(8, 3, 8, 10);
+ }
+
+ @Test
+ public void replaceMultilineLineNoEOLAtStart() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\n", 1, 0, 1, 2, "Abc\nDefgh");
+ assertThat(fixResult).text().isEqualTo("Abc\nDefghrst line\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 2);
+ assertThat(edit).internalEdits().onlyElement().isReplace(0, 2, 0, 9);
+ }
+
+ @Test
+ public void replaceMultilineLineNoEOLInTheMiddle() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\n", 1, 3, 1, 5, "Abc\nDefgh");
+ assertThat(fixResult).text().isEqualTo("FirAbc\nDefgh line\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 2);
+ assertThat(edit).internalEdits().onlyElement().isReplace(3, 2, 3, 9);
+ }
+
+ @Test
+ public void replaceMultilineLineNoEOLAtEnd() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement(
+ "First line\n", 1, 8, 2, 0, "Abc\nDefgh");
+ assertThat(fixResult).text().isEqualTo("First liAbc\nDefgh");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 2);
+ assertThat(edit).internalEdits().onlyElement().isReplace(8, 3, 8, 9);
+ }
+
+ @Test
+ public void replaceWholeContent() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement("First line\n", 1, 0, 2, 0, "Abc");
+ assertThat(fixResult).text().isEqualTo("Abc");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 1);
+ assertThat(edit).internalEdits().onlyElement().isReplace(0, 11, 0, 3);
+ }
+
+ @Test
+ public void deleteWholeContent() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement("First line\n", 1, 0, 2, 0, "");
+ assertThat(fixResult).text().isEqualTo("");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isDelete(0, 1, 0);
+ assertThat(edit).internalEdits().onlyElement().isDelete(0, 11, 0);
+ }
+
+ @Test
+ public void deleteAtStart() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement("First line\n", 1, 0, 1, 4, "");
+ assertThat(fixResult).text().isEqualTo("t line\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 1);
+ assertThat(edit).internalEdits().onlyElement().isDelete(0, 4, 0);
+ }
+
+ @Test
+ public void deleteInTheMiddle() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement("First line\n", 1, 5, 1, 8, "");
+ assertThat(fixResult).text().isEqualTo("Firstne\n");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 1);
+ assertThat(edit).internalEdits().onlyElement().isDelete(5, 3, 5);
+ }
+
+ @Test
+ public void deleteAtEnd() throws Exception {
+ FixResult fixResult =
+ FixCalculatorVariousTest.calculateFixSingleReplacement("First line\n", 1, 7, 2, 0, "");
+ assertThat(fixResult).text().isEqualTo("First l");
+ assertThat(fixResult).edits().hasSize(1);
+ Edit edit = fixResult.edits.get(0);
+ assertThat(edit).isReplace(0, 1, 0, 1);
+ assertThat(edit).internalEdits().onlyElement().isDelete(7, 4, 7);
+ }
+}