blob: 77582c6e0677ef4a2d49998faf462c3270f34703 [file] [log] [blame]
// Copyright (C) 2021 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.acceptance.api.change;
import static com.google.common.truth.Truth.assertThat;
import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.allowLabel;
import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
import static com.google.gerrit.server.project.testing.TestLabels.labelBuilder;
import static com.google.gerrit.server.project.testing.TestLabels.value;
import static com.google.gerrit.testing.GerritJUnit.assertThrows;
import static org.eclipse.jgit.lib.Constants.HEAD;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.config.GerritConfig;
import com.google.gerrit.acceptance.testsuite.change.ChangeOperations;
import com.google.gerrit.acceptance.testsuite.project.ProjectOperations;
import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.LabelId;
import com.google.gerrit.entities.LabelType;
import com.google.gerrit.entities.RefNames;
import com.google.gerrit.extensions.api.changes.RebaseInput;
import com.google.gerrit.extensions.api.changes.ReviewInput;
import com.google.gerrit.extensions.api.changes.ReviewInput.CommentInput;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.server.project.testing.TestLabels;
import com.google.inject.Inject;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.jgit.lib.ObjectId;
import org.junit.Before;
import org.junit.Test;
public class SubmitWithStickyApprovalDiffIT extends AbstractDaemonTest {
@Inject private ProjectOperations projectOperations;
@Inject private ChangeOperations changeOperations;
@Before
public void setup() throws Exception {
try (ProjectConfigUpdate u = updateProject(project)) {
// Overwrite "Code-Review" label that is inherited from All-Projects.
// This way changes to the "Code Review" label don't affect other tests.
// Also make the vote sticky.
LabelType.Builder codeReview =
labelBuilder(
LabelId.CODE_REVIEW,
value(2, "Looks good to me, approved"),
value(1, "Looks good to me, but someone else must approve"),
value(0, "No score"),
value(-1, "I would prefer this is not submitted as is"),
value(-2, "This shall not be submitted"));
codeReview.setCopyAnyScore(true);
u.getConfig().upsertLabelType(codeReview.build());
u.save();
}
projectOperations
.project(project)
.forUpdate()
.add(
allowLabel(TestLabels.codeReview().getName())
.ref(RefNames.REFS_HEADS + "*")
.group(REGISTERED_USERS)
.range(-2, 2))
.update();
}
@Test
public void diffChangeMessageOnSubmitWithStickyVote_modifiedFileWithReplaces() throws Exception {
Change.Id changeId =
changeOperations
.newChange()
.project(project)
.file("file")
.content("content\naa\nsF\naa\naaa\nsomething\nfoo\nbla\ndeletedEnd")
.create();
gApi.changes().id(changeId.get()).current().review(ReviewInput.approve());
changeOperations
.change(changeId)
.newPatchset()
.file("file")
.content("content\naa\nsS\naa\naaa\ndifferent\nfoo\nbla")
.create();
// add a reviewer to ensure an email is sent.
gApi.changes().id(changeId.get()).addReviewer(user.email());
gApi.changes().id(changeId.get()).current().submit();
assertDiffChangeMessageAndEmailWithStickyApproval(
Iterables.getLast(gApi.changes().id(changeId.get()).messages()).message,
/* file= */ "file",
/* insertions= */ 3,
/* deletions= */ 4,
/* expectedFileDiff= */ "@@ -1,9 +1,8 @@\n"
+ " content\n"
+ " aa\n"
+ "-sF\n"
+ "+sS\n"
+ " aa\n"
+ " aaa\n"
+ "-something\n"
+ "+different\n"
+ " foo\n"
+ "-bla\n"
+ "-deletedEnd\n"
+ "+bla",
/* oldFileName= */ null);
}
@Test
public void diffChangeMessageOnSubmitWithStickyVote_ignoreDiffFromRebaseAdditions()
throws Exception {
ObjectId initial = repo().exactRef(HEAD).getLeaf().getObjectId();
Change.Id changeId =
changeOperations
.newChange()
.project(project)
.file("file")
.content("line1\nline2\nline3\nline4")
.create();
gApi.changes().id(changeId.get()).current().review(ReviewInput.approve());
changeOperations
.change(changeId)
.newPatchset()
.file("file")
.content("line012\nline1\nline2\nline3\nline4")
.create();
// add a reviewer to ensure an email is sent.
gApi.changes().id(changeId.get()).addReviewer(user.email());
testRepo.reset(initial);
// create 2 unrelated changes and rebase on top of them. Those rebases should be ignored.
// The changes add files.
Change.Id unrelated =
changeOperations.newChange().project(project).file("a").content("a").create();
gApi.changes().id(unrelated.get()).current().review(ReviewInput.approve());
gApi.changes().id(unrelated.get()).current().submit();
unrelated = changeOperations.newChange().project(project).file("z").content("z").create();
gApi.changes().id(unrelated.get()).current().review(ReviewInput.approve());
gApi.changes().id(unrelated.get()).current().submit();
RebaseInput rebaseInput = new RebaseInput();
rebaseInput.base = gApi.changes().id(unrelated.get()).current().commit(true).commit;
gApi.changes().id(changeId.get()).current().rebase(rebaseInput);
gApi.changes().id(changeId.get()).current().submit();
assertDiffChangeMessageAndEmailWithStickyApproval(
Iterables.getLast(gApi.changes().id(changeId.get()).messages()).message,
/* file= */ "file",
/* insertions= */ 1,
/* deletions= */ 0,
/* expectedFileDiff= */ "@@ -1,3 +1,4 @@\n"
+ "+line012\n"
+ " line1\n"
+ " line2\n"
+ " line3",
/* oldFileName= */ null);
}
@Test
public void diffChangeMessageOnSubmitWithStickyVote_ignoreDiffFromRebaseRenames()
throws Exception {
Change.Id setup = changeOperations.newChange().project(project).file("a").content("a").create();
gApi.changes().id(setup.get()).current().review(ReviewInput.approve());
gApi.changes().id(setup.get()).current().submit();
setup = changeOperations.newChange().project(project).file("z").content("z").create();
gApi.changes().id(setup.get()).current().review(ReviewInput.approve());
gApi.changes().id(setup.get()).current().submit();
ObjectId initial = repo().exactRef(HEAD).getLeaf().getObjectId();
Change.Id changeId =
changeOperations
.newChange()
.project(project)
.file("file")
.content("line1\nline2\nline3\nline4")
.create();
gApi.changes().id(changeId.get()).current().review(ReviewInput.approve());
changeOperations
.change(changeId)
.newPatchset()
.file("file")
.content("line012\nline1\nline2\nline3\nline4")
.create();
// add a reviewer to ensure an email is sent.
gApi.changes().id(changeId.get()).addReviewer(user.email());
testRepo.reset(initial);
// create 2 unrelated changes and rebase on top of them. Those rebases should be ignored.
// The changes rename files.
Change.Id unrelated =
changeOperations.newChange().project(project).file("a").renameTo("aa").create();
gApi.changes().id(unrelated.get()).current().review(ReviewInput.approve());
gApi.changes().id(unrelated.get()).current().submit();
unrelated = changeOperations.newChange().project(project).file("z").renameTo("zz").create();
gApi.changes().id(unrelated.get()).current().review(ReviewInput.approve());
gApi.changes().id(unrelated.get()).current().submit();
RebaseInput rebaseInput = new RebaseInput();
rebaseInput.base = gApi.changes().id(unrelated.get()).current().commit(true).commit;
gApi.changes().id(changeId.get()).current().rebase(rebaseInput);
gApi.changes().id(changeId.get()).current().submit();
assertDiffChangeMessageAndEmailWithStickyApproval(
Iterables.getLast(gApi.changes().id(changeId.get()).messages()).message,
/* file= */ "file",
/* insertions= */ 1,
/* deletions= */ 0,
/* expectedFileDiff= */ "@@ -1,3 +1,4 @@\n"
+ "+line012\n"
+ " line1\n"
+ " line2\n"
+ " line3",
/* oldFileName= */ null);
}
@Test
public void diffChangeMessageOnSubmitWithStickyVote_ignoreDiffFromRebaseDeletions()
throws Exception {
Change.Id setup = changeOperations.newChange().project(project).file("a").content("a").create();
gApi.changes().id(setup.get()).current().review(ReviewInput.approve());
gApi.changes().id(setup.get()).current().submit();
setup = changeOperations.newChange().project(project).file("z").content("z").create();
gApi.changes().id(setup.get()).current().review(ReviewInput.approve());
gApi.changes().id(setup.get()).current().submit();
ObjectId initial = repo().exactRef(HEAD).getLeaf().getObjectId();
Change.Id changeId =
changeOperations
.newChange()
.project(project)
.file("file")
.content("line1\nline2\nline3\nline4")
.create();
gApi.changes().id(changeId.get()).current().review(ReviewInput.approve());
changeOperations
.change(changeId)
.newPatchset()
.file("file")
.content("line012\nline1\nline2\nline3\nline4")
.create();
// add a reviewer to ensure an email is sent.
gApi.changes().id(changeId.get()).addReviewer(user.email());
testRepo.reset(initial);
// create 2 unrelated changes and rebase on top of them. Those rebases should be ignored.
// The changes delete files.
Change.Id unrelated = changeOperations.newChange().project(project).file("a").delete().create();
gApi.changes().id(unrelated.get()).current().review(ReviewInput.approve());
gApi.changes().id(unrelated.get()).current().submit();
unrelated = changeOperations.newChange().project(project).file("z").delete().create();
gApi.changes().id(unrelated.get()).current().review(ReviewInput.approve());
gApi.changes().id(unrelated.get()).current().submit();
RebaseInput rebaseInput = new RebaseInput();
rebaseInput.base = gApi.changes().id(unrelated.get()).current().commit(true).commit;
gApi.changes().id(changeId.get()).current().rebase(rebaseInput);
gApi.changes().id(changeId.get()).current().submit();
assertDiffChangeMessageAndEmailWithStickyApproval(
Iterables.getLast(gApi.changes().id(changeId.get()).messages()).message,
/* file= */ "file",
/* insertions= */ 1,
/* deletions= */ 0,
/* expectedFileDiff= */ "@@ -1,3 +1,4 @@\n"
+ "+line012\n"
+ " line1\n"
+ " line2\n"
+ " line3",
/* oldFileName= */ null);
}
@Test
public void diffChangeMessageOnSubmitWithStickyVote_modifiedFileWithInsertionAndDeletion()
throws Exception {
Change.Id changeId =
changeOperations
.newChange()
.project(project)
.file("file")
.content("content\naa\nbb\ncc\ndd\nee\nff\nTODELETE1\nTODELETE2\ngg\nend")
.create();
gApi.changes().id(changeId.get()).current().review(ReviewInput.approve());
changeOperations
.change(changeId)
.newPatchset()
.file("file")
.content("content\naa\nbb\ncc\nINSERTION\nINSERTED\nVERY\nLONG\ndd\nee\nff\ngg\nend")
.create();
// add a reviewer to ensure an email is sent.
gApi.changes().id(changeId.get()).addReviewer(user.email());
gApi.changes().id(changeId.get()).current().submit();
assertDiffChangeMessageAndEmailWithStickyApproval(
Iterables.getLast(gApi.changes().id(changeId.get()).messages()).message,
/* file= */ "file",
/* insertions= */ 4,
/* deletions= */ 2,
/* expectedFileDiff= */ "@@ -2,10 +2,12 @@\n"
+ " aa\n"
+ " bb\n"
+ " cc\n"
+ "+INSERTION\n"
+ "+INSERTED\n"
+ "+VERY\n"
+ "+LONG\n"
+ " dd\n"
+ " ee\n"
+ " ff\n"
+ "-TODELETE1\n"
+ "-TODELETE2\n"
+ " gg\n"
+ " end",
/* oldFileName= */ null);
}
@Test
@GerritConfig(name = "change.cumulativeCommentSizeLimit", value = "10k")
public void autoGeneratedPostSubmitDiffIsPartOfTheCommentSizeLimit() throws Exception {
Change.Id changeId =
changeOperations.newChange().project(project).file("file").content("content").create();
gApi.changes().id(changeId.get()).current().review(ReviewInput.approve());
String content = new String(new char[800]).replace("\0", "a");
changeOperations.change(changeId).newPatchset().file("file").content(content).create();
// Post a submit diff that is almost the cumulativeCommentSizeLimit
gApi.changes().id(changeId.get()).current().submit();
assertThat(Iterables.getLast(gApi.changes().id(changeId.get()).messages()).message)
.doesNotContain("The diff is too large to show. Please review the diff");
// unrelated comment and change message posting doesn't work, since the post submit diff is
// counted towards the cumulativeCommentSizeLimit for unrelated follow-up comments.
// 800 + 9500 > 10k.
String message = new String(new char[9500]).replace("\0", "a");
ReviewInput reviewInput = new ReviewInput().message(message);
CommentInput commentInput = new CommentInput();
commentInput.line = 1;
commentInput.path = "file";
reviewInput.comments = ImmutableMap.of("file", ImmutableList.of(commentInput));
BadRequestException thrown =
assertThrows(
BadRequestException.class,
() -> gApi.changes().id(changeId.get()).current().review(reviewInput));
assertThat(thrown)
.hasMessageThat()
.contains("Exceeding maximum cumulative size of comments and change messages");
}
@Test
public void postSubmitDiffCannotBeTooBig() throws Exception {
Change.Id changeId =
changeOperations.newChange().project(project).file("file").content("content").create();
gApi.changes().id(changeId.get()).current().review(ReviewInput.approve());
// max post submit diff size is 300k
String content = new String(new char[320000]).replace("\0", "a");
changeOperations.change(changeId).newPatchset().file("file").content(content).create();
// Post submit diff is over the postSubmitDiffSizeLimit (300k).
gApi.changes().id(changeId.get()).current().submit();
assertThat(Iterables.getLast(gApi.changes().id(changeId.get()).messages()).message)
.isEqualTo(
"Change has been successfully merged\n\n1 is the latest approved patch-set.\nThe "
+ "change was submitted with unreviewed changes in the following "
+ "files:\n\n```\nThe name of the file: file\nInsertions: 1, Deletions: 1.\n\nThe"
+ " diff is too large to show. Please review the diff.\n```\n");
}
@Test
@GerritConfig(name = "change.cumulativeCommentSizeLimit", value = "10k")
public void postSubmitDiffCannotBeTooBigWithLargeComments() throws Exception {
Change.Id changeId =
changeOperations.newChange().project(project).file("file").content("content").create();
gApi.changes().id(changeId.get()).current().review(ReviewInput.approve());
// unrelated comment taking up most of the space, making post submit diff shorter.
String message = new String(new char[9700]).replace("\0", "a");
ReviewInput reviewInput = new ReviewInput().message(message);
CommentInput commentInput = new CommentInput();
commentInput.line = 1;
commentInput.path = "file";
reviewInput.comments = ImmutableMap.of("file", ImmutableList.of(commentInput));
gApi.changes().id(changeId.get()).current().review(reviewInput);
String content = new String(new char[500]).replace("\0", "a");
changeOperations.change(changeId).newPatchset().file("file").content(content).create();
// Post submit diff is over the cumulativeCommentSizeLimit, since the comment took most of
// the space (even though the post submit diff is not limited).
gApi.changes().id(changeId.get()).current().submit();
assertThat(Iterables.getLast(gApi.changes().id(changeId.get()).messages()).message)
.isEqualTo(
"Change has been successfully merged\n\n1 is the latest approved patch-set.\nThe "
+ "change was submitted with unreviewed changes in the following "
+ "files:\n\n```\nThe name of the file: file\nInsertions: 1, Deletions: 1.\n\nThe"
+ " diff is too large to show. Please review the diff.\n```\n");
}
@Test
public void diffChangeMessageOnSubmitWithStickyVote_addedFile() throws Exception {
Change.Id changeId = changeOperations.newChange().project(project).create();
gApi.changes().id(changeId.get()).current().review(ReviewInput.approve());
changeOperations
.change(changeId)
.newPatchset()
.file("file")
.content("content\nmore content\nlast content")
.create();
// add a reviewer to ensure an email is sent.
gApi.changes().id(changeId.get()).addReviewer(user.email());
gApi.changes().id(changeId.get()).current().submit();
assertDiffChangeMessageAndEmailWithStickyApproval(
Iterables.getLast(gApi.changes().id(changeId.get()).messages()).message,
/* file= */ "file",
/* insertions= */ 3,
/* deletions= */ 0,
/* expectedFileDiff= */ "@@ -0,0 +1,3 @@\n+content\n+more content\n+last content",
/* oldFileName= */ null);
}
@Test
public void diffChangeMessageOnSubmitWithStickyVote_addedMultipleFiles() throws Exception {
Change.Id changeId = changeOperations.newChange().project(project).create();
gApi.changes().id(changeId.get()).current().review(ReviewInput.approve());
changeOperations
.change(changeId)
.newPatchset()
.file("file")
.content("content1\nmore content\nlast content")
.create();
changeOperations
.change(changeId)
.newPatchset()
.file("otherFile")
.content("content2\nmore content\nlast content")
.create();
// add a reviewer to ensure an email is sent.
gApi.changes().id(changeId.get()).addReviewer(user.email());
gApi.changes().id(changeId.get()).current().submit();
assertDiffChangeMessageAndEmailWithStickyApproval(
Iterables.getLast(gApi.changes().id(changeId.get()).messages()).message,
/* file1= */ "otherFile",
/* insertions1= */ 3,
/* deletions1= */ 0,
/* expectedFileDiff1= */ "@@ -0,0 +1,3 @@\n+content2\n+more content\n+last content",
/* oldFileName1= */ null,
/* file2= */ "file",
/* insertions2= */ 3,
/* deletions2= */ 0,
/* expectedFileDiff2= */ "@@ -0,0 +1,3 @@\n+content1\n+more content\n+last content",
/* oldFileName2= */ null);
}
@Test
public void diffChangeMessageOnSubmitWithStickyVote_removedFile() throws Exception {
Change.Id changeId =
changeOperations
.newChange()
.project(project)
.file("file")
.content("content\nmore content\nlast content")
.create();
gApi.changes().id(changeId.get()).current().review(ReviewInput.approve());
changeOperations.change(changeId).newPatchset().file("file").delete().create();
// add a reviewer to ensure an email is sent.
gApi.changes().id(changeId.get()).addReviewer(user.email());
gApi.changes().id(changeId.get()).current().submit();
assertDiffChangeMessageAndEmailWithStickyApproval(
Iterables.getLast(gApi.changes().id(changeId.get()).messages()).message,
/* file= */ "file",
/* insertions= */ 0,
/* deletions= */ 3,
/* expectedFileDiff= */ "@@ -1,3 +0,0 @@\n-content\n-more content\n-last content",
/* oldFileName= */ null);
}
@Test
public void diffChangeMessageOnSubmitWithStickyVote_renamedFile() throws Exception {
Change.Id changeId =
changeOperations
.newChange()
.project(project)
.file("file")
.content("content\nmoreContent")
.create();
gApi.changes().id(changeId.get()).current().review(ReviewInput.approve());
changeOperations.change(changeId).newPatchset().file("file").renameTo("new_file").create();
// add a reviewer to ensure an email is sent.
gApi.changes().id(changeId.get()).addReviewer(user.email());
gApi.changes().id(changeId.get()).current().submit();
assertDiffChangeMessageAndEmailWithStickyApproval(
Iterables.getLast(gApi.changes().id(changeId.get()).messages()).message,
/* file= */ "new_file",
/* insertions= */ 0,
/* deletions= */ 0,
/* expectedFileDiff= */ "",
/* oldFileName= */ "file");
}
@Test
public void noDiffChangeMessageOnSubmitWhenVotedOnLastPatchset() throws Exception {
Change.Id changeId =
changeOperations
.newChange()
.project(project)
.file("file")
.content("content\nmoreContent")
.create();
gApi.changes().id(changeId.get()).current().review(ReviewInput.approve());
changeOperations.change(changeId).newPatchset().file("file").renameTo("new_file").create();
// Approve last patch-set again, although there is already a +2 on the change (since it's
// sticky).
gApi.changes().id(changeId.get()).current().review(ReviewInput.approve());
gApi.changes().id(changeId.get()).current().submit();
assertThat(Iterables.getLast(gApi.changes().id(changeId.get()).messages()).message.trim())
.isEqualTo("Change has been successfully merged");
}
@Test
public void diffChangeMessageOnSubmitWithStickyVote_approvedPatchset() throws Exception {
Change.Id changeId = changeOperations.newChange().project(project).create();
changeOperations.change(changeId).newPatchset().create();
// approve patch-set 2
gApi.changes().id(changeId.get()).current().review(ReviewInput.approve());
// create patch-set 3
changeOperations.change(changeId).newPatchset().create();
gApi.changes().id(changeId.get()).current().submit();
// patch-set 2 was the latest approved one.
assertThat(Iterables.getLast(gApi.changes().id(changeId.get()).messages()).message)
.contains("2 is the latest approved patch-set.");
}
@Test
public void diffChangeMessageOnSubmitWithStickyVote_noChanges() throws Exception {
Change.Id changeId = changeOperations.newChange().project(project).create();
gApi.changes().id(changeId.get()).current().review(ReviewInput.approve());
// no file changed
changeOperations.change(changeId).newPatchset().create();
gApi.changes().id(changeId.get()).current().submit();
// No other content in the message since the diff is the same.
assertThat(Iterables.getLast(gApi.changes().id(changeId.get()).messages()).message)
.isEqualTo(
"Change has been successfully merged\n\n1 is the latest approved patch-set.\n"
+ "No files were changed between the latest approved patch-set and the submitted"
+ " one.\n");
}
private void assertDiffChangeMessageAndEmailWithStickyApproval(
String message,
String file,
int insertions,
int deletions,
String expectedFileDiff,
String oldFileName) {
assertDiffChangeMessageAndEmailWithStickyApproval(
message,
file,
insertions,
deletions,
expectedFileDiff,
oldFileName,
/* file2= */ null,
/* insertions2= */ 0,
/* deletions2 =
*/ 0,
/* expectedFileDiff2= */ null,
/* oldFileName2= */ null);
}
private void assertDiffChangeMessageAndEmailWithStickyApproval(
String message,
String file1,
int insertions1,
int deletions1,
String expectedFileDiff1,
String oldFileName1,
String file2,
int insertions2,
int deletions2,
String expectedFileDiff2,
String oldFileName2) {
String beginningOfMessage =
"1 is the latest approved patch-set.\n"
+ "The change was submitted with unreviewed changes in the following files:\n"
+ "\n";
String fileDiff1 = fileDiff(expectedFileDiff1, oldFileName1, file1, insertions1, deletions1);
String expectedMessage1 = beginningOfMessage + fileDiff1;
String expectedMessage2 = "";
Set<String> expectedChangeMessages = new HashSet<>();
if (file2 != null) {
String fileDiff2 = fileDiff(expectedFileDiff2, oldFileName2, file2, insertions2, deletions2);
expectedMessage2 = beginningOfMessage + fileDiff2 + fileDiff1;
String expectedChangeMessage2 = "Change has been successfully merged\n\n" + expectedMessage2;
expectedMessage1 += fileDiff2;
expectedChangeMessages.add(expectedChangeMessage2.trim());
}
String expectedChangeMessage1 = "Change has been successfully merged\n\n" + expectedMessage1;
expectedChangeMessage1 = expectedChangeMessage1.trim();
expectedChangeMessages.add(expectedChangeMessage1.trim());
// The order of appearance in the diff for multiple files is not defined, so check both
// possible orders.
assertThat(expectedChangeMessages).contains(message.trim());
String email = Iterables.getLast(sender.getMessages()).body();
if (email.contains(expectedMessage1) || expectedMessage2.isEmpty()) {
assertThat(email).contains(expectedMessage1.trim());
} else {
assertThat(email).contains(expectedMessage2.trim());
}
}
private String fileDiff(
String expectedFileDiff, String oldFileName, String file, int insertions, int deletions) {
String expectedMessage =
"```\n"
+ String.format("The name of the file: %s\n", file)
+ String.format("Insertions: %d, Deletions: %d.\n\n", insertions, deletions);
if (oldFileName != null) {
expectedMessage += String.format("The file %s was renamed to %s\n", oldFileName, file);
}
expectedMessage += expectedFileDiff;
expectedMessage += "\n```\n";
return expectedMessage;
}
}