| // Copyright (C) 2020 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.truth.Truth.assertThat; |
| |
| import com.google.gerrit.entities.Project; |
| import com.google.gerrit.server.git.GitRepositoryManager; |
| import com.google.gerrit.testing.InMemoryRepositoryManager; |
| import java.time.Instant; |
| import java.time.LocalDateTime; |
| import java.time.Month; |
| import java.time.ZoneOffset; |
| import java.util.Date; |
| import java.util.TimeZone; |
| import org.eclipse.jgit.junit.TestRepository; |
| import org.eclipse.jgit.lib.ObjectId; |
| import org.eclipse.jgit.lib.ObjectReader; |
| import org.eclipse.jgit.lib.PersonIdent; |
| import org.eclipse.jgit.lib.Repository; |
| import org.eclipse.jgit.revwalk.RevCommit; |
| import org.junit.Test; |
| |
| public class MagicFileTest { |
| |
| private final GitRepositoryManager repositoryManager = new InMemoryRepositoryManager(); |
| |
| @Test |
| public void magicFileContentIsBuiltCorrectly() { |
| MagicFile magicFile = |
| MagicFile.builder() |
| .generatedContent("Generated 1\n") |
| .modifiableContent("Modifiable 1\n") |
| .build(); |
| |
| assertThat(magicFile.getFileContent()).isEqualTo("Generated 1\nModifiable 1\n"); |
| } |
| |
| @Test |
| public void generatedContentMayBeEmpty() { |
| MagicFile magicFile = MagicFile.builder().modifiableContent("Modifiable 1\n").build(); |
| |
| assertThat(magicFile.getFileContent()).isEqualTo("Modifiable 1\n"); |
| } |
| |
| @Test |
| public void modifiableContentMayBeEmpty() { |
| MagicFile magicFile = MagicFile.builder().generatedContent("Generated 1\n").build(); |
| |
| assertThat(magicFile.getFileContent()).isEqualTo("Generated 1\n"); |
| } |
| |
| @Test |
| public void generatedContentAlwaysHasNewlineAtEnd() { |
| MagicFile magicFile = MagicFile.builder().generatedContent("Generated 1").build(); |
| |
| assertThat(magicFile.generatedContent()).isEqualTo("Generated 1\n"); |
| } |
| |
| @Test |
| public void modifiableContentAlwaysHasNewlineAtEnd() { |
| MagicFile magicFile = MagicFile.builder().modifiableContent("Modifiable 1").build(); |
| |
| assertThat(magicFile.modifiableContent()).isEqualTo("Modifiable 1\n"); |
| } |
| |
| @Test |
| public void startOfModifiableContentIsIndicatedCorrectlyWhenGeneratedContentIsPresent() { |
| MagicFile magicFile = |
| MagicFile.builder() |
| .generatedContent("Line 1\nLine2\n") |
| .modifiableContent("Line 3\n") |
| .build(); |
| |
| // Generated content. -> Modifiable content starts in line 3. |
| assertThat(magicFile.getStartLineOfModifiableContent()).isEqualTo(3); |
| } |
| |
| @Test |
| public void startOfModifiableContentIsIndicatedCorrectlyWhenGeneratedContentIsEmpty() { |
| MagicFile magicFile = MagicFile.builder().modifiableContent("Line 1\n").build(); |
| |
| assertThat(magicFile.getStartLineOfModifiableContent()).isEqualTo(1); |
| } |
| |
| @Test |
| public void commitMessageFileOfRootCommitContainsCorrectContent() throws Exception { |
| try (Repository repository = repositoryManager.createRepository(Project.nameKey("repo1")); |
| TestRepository<Repository> testRepo = new TestRepository<>(repository); |
| ObjectReader objectReader = repository.newObjectReader()) { |
| |
| Instant authorTime = |
| LocalDateTime.of(2020, Month.APRIL, 23, 19, 30, 27).atZone(ZoneOffset.UTC).toInstant(); |
| PersonIdent author = |
| new PersonIdent( |
| "Alfred", |
| "alfred@example.com", |
| Date.from(authorTime), |
| TimeZone.getTimeZone(ZoneOffset.UTC)); |
| |
| Instant committerTime = |
| LocalDateTime.of(2021, Month.JANUARY, 6, 5, 12, 55).atZone(ZoneOffset.UTC).toInstant(); |
| PersonIdent committer = |
| new PersonIdent( |
| "Luise", |
| "luise@example.com", |
| Date.from(committerTime), |
| TimeZone.getTimeZone(ZoneOffset.UTC)); |
| |
| ObjectId commit = |
| testRepo |
| .commit() |
| .message("Subject line\n\nFurther explanations.\n") |
| .author(author) |
| .committer(committer) |
| .noParents() |
| .create(); |
| |
| MagicFile commitMessageFile = MagicFile.forCommitMessage(objectReader, commit); |
| |
| // The content of the commit message file must not change over time as existing comments |
| // would otherwise refer to different content than when they were originally left. |
| // -> Keep this format stable over time. |
| assertThat(commitMessageFile.getFileContent()) |
| .isEqualTo( |
| "Author: Alfred <alfred@example.com>\n" |
| + "AuthorDate: 2020-04-23 19:30:27 +0000\n" |
| + "Commit: Luise <luise@example.com>\n" |
| + "CommitDate: 2021-01-06 05:12:55 +0000\n" |
| + "\n" |
| + "Subject line\n" |
| + "\n" |
| + "Further explanations.\n"); |
| } |
| } |
| |
| @Test |
| public void commitMessageFileOfNonMergeCommitContainsCorrectContent() throws Exception { |
| try (Repository repository = repositoryManager.createRepository(Project.nameKey("repo1")); |
| TestRepository<Repository> testRepo = new TestRepository<>(repository); |
| ObjectReader objectReader = repository.newObjectReader()) { |
| |
| Instant authorTime = |
| LocalDateTime.of(2020, Month.APRIL, 23, 19, 30, 27).atZone(ZoneOffset.UTC).toInstant(); |
| PersonIdent author = |
| new PersonIdent( |
| "Alfred", |
| "alfred@example.com", |
| Date.from(authorTime), |
| TimeZone.getTimeZone(ZoneOffset.UTC)); |
| |
| Instant committerTime = |
| LocalDateTime.of(2021, Month.JANUARY, 6, 5, 12, 55).atZone(ZoneOffset.UTC).toInstant(); |
| PersonIdent committer = |
| new PersonIdent( |
| "Luise", |
| "luise@example.com", |
| Date.from(committerTime), |
| TimeZone.getTimeZone(ZoneOffset.UTC)); |
| |
| RevCommit parent = |
| testRepo.commit().message("Parent subject\n\nParent further details.").create(); |
| ObjectId commit = |
| testRepo |
| .commit() |
| .message("Subject line\n\nFurther explanations.\n") |
| .author(author) |
| .committer(committer) |
| .parent(parent) |
| .create(); |
| |
| MagicFile commitMessageFile = MagicFile.forCommitMessage(objectReader, commit); |
| |
| // The content of the commit message file must not change over time as existing comments |
| // would otherwise refer to different content than when they were originally left. |
| // -> Keep this format stable over time. |
| assertThat(commitMessageFile.getFileContent()) |
| .isEqualTo( |
| String.format( |
| "Parent: %s (Parent subject)\n" |
| + "Author: Alfred <alfred@example.com>\n" |
| + "AuthorDate: 2020-04-23 19:30:27 +0000\n" |
| + "Commit: Luise <luise@example.com>\n" |
| + "CommitDate: 2021-01-06 05:12:55 +0000\n" |
| + "\n" |
| + "Subject line\n" |
| + "\n" |
| + "Further explanations.\n", |
| parent.name().substring(0, 8))); |
| } |
| } |
| |
| @Test |
| public void commitMessageFileOfMergeCommitContainsCorrectContent() throws Exception { |
| try (Repository repository = repositoryManager.createRepository(Project.nameKey("repo1")); |
| TestRepository<Repository> testRepo = new TestRepository<>(repository); |
| ObjectReader objectReader = repository.newObjectReader()) { |
| |
| Instant authorTime = |
| LocalDateTime.of(2020, Month.APRIL, 23, 19, 30, 27).atZone(ZoneOffset.UTC).toInstant(); |
| PersonIdent author = |
| new PersonIdent( |
| "Alfred", |
| "alfred@example.com", |
| Date.from(authorTime), |
| TimeZone.getTimeZone(ZoneOffset.UTC)); |
| |
| Instant committerTime = |
| LocalDateTime.of(2021, Month.JANUARY, 6, 5, 12, 55).atZone(ZoneOffset.UTC).toInstant(); |
| PersonIdent committer = |
| new PersonIdent( |
| "Luise", |
| "luise@example.com", |
| Date.from(committerTime), |
| TimeZone.getTimeZone(ZoneOffset.UTC)); |
| |
| RevCommit parent1 = testRepo.commit().message("Parent 1\n\nExplanation 1.").create(); |
| RevCommit parent2 = testRepo.commit().message("Parent 2\n\nExplanation 2.").create(); |
| ObjectId commit = |
| testRepo |
| .commit() |
| .message("Subject line\n\nFurther explanations.\n") |
| .author(author) |
| .committer(committer) |
| .parent(parent1) |
| .parent(parent2) |
| .create(); |
| |
| MagicFile commitMessageFile = MagicFile.forCommitMessage(objectReader, commit); |
| |
| // The content of the commit message file must not change over time as existing comments |
| // would otherwise refer to different content than when they were originally left. |
| // -> Keep this format stable over time. |
| String expectedContent = |
| String.format( |
| "Merge Of: %s (Parent 1)\n" |
| + " %s (Parent 2)\n" |
| + "Author: Alfred <alfred@example.com>\n" |
| + "AuthorDate: 2020-04-23 19:30:27 +0000\n" |
| + "Commit: Luise <luise@example.com>\n" |
| + "CommitDate: 2021-01-06 05:12:55 +0000\n" |
| + "\n" |
| + "Subject line\n" |
| + "\n" |
| + "Further explanations.\n", |
| parent1.name().substring(0, 8), parent2.name().substring(0, 8)); |
| assertThat(commitMessageFile.getFileContent()).isEqualTo(expectedContent); |
| } |
| } |
| |
| @Test |
| public void commitMessageFileEndsWithEmptyLineIfCommitMessageIsEmpty() throws Exception { |
| try (Repository repository = repositoryManager.createRepository(Project.nameKey("myRepo")); |
| TestRepository<Repository> testRepo = new TestRepository<>(repository); |
| ObjectReader objectReader = repository.newObjectReader()) { |
| RevCommit commit = testRepo.commit().message("").create(); |
| |
| MagicFile commitMessageFile = MagicFile.forCommitMessage(objectReader, commit); |
| assertThat(commitMessageFile.getFileContent()).endsWith("\n\n"); |
| } |
| } |
| |
| @Test |
| public void commitMessageFileContainsFullCommitMessageAsModifiablePart() throws Exception { |
| try (Repository repository = repositoryManager.createRepository(Project.nameKey("myRepo")); |
| TestRepository<Repository> testRepo = new TestRepository<>(repository); |
| ObjectReader objectReader = repository.newObjectReader()) { |
| RevCommit commit = |
| testRepo.commit().message("Subject line\n\nFurther explanations.\n").create(); |
| |
| MagicFile commitMessageFile = MagicFile.forCommitMessage(objectReader, commit); |
| assertThat(commitMessageFile.modifiableContent()) |
| .isEqualTo("Subject line\n\nFurther explanations.\n"); |
| } |
| } |
| |
| @Test |
| public void mergeListFileContainsCorrectContentForDiffAgainstFirstParent() throws Exception { |
| try (Repository repository = repositoryManager.createRepository(Project.nameKey("myRepo")); |
| TestRepository<Repository> testRepo = new TestRepository<>(repository); |
| ObjectReader objectReader = repository.newObjectReader()) { |
| RevCommit parent1 = testRepo.commit().message("Parent 1\n\nExplanation 1.").create(); |
| RevCommit parent2 = testRepo.commit().message("Parent 2\n\nExplanation 2.").create(); |
| ObjectId commit = testRepo.commit().parent(parent1).parent(parent2).create(); |
| |
| MagicFile mergeListFile = |
| MagicFile.forMergeList(ComparisonType.againstParent(1), objectReader, commit); |
| |
| // The content of the merge list file must not change over time as existing comments |
| // would otherwise refer to different content than when they were originally left. |
| // -> Keep this format stable over time. |
| String expectedContent = |
| String.format("Merge List:\n\n* %s Parent 2\n", parent2.name().substring(0, 8)); |
| assertThat(mergeListFile.getFileContent()).isEqualTo(expectedContent); |
| } |
| } |
| |
| @Test |
| public void mergeListFileContainsCorrectContentForDiffAgainstSecondParent() throws Exception { |
| try (Repository repository = repositoryManager.createRepository(Project.nameKey("myRepo")); |
| TestRepository<Repository> testRepo = new TestRepository<>(repository); |
| ObjectReader objectReader = repository.newObjectReader()) { |
| RevCommit parent1 = testRepo.commit().message("Parent 1\n\nExplanation 1.").create(); |
| RevCommit parent2 = testRepo.commit().message("Parent 2\n\nExplanation 2.").create(); |
| ObjectId commit = testRepo.commit().parent(parent1).parent(parent2).create(); |
| |
| MagicFile mergeListFile = |
| MagicFile.forMergeList(ComparisonType.againstParent(2), objectReader, commit); |
| |
| // The content of the merge list file must not change over time as existing comments |
| // would otherwise refer to different content than when they were originally left. |
| // -> Keep this format stable over time. |
| String expectedContent = |
| String.format("Merge List:\n\n* %s Parent 1\n", parent1.name().substring(0, 8)); |
| assertThat(mergeListFile.getFileContent()).isEqualTo(expectedContent); |
| } |
| } |
| |
| @Test |
| public void mergeListFileContainsCorrectContentForDiffAgainstAutoMerge() throws Exception { |
| try (Repository repository = repositoryManager.createRepository(Project.nameKey("myRepo")); |
| TestRepository<Repository> testRepo = new TestRepository<>(repository); |
| ObjectReader objectReader = repository.newObjectReader()) { |
| RevCommit parent1 = testRepo.commit().message("Parent 1\n\nExplanation 1.").create(); |
| RevCommit parent2 = testRepo.commit().message("Parent 2\n\nExplanation 2.").create(); |
| ObjectId commit = testRepo.commit().parent(parent1).parent(parent2).create(); |
| |
| MagicFile mergeListFile = |
| MagicFile.forMergeList(ComparisonType.againstAutoMerge(), objectReader, commit); |
| |
| // When auto-merge is chosen, we fall back to the diff against the first parent. |
| String expectedContent = |
| String.format("Merge List:\n\n* %s Parent 2\n", parent2.name().substring(0, 8)); |
| assertThat(mergeListFile.getFileContent()).isEqualTo(expectedContent); |
| } |
| } |
| |
| @Test |
| public void mergeListFileIsEmptyForRootCommit() throws Exception { |
| try (Repository repository = repositoryManager.createRepository(Project.nameKey("myRepo")); |
| TestRepository<Repository> testRepo = new TestRepository<>(repository); |
| ObjectReader objectReader = repository.newObjectReader()) { |
| ObjectId commit = testRepo.commit().noParents().create(); |
| |
| MagicFile mergeListFile = |
| MagicFile.forMergeList(ComparisonType.againstParent(1), objectReader, commit); |
| |
| assertThat(mergeListFile.getFileContent()).isEmpty(); |
| } |
| } |
| |
| @Test |
| public void mergeListFileIsEmptyForNonMergeCommit() throws Exception { |
| try (Repository repository = repositoryManager.createRepository(Project.nameKey("myRepo")); |
| TestRepository<Repository> testRepo = new TestRepository<>(repository); |
| ObjectReader objectReader = repository.newObjectReader()) { |
| RevCommit parent = testRepo.commit().message("Parent 1\n").create(); |
| ObjectId commit = testRepo.commit().parent(parent).create(); |
| |
| MagicFile mergeListFile = |
| MagicFile.forMergeList(ComparisonType.againstParent(1), objectReader, commit); |
| |
| assertThat(mergeListFile.getFileContent()).isEmpty(); |
| } |
| } |
| |
| @Test |
| public void mergeListFileDoesNotHaveAModifiablePart() throws Exception { |
| try (Repository repository = repositoryManager.createRepository(Project.nameKey("myRepo")); |
| TestRepository<Repository> testRepo = new TestRepository<>(repository); |
| ObjectReader objectReader = repository.newObjectReader()) { |
| RevCommit parent1 = testRepo.commit().message("Parent 1\n").create(); |
| RevCommit parent2 = testRepo.commit().message("Parent 2\n").create(); |
| ObjectId commit = testRepo.commit().parent(parent1).parent(parent2).create(); |
| |
| MagicFile mergeListFile = |
| MagicFile.forMergeList(ComparisonType.againstParent(1), objectReader, commit); |
| |
| // Nothing in the merge list file represents something users may modify. |
| assertThat(mergeListFile.modifiableContent()).isEmpty(); |
| } |
| } |
| } |