2 * Copyright 2000-2014 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 import com.intellij.openapi.components.ServiceManager;
19 import com.intellij.openapi.util.Condition;
20 import com.intellij.openapi.util.text.StringUtil;
21 import com.intellij.openapi.vcs.VcsException;
22 import com.intellij.openapi.vfs.VirtualFile;
23 import com.intellij.util.ArrayUtil;
24 import com.intellij.util.CollectConsumer;
25 import com.intellij.util.Consumer;
26 import com.intellij.util.Function;
27 import com.intellij.util.containers.ContainerUtil;
28 import com.intellij.vcs.log.*;
29 import com.intellij.vcs.log.data.VcsLogBranchFilterImpl;
30 import com.intellij.vcs.log.impl.*;
31 import com.intellij.vcs.log.impl.VcsLogUserFilterImpl;
32 import com.intellij.vcsUtil.VcsFileUtil;
33 import git4idea.test.GitSingleRepoTest;
34 import git4idea.test.GitTestUtil;
35 import org.jetbrains.annotations.NotNull;
36 import org.jetbrains.annotations.Nullable;
38 import java.io.IOException;
39 import java.util.Collections;
40 import java.util.List;
43 import static git4idea.test.GitExecutor.*;
44 import static java.util.Collections.singleton;
46 public class GitLogProviderTest extends GitSingleRepoTest {
48 private GitLogProvider myLogProvider;
49 private VcsLogObjectsFactory myObjectsFactory;
51 public void setUp() throws Exception {
53 myLogProvider = GitTestUtil.findGitLogProvider(myProject);
54 myObjectsFactory = ServiceManager.getService(myProject, VcsLogObjectsFactory.class);
57 public void tearDown() throws Exception {
61 public void test_init_with_tagged_branch() throws VcsException {
63 List<VcsCommitMetadata> expectedLogWithoutTaggedBranch = log();
66 VcsLogProvider.DetailedLogData block = myLogProvider.readFirstBlock(myProjectRoot,new RequirementsImpl(1000, false, Collections.<VcsRef>emptySet()));
67 assertOrderedEquals(block.getCommits(), expectedLogWithoutTaggedBranch);
70 public void test_refresh_with_new_tagged_branch() throws VcsException {
72 Set<VcsRef> prevRefs = GitTestUtil.readAllRefs(myProjectRoot, myObjectsFactory);
75 List<VcsCommitMetadata> expectedLog = log();
76 VcsLogProvider.DetailedLogData block = myLogProvider.readFirstBlock(myProjectRoot, new RequirementsImpl(1000, true, prevRefs));
77 assertSameElements(block.getCommits(), expectedLog);
80 public void test_refresh_when_new_tag_moved() throws VcsException {
82 Set<VcsRef> prevRefs = GitTestUtil.readAllRefs(myProjectRoot, myObjectsFactory);
85 List<VcsCommitMetadata> expectedLog = log();
86 Set<VcsRef> refs = GitTestUtil.readAllRefs(myProjectRoot, myObjectsFactory);
87 VcsLogProvider.DetailedLogData block = myLogProvider.readFirstBlock(myProjectRoot, new RequirementsImpl(1000, true, prevRefs));
88 assertSameElements(block.getCommits(), expectedLog);
89 assertSameElements(block.getRefs(), refs);
92 public void test_new_tag_on_old_commit() throws VcsException {
94 Set<VcsRef> prevRefs = GitTestUtil.readAllRefs(myProjectRoot, myObjectsFactory);
95 List<VcsCommitMetadata> log = log();
96 String firstCommit = log.get(log.size() - 1).getId().asString();
97 git("tag NEW_TAG " + firstCommit);
99 Set<VcsRef> refs = GitTestUtil.readAllRefs(myProjectRoot, myObjectsFactory);
100 VcsLogProvider.DetailedLogData block = myLogProvider.readFirstBlock(myProjectRoot, new RequirementsImpl(1000, true, prevRefs));
101 assertSameElements(block.getRefs(), refs);
104 public void test_all_log_with_tagged_branch() throws VcsException {
105 prepareSomeHistory();
106 createTaggedBranch();
107 List<VcsCommitMetadata> expectedLog = log();
108 List<TimedVcsCommit> collector = ContainerUtil.newArrayList();
109 //noinspection unchecked
110 myLogProvider.readAllHashes(myProjectRoot, new CollectConsumer<>(collector));
111 assertOrderedEquals(expectedLog, collector);
114 public void test_get_current_user() throws Exception {
115 VcsUser user = myLogProvider.getCurrentUser(myProjectRoot);
116 assertNotNull("User is not defined", user);
117 VcsUser expected = getDefaultUser();
118 assertEquals("User name is incorrect", expected.getName(), user.getName());
119 assertEquals("User email is incorrect", expected.getEmail(), user.getEmail());
122 public void test_dont_report_origin_HEAD() throws Exception {
123 prepareSomeHistory();
124 git("update-ref refs/remotes/origin/HEAD master");
126 VcsLogProvider.DetailedLogData block = myLogProvider.readFirstBlock(myProjectRoot,
127 new RequirementsImpl(1000, false, Collections.<VcsRef>emptySet()));
128 assertFalse("origin/HEAD should be ignored", ContainerUtil.exists(block.getRefs(), ref -> ref.getName().equals("origin/HEAD")));
131 public void test_support_equally_named_branch_and_tag() throws Exception {
132 prepareSomeHistory();
136 VcsLogProvider.DetailedLogData data = myLogProvider.readFirstBlock(myProjectRoot,
137 new RequirementsImpl(1000, true, Collections.<VcsRef>emptySet()));
138 List<VcsCommitMetadata> expectedLog = log();
139 assertOrderedEquals(data.getCommits(), expectedLog);
140 assertTrue(ContainerUtil.exists(data.getRefs(), ref -> ref.getName().equals("build") && ref.getType() == GitRefManager.LOCAL_BRANCH));
141 assertTrue(ContainerUtil.exists(data.getRefs(), ref -> ref.getName().equals("build") && ref.getType() == GitRefManager.TAG));
144 public void test_filter_by_branch() throws Exception {
145 List<String> hashes = generateHistoryForFilters(true);
146 VcsLogBranchFilter branchFilter = VcsLogBranchFilterImpl.fromBranch("feature");
147 List<String> actualHashes = getFilteredHashes(branchFilter, null);
148 assertEquals(hashes, actualHashes);
151 public void test_filter_by_branch_and_user() throws Exception {
152 List<String> hashes = generateHistoryForFilters(false);
153 VcsLogBranchFilter branchFilter = VcsLogBranchFilterImpl.fromBranch("feature");
154 VcsUserImpl user = new VcsUserImpl(GitTestUtil.USER_NAME, GitTestUtil.USER_EMAIL);
155 VcsLogUserFilter userFilter = new VcsLogUserFilterImpl(singleton(GitTestUtil.USER_NAME),
156 Collections.emptyMap(),
158 List<String> actualHashes = getFilteredHashes(branchFilter, userFilter);
159 assertEquals(hashes, actualHashes);
162 public void test_short_details() throws Exception {
163 prepareLongHistory(VcsFileUtil.FILE_PATH_LIMIT * 2 / 40);
164 List<VcsCommitMetadata> log = log();
166 final List<String> hashes = ContainerUtil.newArrayList();
167 myLogProvider.readAllHashes(myProjectRoot, timedVcsCommit -> hashes.add(timedVcsCommit.getId().asString()));
169 List<? extends VcsShortCommitDetails> shortDetails = myLogProvider.readShortDetails(myProjectRoot, hashes);
171 Function<VcsShortCommitDetails, String> shortDetailsToString = getShortDetailsToString();
172 assertOrderedEquals(ContainerUtil.map(shortDetails, shortDetailsToString), ContainerUtil.map(log, shortDetailsToString));
175 public void test_full_details() throws Exception {
176 prepareLongHistory(VcsFileUtil.FILE_PATH_LIMIT * 2 / 40);
177 List<VcsCommitMetadata> log = log();
179 final List<String> hashes = ContainerUtil.newArrayList();
180 myLogProvider.readAllHashes(myProjectRoot, timedVcsCommit -> hashes.add(timedVcsCommit.getId().asString()));
182 List<? extends VcsFullCommitDetails> fullDetails = myLogProvider.readFullDetails(myProjectRoot, hashes);
184 // we do not check for changes here
185 final Function<VcsShortCommitDetails, String> shortDetailsToString = getShortDetailsToString();
186 Function<VcsCommitMetadata, String> metadataToString = details -> shortDetailsToString.fun(details) + "\n" + details.getFullMessage();
187 assertOrderedEquals(ContainerUtil.map(fullDetails, metadataToString), ContainerUtil.map(log, metadataToString));
191 private Function<VcsShortCommitDetails, String> getShortDetailsToString() {
195 result += details.getId().toShortString() + "\n";
196 result += details.getAuthorTime() + "\n";
197 result += details.getAuthor() + "\n";
198 result += details.getCommitTime() + "\n";
199 result += details.getCommitter() + "\n";
200 result += details.getSubject();
207 * Generates some history with two branches: master and feature, and made by two users.
208 * Returns hashes of this history filtered by the given parameters:
209 * @param takeAllUsers if true, don't filter by users, otherwise filter by default user.
211 private List<String> generateHistoryForFilters(boolean takeAllUsers) {
212 List<String> hashes = ContainerUtil.newArrayList();
215 GitTestUtil.setupUsername("bob.smith", "bob.smith@example.com");
217 String commitByBob = tac("file.txt");
218 hashes.add(commitByBob);
220 GitTestUtil.setupDefaultUsername();
222 hashes.add(tac("file1.txt"));
223 git("checkout -b feature");
224 String commitOnlyInFeature = tac("file2.txt");
225 hashes.add(commitOnlyInFeature);
226 git("checkout master");
227 String commitOnlyInMaster = tac("master.txt");
229 Collections.reverse(hashes);
235 private List<String> getFilteredHashes(@Nullable VcsLogBranchFilter branchFilter,
236 @Nullable VcsLogUserFilter userFilter) throws VcsException {
237 VcsLogFilterCollectionImpl filters = new VcsLogFilterCollectionImpl(branchFilter, userFilter, null, null, null, null, null);
238 List<TimedVcsCommit> commits = myLogProvider.getCommitsMatchingFilter(myProjectRoot, filters, -1);
239 return ContainerUtil.map(commits, commit -> commit.getId().asString());
242 private static void prepareSomeHistory() {
248 private static void prepareLongHistory(int size) throws IOException {
249 for (int i = 0; i < size; i++) {
250 String file = "a" + (i % 10) + ".txt";
260 private static void createTaggedBranch() {
261 String hash = last();
266 git("reset --hard " + hash);
270 private static VcsUser getDefaultUser() {
271 return new VcsUserImpl(GitTestUtil.USER_NAME, GitTestUtil.USER_EMAIL);
275 private List<VcsCommitMetadata> log() {
276 String output = git("log --all --date-order --full-history --sparse --pretty='%H|%P|%ct|%s|%B'");
277 final VcsUser defaultUser = getDefaultUser();
278 final Function<String, Hash> TO_HASH = s -> HashImpl.build(s);
279 return ContainerUtil.map(StringUtil.splitByLines(output), record -> {
280 String[] items = ArrayUtil.toStringArray(StringUtil.split(record, "|", true, false));
281 long time = Long.valueOf(items[2]) * 1000;
282 return new VcsCommitMetadataImpl(TO_HASH.fun(items[0]), ContainerUtil.map(items[1].split(" "), TO_HASH), time,
283 myProjectRoot, items[3], defaultUser, items[4], defaultUser, time);