// 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.gerrit.server.edit.tree.TreeModificationSubject.assertThatList;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.replay;

import com.google.common.collect.ImmutableList;
import com.google.gerrit.extensions.restapi.BinaryResult;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.reviewdb.client.Comment.Range;
import com.google.gerrit.reviewdb.client.FixReplacement;
import com.google.gerrit.server.change.FileContentUtil;
import com.google.gerrit.server.edit.tree.TreeModification;
import com.google.gerrit.server.project.ProjectState;
import com.google.gerrit.testing.GerritBaseTests;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import org.easymock.EasyMock;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
import org.junit.Before;
import org.junit.Test;

public class FixReplacementInterpreterTest extends GerritBaseTests {
  private final FileContentUtil fileContentUtil = createMock(FileContentUtil.class);
  private final Repository repository = createMock(Repository.class);
  private final ProjectState projectState = createMock(ProjectState.class);
  private final ObjectId patchSetCommitId = createMock(ObjectId.class);
  private final String filePath1 = "an/arbitrary/file.txt";
  private final String filePath2 = "another/arbitrary/file.txt";

  private FixReplacementInterpreter fixReplacementInterpreter;

  @Before
  public void setUp() {
    fixReplacementInterpreter = new FixReplacementInterpreter(fileContentUtil);
  }

  @Test
  public void noReplacementsResultInNoTreeModifications() throws Exception {
    List<TreeModification> treeModifications = toTreeModifications();
    assertThatList(treeModifications).isEmpty();
  }

  @Test
  public void treeModificationsTargetCorrectFiles() throws Exception {
    FixReplacement fixReplacement =
        new FixReplacement(filePath1, new Range(1, 6, 3, 2), "Modified content");
    FixReplacement fixReplacement2 =
        new FixReplacement(filePath1, new Range(3, 5, 3, 5), "Second modification");
    mockFileContent(filePath1, "First line\nSecond line\nThird line\n");
    FixReplacement fixReplacement3 =
        new FixReplacement(filePath2, new Range(2, 0, 3, 0), "Another modified content");
    mockFileContent(filePath2, "1st line\n2nd line\n3rd line\n");

    replay(fileContentUtil);
    List<TreeModification> treeModifications =
        toTreeModifications(fixReplacement, fixReplacement3, fixReplacement2);
    List<TreeModification> sortedTreeModifications = getSortedCopy(treeModifications);
    assertThatList(sortedTreeModifications)
        .element(0)
        .asChangeFileContentModification()
        .filePath()
        .isEqualTo(filePath1);
    assertThatList(sortedTreeModifications)
        .element(0)
        .asChangeFileContentModification()
        .newContent()
        .startsWith("First");
    assertThatList(sortedTreeModifications)
        .element(1)
        .asChangeFileContentModification()
        .filePath()
        .isEqualTo(filePath2);
    assertThatList(sortedTreeModifications)
        .element(1)
        .asChangeFileContentModification()
        .newContent()
        .startsWith("1st");
  }

  @Test
  public void replacementsCanDeleteALine() throws Exception {
    FixReplacement fixReplacement = new FixReplacement(filePath1, new Range(2, 0, 3, 0), "");
    mockFileContent(filePath1, "First line\nSecond line\nThird line\n");

    replay(fileContentUtil);
    List<TreeModification> treeModifications = toTreeModifications(fixReplacement);
    assertThatList(treeModifications)
        .onlyElement()
        .asChangeFileContentModification()
        .newContent()
        .isEqualTo("First line\nThird line\n");
  }

  @Test
  public void replacementsCanAddALine() throws Exception {
    FixReplacement fixReplacement =
        new FixReplacement(filePath1, new Range(2, 0, 2, 0), "A new line\n");
    mockFileContent(filePath1, "First line\nSecond line\nThird line\n");

    replay(fileContentUtil);
    List<TreeModification> treeModifications = toTreeModifications(fixReplacement);
    assertThatList(treeModifications)
        .onlyElement()
        .asChangeFileContentModification()
        .newContent()
        .isEqualTo("First line\nA new line\nSecond line\nThird line\n");
  }

  @Test
  public void replacementsMaySpanMultipleLines() throws Exception {
    FixReplacement fixReplacement = new FixReplacement(filePath1, new Range(1, 6, 3, 1), "and t");
    mockFileContent(filePath1, "First line\nSecond line\nThird line\n");

    replay(fileContentUtil);
    List<TreeModification> treeModifications = toTreeModifications(fixReplacement);
    assertThatList(treeModifications)
        .onlyElement()
        .asChangeFileContentModification()
        .newContent()
        .isEqualTo("First and third line\n");
  }

  @Test
  public void replacementsMayOccurOnSameLine() throws Exception {
    FixReplacement fixReplacement1 = new FixReplacement(filePath1, new Range(2, 0, 2, 6), "A");
    FixReplacement fixReplacement2 =
        new FixReplacement(filePath1, new Range(2, 7, 2, 11), "modification");
    mockFileContent(filePath1, "First line\nSecond line\nThird line\n");

    replay(fileContentUtil);
    List<TreeModification> treeModifications =
        toTreeModifications(fixReplacement1, fixReplacement2);
    assertThatList(treeModifications)
        .onlyElement()
        .asChangeFileContentModification()
        .newContent()
        .isEqualTo("First line\nA modification\nThird line\n");
  }

  @Test
  public void replacementsMayTouch() throws Exception {
    FixReplacement fixReplacement1 =
        new FixReplacement(filePath1, new Range(1, 6, 2, 7), "modified ");
    FixReplacement fixReplacement2 =
        new FixReplacement(filePath1, new Range(2, 7, 3, 5), "content");
    mockFileContent(filePath1, "First line\nSecond line\nThird line\n");

    replay(fileContentUtil);
    List<TreeModification> treeModifications =
        toTreeModifications(fixReplacement1, fixReplacement2);
    assertThatList(treeModifications)
        .onlyElement()
        .asChangeFileContentModification()
        .newContent()
        .isEqualTo("First modified content line\n");
  }

  @Test
  public void replacementsCanAddContentAtEndOfFile() throws Exception {
    FixReplacement fixReplacement =
        new FixReplacement(filePath1, new Range(4, 0, 4, 0), "New content");
    mockFileContent(filePath1, "First line\nSecond line\nThird line\n");

    replay(fileContentUtil);
    List<TreeModification> treeModifications = toTreeModifications(fixReplacement);
    assertThatList(treeModifications)
        .onlyElement()
        .asChangeFileContentModification()
        .newContent()
        .isEqualTo("First line\nSecond line\nThird line\nNew content");
  }

  @Test
  public void replacementsCanModifySeveralFilesInAnyOrder() throws Exception {
    FixReplacement fixReplacement1 =
        new FixReplacement(filePath1, new Range(1, 1, 3, 2), "Modified content");
    mockFileContent(filePath1, "First line\nSecond line\nThird line\n");
    FixReplacement fixReplacement2 =
        new FixReplacement(filePath2, new Range(2, 0, 3, 0), "First modification\n");
    FixReplacement fixReplacement3 =
        new FixReplacement(filePath2, new Range(3, 0, 4, 0), "Second modification\n");
    mockFileContent(filePath2, "1st line\n2nd line\n3rd line\n");

    replay(fileContentUtil);
    List<TreeModification> treeModifications =
        toTreeModifications(fixReplacement3, fixReplacement1, fixReplacement2);
    List<TreeModification> sortedTreeModifications = getSortedCopy(treeModifications);
    assertThatList(sortedTreeModifications)
        .element(0)
        .asChangeFileContentModification()
        .newContent()
        .isEqualTo("FModified contentird line\n");
    assertThatList(sortedTreeModifications)
        .element(1)
        .asChangeFileContentModification()
        .newContent()
        .isEqualTo("1st line\nFirst modification\nSecond modification\n");
  }

  @Test
  public void lineSeparatorCanBeChanged() throws Exception {
    FixReplacement fixReplacement = new FixReplacement(filePath1, new Range(2, 11, 3, 0), "\r");
    mockFileContent(filePath1, "First line\nSecond line\nThird line\n");

    replay(fileContentUtil);
    List<TreeModification> treeModifications = toTreeModifications(fixReplacement);
    assertThatList(treeModifications)
        .onlyElement()
        .asChangeFileContentModification()
        .newContent()
        .isEqualTo("First line\nSecond line\rThird line\n");
  }

  @Test
  public void replacementsDoNotNeedToBeOrderedAccordingToRange() throws Exception {
    FixReplacement fixReplacement1 =
        new FixReplacement(filePath1, new Range(1, 0, 2, 0), "1st modification\n");
    FixReplacement fixReplacement2 =
        new FixReplacement(filePath1, new Range(3, 0, 4, 0), "2nd modification\n");
    FixReplacement fixReplacement3 =
        new FixReplacement(filePath1, new Range(4, 0, 5, 0), "3rd modification\n");
    mockFileContent(filePath1, "First line\nSecond line\nThird line\nFourth line\nFifth line\n");

    replay(fileContentUtil);
    List<TreeModification> treeModifications =
        toTreeModifications(fixReplacement2, fixReplacement1, fixReplacement3);
    assertThatList(treeModifications)
        .onlyElement()
        .asChangeFileContentModification()
        .newContent()
        .isEqualTo(
            "1st modification\nSecond line\n2nd modification\n3rd modification\nFifth line\n");
  }

  @Test
  public void replacementsMustNotReferToNotExistingLine() throws Exception {
    FixReplacement fixReplacement =
        new FixReplacement(filePath1, new Range(5, 0, 5, 0), "A new line\n");
    mockFileContent(filePath1, "First line\nSecond line\nThird line\n");

    replay(fileContentUtil);

    exception.expect(ResourceConflictException.class);
    toTreeModifications(fixReplacement);
  }

  @Test
  public void replacementsMustNotReferToZeroLine() throws Exception {
    FixReplacement fixReplacement =
        new FixReplacement(filePath1, new Range(0, 0, 0, 0), "A new line\n");
    mockFileContent(filePath1, "First line\nSecond line\nThird line\n");

    replay(fileContentUtil);

    exception.expect(ResourceConflictException.class);
    toTreeModifications(fixReplacement);
  }

  @Test
  public void replacementsMustNotReferToNotExistingOffsetOfIntermediateLine() throws Exception {
    FixReplacement fixReplacement =
        new FixReplacement(filePath1, new Range(1, 0, 1, 11), "modified");
    mockFileContent(filePath1, "First line\nSecond line\nThird line\n");

    replay(fileContentUtil);

    exception.expect(ResourceConflictException.class);
    toTreeModifications(fixReplacement);
  }

  @Test
  public void replacementsMustNotReferToNotExistingOffsetOfLastLine() throws Exception {
    FixReplacement fixReplacement =
        new FixReplacement(filePath1, new Range(3, 0, 3, 11), "modified");
    mockFileContent(filePath1, "First line\nSecond line\nThird line\n");

    replay(fileContentUtil);

    exception.expect(ResourceConflictException.class);
    toTreeModifications(fixReplacement);
  }

  @Test
  public void replacementsMustNotReferToNegativeOffset() throws Exception {
    FixReplacement fixReplacement =
        new FixReplacement(filePath1, new Range(1, -1, 1, 5), "modified");
    mockFileContent(filePath1, "First line\nSecond line\nThird line\n");

    replay(fileContentUtil);

    exception.expect(ResourceConflictException.class);
    toTreeModifications(fixReplacement);
  }

  private void mockFileContent(String filePath, String fileContent) throws Exception {
    EasyMock.expect(
            fileContentUtil.getContent(repository, projectState, patchSetCommitId, filePath))
        .andReturn(BinaryResult.create(fileContent));
  }

  private List<TreeModification> toTreeModifications(FixReplacement... fixReplacements)
      throws Exception {
    return fixReplacementInterpreter.toTreeModifications(
        repository, projectState, patchSetCommitId, ImmutableList.copyOf(fixReplacements));
  }

  private static List<TreeModification> getSortedCopy(List<TreeModification> treeModifications) {
    List<TreeModification> sortedTreeModifications = new ArrayList<>(treeModifications);
    sortedTreeModifications.sort(Comparator.comparing(TreeModification::getFilePath));
    return sortedTreeModifications;
  }
}
