blob: 782c7d73df5e8d8cf0af5748cc7e905959a3659f [file] [log] [blame]
// 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));
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), false);
}
@Test
public void lineNumberMustBePositive() {
assertThrows(
ResourceConflictException.class,
() -> calculateFixSingleReplacement("First line\nSecond line", 0, 0, 0, 0, "Abc"));
}
@Test
public void lineNumberMustExist() {
assertThrows(
ResourceConflictException.class,
() -> calculateFixSingleReplacement("First line\nSecond line", 4, 0, 4, 0, "Abc"));
}
@Test
public void startOffsetMustNotBeNegative() {
assertThrows(
ResourceConflictException.class,
() -> calculateFixSingleReplacement("First line\nSecond line", 0, -1, 0, 0, "Abc"));
}
@Test
public void endOffsetMustNotBeNegative() {
assertThrows(
ResourceConflictException.class,
() -> calculateFixSingleReplacement("First line\nSecond line", 0, 0, 0, -1, "Abc"));
}
@Test
public void insertAtTheEndOfSingleLineContentHasEOLMarkInvalidPosition() {
assertThrows(
ResourceConflictException.class,
() -> calculateFixSingleReplacement("First line\n", 1, 11, 1, 11, "Abc"));
}
@Test
public void startAfterEndOfLineMarkOfIntermediateLineThrowsAnException() {
assertThrows(
ResourceConflictException.class,
() ->
calculateFixSingleReplacement(
"First line\nSecond line\nThird line\n", 1, 11, 2, 6, "Abc"));
}
@Test
public void startAfterEndOfLineMarkOfLastLineThrowsAnException() {
assertThrows(
ResourceConflictException.class,
() -> calculateFixSingleReplacement("First line\n", 1, 11, 2, 0, "Abc"));
}
@Test
public void endAfterEndOfLineMarkOfIntermediateLineThrowsAnException() {
assertThrows(
ResourceConflictException.class,
() ->
calculateFixSingleReplacement(
"First line\nSecond line\nThird line\n", 2, 0, 2, 12, "Abc"));
}
@Test
public void endAfterEndOfLineMarkOfLastLineThrowsAnException() {
assertThrows(
ResourceConflictException.class,
() -> calculateFixSingleReplacement("First line\nSecond line\n", 2, 0, 2, 12, "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), false);
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), false);
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 intraline() throws Exception {
FixReplacement replace = new FixReplacement("path", new Range(2, 0, 2, 11), "Second ABC line");
FixResult result =
FixCalculator.calculateFix(multilineContent, ImmutableList.of(replace), true);
assertThat(result)
.text()
.isEqualTo("First line\nSecond ABC line\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(1);
assertThat(edit).internalEdits().element(0).isInsert(7, 7, 4);
}
@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), false);
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),
false);
assertThat(result)
.text()
.isEqualTo(
"FiAB\n"
+ "C\n"
+ "DEFG\n"
+ "Q\n"
+ "rd line\n"
+ "Fourth lneQWERTY\n"
+ "Sixth line\n"
+ "SevXY line\n"
+ "Eighth KLMNO\n"
+ "ASDFline\n"
+ "Ninth line\n"
+ "Tenine\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);
}
@Test
public void changesMayTouch() throws Exception {
FixReplacement firstReplace = new FixReplacement("path", new Range(1, 6, 2, 7), "modified ");
FixReplacement consecutiveReplace =
new FixReplacement("path", new Range(2, 7, 3, 5), "content");
FixResult result =
FixCalculator.calculateFix(
multilineContent, ImmutableList.of(firstReplace, consecutiveReplace), false);
assertThat(result).text().isEqualTo("First modified content line\nFourth line\nFifth line\n");
assertThat(result).edits().hasSize(1);
Edit edit = result.edits.get(0);
assertThat(edit).isReplace(0, 3, 0, 1);
// The current code creates two inline edits even though only one would be necessary. It
// shouldn't make a visual difference to the user and hence we can ignore this.
assertThat(edit).internalEdits().hasSize(2);
assertThat(edit).internalEdits().element(0).isReplace(6, 12, 6, 9);
assertThat(edit).internalEdits().element(1).isReplace(18, 10, 15, 7);
}
@Test
public void overlappingChangesInMiddleOfLineRaisesException() throws Exception {
FixReplacement firstReplace =
new FixReplacement("path", new Range(2, 0, 3, 5), "First modification\n");
FixReplacement secondReplace =
new FixReplacement("path", new Range(3, 4, 4, 0), "Some other modified content\n");
assertThrows(
ResourceConflictException.class,
() ->
FixCalculator.calculateFix(
multilineContent, ImmutableList.of(firstReplace, secondReplace), false));
}
@Test
public void overlappingChangesInBeginningOfLineRaisesException() throws Exception {
FixReplacement firstReplace =
new FixReplacement("path", new Range(2, 0, 3, 1), "First modification\n");
FixReplacement secondReplace =
new FixReplacement("path", new Range(3, 0, 4, 0), "Some other modified content\n");
assertThrows(
ResourceConflictException.class,
() ->
FixCalculator.calculateFix(
multilineContent, ImmutableList.of(firstReplace, secondReplace), false));
}
}