[git] fix branch and user test
[idea/community.git] / plugins / git4idea / tests / git4idea / log / GitLogProviderTest.java
1 /*
2  * Copyright 2000-2014 JetBrains s.r.o.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 package git4idea.log;
17
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;
37
38 import java.io.IOException;
39 import java.util.Collections;
40 import java.util.List;
41 import java.util.Set;
42
43 import static git4idea.test.GitExecutor.*;
44 import static java.util.Collections.singleton;
45
46 public class GitLogProviderTest extends GitSingleRepoTest {
47
48   private GitLogProvider myLogProvider;
49   private VcsLogObjectsFactory myObjectsFactory;
50
51   public void setUp() throws Exception {
52     super.setUp();
53     myLogProvider = GitTestUtil.findGitLogProvider(myProject);
54     myObjectsFactory = ServiceManager.getService(myProject, VcsLogObjectsFactory.class);
55   }
56
57   public void tearDown() throws Exception {
58     super.tearDown();
59   }
60
61   public void test_init_with_tagged_branch() throws VcsException {
62     prepareSomeHistory();
63     List<VcsCommitMetadata> expectedLogWithoutTaggedBranch = log();
64     createTaggedBranch();
65
66     VcsLogProvider.DetailedLogData block = myLogProvider.readFirstBlock(myProjectRoot,new RequirementsImpl(1000, false, Collections.<VcsRef>emptySet()));
67     assertOrderedEquals(block.getCommits(), expectedLogWithoutTaggedBranch);
68   }
69
70   public void test_refresh_with_new_tagged_branch() throws VcsException {
71     prepareSomeHistory();
72     Set<VcsRef> prevRefs = GitTestUtil.readAllRefs(myProjectRoot, myObjectsFactory);
73     createTaggedBranch();
74
75     List<VcsCommitMetadata> expectedLog = log();
76     VcsLogProvider.DetailedLogData block = myLogProvider.readFirstBlock(myProjectRoot, new RequirementsImpl(1000, true, prevRefs));
77     assertSameElements(block.getCommits(), expectedLog);
78   }
79
80   public void test_refresh_when_new_tag_moved() throws VcsException {
81     prepareSomeHistory();
82     Set<VcsRef> prevRefs = GitTestUtil.readAllRefs(myProjectRoot, myObjectsFactory);
83     git("tag -f ATAG");
84
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);
90   }
91
92   public void test_new_tag_on_old_commit() throws VcsException {
93     prepareSomeHistory();
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);
98
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);
102   }
103
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);
112   }
113
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());
120   }
121
122   public void test_dont_report_origin_HEAD() throws Exception {
123     prepareSomeHistory();
124     git("update-ref refs/remotes/origin/HEAD master");
125
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")));
129   }
130
131   public void test_support_equally_named_branch_and_tag() throws Exception {
132     prepareSomeHistory();
133     git("branch build");
134     git("tag build");
135
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));
142   }
143
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);
149   }
150
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(),
157                                                            singleton(user));
158     List<String> actualHashes = getFilteredHashes(branchFilter, userFilter);
159     assertEquals(hashes, actualHashes);
160   }
161
162   public void test_short_details() throws Exception {
163     prepareLongHistory(VcsFileUtil.FILE_PATH_LIMIT * 2 / 40);
164     List<VcsCommitMetadata> log = log();
165
166     final List<String> hashes = ContainerUtil.newArrayList();
167     myLogProvider.readAllHashes(myProjectRoot, timedVcsCommit -> hashes.add(timedVcsCommit.getId().asString()));
168
169     List<? extends VcsShortCommitDetails> shortDetails = myLogProvider.readShortDetails(myProjectRoot, hashes);
170
171     Function<VcsShortCommitDetails, String> shortDetailsToString = getShortDetailsToString();
172     assertOrderedEquals(ContainerUtil.map(shortDetails, shortDetailsToString), ContainerUtil.map(log, shortDetailsToString));
173   }
174
175   public void test_full_details() throws Exception {
176     prepareLongHistory(VcsFileUtil.FILE_PATH_LIMIT * 2 / 40);
177     List<VcsCommitMetadata> log = log();
178
179     final List<String> hashes = ContainerUtil.newArrayList();
180     myLogProvider.readAllHashes(myProjectRoot, timedVcsCommit -> hashes.add(timedVcsCommit.getId().asString()));
181
182     List<? extends VcsFullCommitDetails> fullDetails = myLogProvider.readFullDetails(myProjectRoot, hashes);
183
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));
188   }
189
190   @NotNull
191   private Function<VcsShortCommitDetails, String> getShortDetailsToString() {
192     return details -> {
193       String result = "";
194
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();
201
202       return result;
203     };
204   }
205
206   /**
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.
210    */
211   private List<String> generateHistoryForFilters(boolean takeAllUsers) {
212     List<String> hashes = ContainerUtil.newArrayList();
213     hashes.add(last());
214
215     GitTestUtil.setupUsername("bob.smith", "bob.smith@example.com");
216     if (takeAllUsers) {
217       String commitByBob = tac("file.txt");
218       hashes.add(commitByBob);
219     }
220     GitTestUtil.setupDefaultUsername();
221
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");
228
229     Collections.reverse(hashes);
230     refresh();
231     return hashes;
232   }
233
234   @NotNull
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());
240   }
241
242   private static void prepareSomeHistory() {
243     tac("a.txt");
244     git("tag ATAG");
245     tac("b.txt");
246   }
247
248   private static void prepareLongHistory(int size) throws IOException {
249     for (int i = 0; i < size; i++) {
250       String file = "a" + (i % 10) + ".txt";
251       if (i < 10) {
252         tac(file);
253       }
254       else {
255         modify(file);
256       }
257     }
258   }
259
260   private static void createTaggedBranch() {
261     String hash = last();
262     tac("c.txt");
263     tac("d.txt");
264     tac("e.txt");
265     git("tag poor-tag");
266     git("reset --hard " + hash);
267   }
268
269   @NotNull
270   private static VcsUser getDefaultUser() {
271     return new VcsUserImpl(GitTestUtil.USER_NAME, GitTestUtil.USER_EMAIL);
272   }
273
274   @NotNull
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);
284     });
285   }
286 }