1 /*******************************************************************************
2 * Copyright (C) 2010-2013 Dariusz Luksza <dariusz@luksza.org> and others.
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License 2.0
6 * which accompanies this distribution, and is available at
7 * https://www.eclipse.org/legal/epl-2.0/
9 * SPDX-License-Identifier: EPL-2.0
10 *******************************************************************************/
11 package org
.eclipse
.egit
.ui
.view
.synchronize
;
13 import static org
.eclipse
.egit
.ui
.internal
.UIText
.GitModelWorkingTree_workingTree
;
14 import static org
.eclipse
.jgit
.lib
.Constants
.HEAD
;
15 import static org
.eclipse
.jgit
.lib
.Constants
.MASTER
;
16 import static org
.eclipse
.jgit
.lib
.Constants
.R_HEADS
;
17 import static org
.eclipse
.jgit
.lib
.Constants
.R_TAGS
;
18 import static org
.eclipse
.swtbot
.swt
.finder
.matchers
.WidgetMatcherFactory
.allOf
;
19 import static org
.eclipse
.swtbot
.swt
.finder
.matchers
.WidgetMatcherFactory
.widgetOfType
;
20 import static org
.eclipse
.swtbot
.swt
.finder
.matchers
.WidgetMatcherFactory
.withRegex
;
21 import static org
.hamcrest
.CoreMatchers
.equalTo
;
22 import static org
.hamcrest
.CoreMatchers
.is
;
23 import static org
.junit
.Assert
.assertEquals
;
24 import static org
.junit
.Assert
.assertNotNull
;
25 import static org
.junit
.Assert
.assertNotSame
;
26 import static org
.junit
.Assert
.assertThat
;
27 import static org
.junit
.Assert
.assertTrue
;
29 import java
.io
.BufferedWriter
;
30 import java
.io
.ByteArrayInputStream
;
32 import java
.io
.FileOutputStream
;
33 import java
.io
.OutputStreamWriter
;
35 import org
.eclipse
.core
.resources
.IFile
;
36 import org
.eclipse
.core
.resources
.IProject
;
37 import org
.eclipse
.core
.resources
.IResource
;
38 import org
.eclipse
.core
.resources
.ResourcesPlugin
;
39 import org
.eclipse
.core
.runtime
.jobs
.Job
;
40 import org
.eclipse
.egit
.ui
.common
.CompareEditorTester
;
41 import org
.eclipse
.egit
.ui
.internal
.CommonUtils
;
42 import org
.eclipse
.egit
.ui
.internal
.UIText
;
43 import org
.eclipse
.egit
.ui
.internal
.repository
.RepositoriesView
;
44 import org
.eclipse
.egit
.ui
.internal
.synchronize
.GitChangeSetModelProvider
;
45 import org
.eclipse
.egit
.ui
.test
.TestUtil
;
46 import org
.eclipse
.jgit
.api
.Git
;
47 import org
.eclipse
.jgit
.api
.Status
;
48 import org
.eclipse
.jgit
.lib
.Repository
;
49 import org
.eclipse
.swt
.widgets
.Display
;
50 import org
.eclipse
.swt
.widgets
.Label
;
51 import org
.eclipse
.swtbot
.swt
.finder
.SWTBot
;
52 import org
.eclipse
.swtbot
.swt
.finder
.widgets
.SWTBotLabel
;
53 import org
.eclipse
.swtbot
.swt
.finder
.widgets
.SWTBotTree
;
54 import org
.eclipse
.swtbot
.swt
.finder
.widgets
.SWTBotTreeItem
;
55 import org
.eclipse
.team
.ui
.synchronize
.ISynchronizeView
;
56 import org
.hamcrest
.Matcher
;
57 import org
.junit
.Before
;
58 import org
.junit
.Ignore
;
59 import org
.junit
.Test
;
61 public class SynchronizeViewGitChangeSetModelTest
extends
62 AbstractSynchronizeViewTest
{
65 public void setUpEnabledModelProvider() {
66 setEnabledModelProvider(GitChangeSetModelProvider
.ID
);
70 public void shouldReturnNoChanges() throws Exception
{
72 changeFilesInProject();
75 launchSynchronization(HEAD
, R_HEADS
+ MASTER
, false);
78 SWTBot viewBot
= bot
.viewById(ISynchronizeView
.VIEW_ID
).bot();
79 @SuppressWarnings("unchecked")
80 Matcher matcher
= allOf(widgetOfType(Label
.class),
81 withRegex("No changes in .*"));
83 @SuppressWarnings("unchecked")
84 SWTBotLabel l
= new SWTBotLabel((Label
) viewBot
.widget(matcher
));
89 public void shouldReturnListOfChanges() throws Exception
{
91 changeFilesInProject();
94 launchSynchronization(HEAD
, HEAD
, true);
97 SWTBotTreeItem workingTreeItem
= getExpandedWorkingTreeItem();
98 assertTrue(workingTreeItem
.getText().endsWith(GitModelWorkingTree_workingTree
));
102 public void shouldCompareBranchAgainstTag() throws Exception
{
104 makeChangesAndCommit(PROJ1
);
107 launchSynchronization(INITIAL_TAG
, HEAD
, false);
110 SWTBotTreeItem changeSetTreeItem
= getChangeSetTreeItem();
111 assertEquals(1, changeSetTreeItem
.getItems().length
);
115 public void shouldCompareTagAgainstTag() throws Exception
{
117 makeChangesAndCommit(PROJ1
);
121 launchSynchronization(INITIAL_TAG
, R_TAGS
+ "v0.1", false);
124 SWTBotTreeItem changeSetTreeItem
= getChangeSetTreeItem();
125 assertEquals(1, changeSetTreeItem
.getItems().length
);
129 public void shouldOpenCompareEditor() throws Exception
{
131 changeFilesInProject();
134 launchSynchronization(HEAD
, INITIAL_TAG
, true);
137 CompareEditorTester compare
= getCompareEditorForFileInGitChangeSet(
139 assertNotNull(compare
);
143 public void shouldListFileDeletedChange() throws Exception
{
145 deleteFileAndCommit(PROJ1
);
148 launchSynchronization(HEAD
, HEAD
+ "~1", true);
151 SWTBotTreeItem changeSetTreeItem
= getChangeSetTreeItem();
152 assertEquals(1, changeSetTreeItem
.getItems().length
);
154 SWTBotTreeItem commitTree
= waitForNodeWithText(changeSetTreeItem
,
156 SWTBotTreeItem projectTree
= waitForNodeWithText(commitTree
, PROJ1
);
157 assertEquals(1, projectTree
.getItems().length
);
159 SWTBotTreeItem folderTree
= waitForNodeWithText(projectTree
, FOLDER
);
160 assertEquals(1, folderTree
.getItems().length
);
162 SWTBotTreeItem fileTree
= folderTree
.getItems()[0];
163 assertEquals("test.txt", fileTree
.getText());
167 public void shouldSynchronizeInEmptyRepository() throws Exception
{
169 createEmptyRepository();
172 launchSynchronization(EMPTY_PROJECT
, "", "", true);
175 SWTBotTreeItem workingTree
= getExpandedWorkingTreeItem();
176 SWTBotTreeItem projectTree
= waitForNodeWithText(workingTree
,
178 assertEquals(2, projectTree
.getItems().length
);
180 SWTBotTreeItem folderTree
= waitForNodeWithText(projectTree
, FOLDER
);
181 assertEquals(2, folderTree
.getItems().length
);
183 SWTBotTreeItem fileTree
= folderTree
.getItems()[0];
184 assertEquals(FILE1
, fileTree
.getText());
185 fileTree
= folderTree
.getItems()[1];
186 assertEquals(FILE2
, fileTree
.getText());
190 public void shouldExchangeCompareEditorSidesBetweenIncomingAndOutgoingChanges()
193 makeChangesAndCommit(PROJ1
);
195 // compare HEAD against tag
196 launchSynchronization(HEAD
, INITIAL_TAG
, false);
198 CompareEditorTester outgoingCompare
= getCompareEditorForFileInGitChangeSet(
200 // save left value from compare editor
201 String outgoingLeft
= outgoingCompare
.getLeftEditor().getText();
202 // save right value from compare editor
203 String outgoingRight
= outgoingCompare
.getRightEditor().getText();
204 outgoingCompare
.close();
206 assertNotSame("Text from SWTBot widgets was the same", outgoingLeft
, outgoingRight
);
209 // compare tag against HEAD
210 launchSynchronization(INITIAL_TAG
, HEAD
, false);
213 CompareEditorTester incomingComp
= getCompareEditorForFileInGitChangeSet(
215 // right side from compare editor should be equal with left
216 assertThat(outgoingLeft
, equalTo(incomingComp
.getRightEditor().getText()));
217 // left side from compare editor should be equal with right
218 assertThat(outgoingRight
, equalTo(incomingComp
.getLeftEditor().getText()));
222 public void shouldNotShowIgnoredFiles()
225 String ignoredName
= "to-be-ignored.txt";
227 IProject proj
= ResourcesPlugin
.getWorkspace().getRoot()
230 IFile ignoredFile
= proj
.getFile(ignoredName
);
231 ignoredFile
.create(new ByteArrayInputStream("content of ignored file"
232 .getBytes(proj
.getDefaultCharset())), false, null);
234 IFile gitignore
= proj
.getFile(".gitignore");
236 new ByteArrayInputStream(ignoredName
.getBytes(proj
237 .getDefaultCharset())), false, null);
238 proj
.refreshLocal(IResource
.DEPTH_INFINITE
, null);
241 launchSynchronization(INITIAL_TAG
, HEAD
, true);
244 // asserts for Git Change Set model
245 SWTBotTreeItem workingTree
= getExpandedWorkingTreeItem();
246 assertEquals(1, workingTree
.getItems().length
);
247 SWTBotTreeItem proj1Node
= workingTree
.getItems()[0];
248 assertEquals(1, proj1Node
.getItems().length
);
249 assertEquals(".gitignore", proj1Node
.getItems()[0].getText());
253 public void shouldShowNonWorkspaceFileInSynchronization()
256 String name
= "non-workspace.txt";
257 File root
= new File(getTestDirectory(), REPO1
);
258 File nonWorkspace
= new File(root
, name
);
259 BufferedWriter writer
= new BufferedWriter(new OutputStreamWriter(
260 new FileOutputStream(nonWorkspace
), "UTF-8"));
262 writer
.append("file content");
264 // TODO Synchronize currently shows "No changes" when the only thing that has
265 // changed is a non-workspace file, so add another change so that this
266 // does not happen. When the bug is fixed, this should be removed.
267 setTestFileContent("other content");
270 launchSynchronization(INITIAL_TAG
, HEAD
, true);
273 SWTBotTreeItem workingTree
= getExpandedWorkingTreeItem();
274 assertEquals(1, workingTree
.getNodes(name
).size());
278 public void shouldShowCompareEditorForNonWorkspaceFileFromSynchronization()
281 String content
= "file content";
282 String name
= "non-workspace.txt";
283 File root
= new File(getTestDirectory(), REPO1
);
284 File nonWorkspace
= new File(root
, name
);
285 BufferedWriter writer
= new BufferedWriter(new OutputStreamWriter(
286 new FileOutputStream(nonWorkspace
), "UTF-8"));
287 writer
.append(content
);
289 // TODO Synchronize currently shows "No changes" when the only thing that has
290 // changed is a non-workspace file, so add another change so that this
291 // does not happen. When the bug is fixed, this should be removed.
292 setTestFileContent("other content");
295 launchSynchronization(INITIAL_TAG
, HEAD
, true);
298 CompareEditorTester editor
= getCompareEditorForNonWorkspaceFileInGitChangeSet(name
);
300 String left
= editor
.getLeftEditor().getText();
301 String right
= editor
.getRightEditor().getText();
302 assertEquals(content
, left
);
303 assertEquals("", right
);
307 public void shouldStagePartialChangeInCompareEditor() throws Exception
{
309 changeFilesInProject();
310 launchSynchronization(HEAD
, HEAD
, true);
311 CompareEditorTester compareEditor
= getCompareEditorForFileInGitChangeSet(
315 Display
.getDefault().syncExec(new Runnable() {
318 CommonUtils
.runCommand("org.eclipse.compare.copyLeftToRight",
322 compareEditor
.save();
325 // then file FILE1 should be in index
326 Repository repo
= lookupRepository(repositoryFile
);
328 try (Git git
= new Git(repo
)) {
329 status
= git
.status().call();
331 assertThat(Long
.valueOf(status
.getChanged().size()),
332 is(Long
.valueOf(1L)));
333 assertThat(status
.getChanged().iterator().next(),
334 is(PROJ1
+ "/" + FOLDER
+ "/" + FILE1
));
338 public void shouldUnStagePartialChangeInCompareEditor() throws Exception
{
340 changeFilesInProject();
341 launchSynchronization(HEAD
, HEAD
, true);
342 CompareEditorTester compareEditor
= getCompareEditorForFileInGitChangeSet(
346 Display
.getDefault().syncExec(new Runnable() {
349 CommonUtils
.runCommand("org.eclipse.compare.copyRightToLeft",
353 compareEditor
.save();
355 // then file FILE1 should be unchanged in working tree
356 Repository repo
= lookupRepository(repositoryFile
);
357 try (Git git
= new Git(repo
)) {
358 Status status
= git
.status().call();
359 assertThat(Long
.valueOf(status
.getModified().size()),
360 is(Long
.valueOf(1)));
361 assertThat(status
.getModified().iterator().next(),
362 is(PROJ1
+ "/" + FOLDER
+ "/" + FILE2
));
367 public void shouldRefreshSyncResultAfterWorkspaceChange() throws Exception
{
369 String newFileName
= "new.txt";
370 launchSynchronization(INITIAL_TAG
, HEAD
, true);
371 IProject proj
= ResourcesPlugin
.getWorkspace().getRoot()
375 IFile newFile
= proj
.getFile(newFileName
);
377 new ByteArrayInputStream("content of new file".getBytes(proj
378 .getDefaultCharset())), false, null);
380 proj
.refreshLocal(IResource
.DEPTH_INFINITE
, null);
381 Job
.getJobManager().join(ResourcesPlugin
.FAMILY_AUTO_BUILD
, null);
384 SWTBotTreeItem workingTree
= getExpandedWorkingTreeItem();
385 assertTrue(workingTree
.getText()
386 .endsWith(GitModelWorkingTree_workingTree
));
387 // WidgetNotFoundException will be thrown when node named 'new.txt' not
389 assertNotNull(TestUtil
.getNode(workingTree
.getItems(), PROJ1
)
390 .getNode(newFileName
));
394 public void shouldRefreshSyncResultAfterRepositoryChange() throws Exception
{
396 changeFilesInProject();
397 launchSynchronization(HEAD
, HEAD
, true);
399 // preconditions - sync result should contain two uncommitted changes
400 SWTBotTreeItem workingTree
= getExpandedWorkingTreeItem();
401 assertTrue(workingTree
.getText().endsWith(GitModelWorkingTree_workingTree
));
403 workingTree
.getItems()[0].getItems()[0].getItems().length
);
408 // then - synchronize view should be empty
409 SWTBot viewBot
= bot
.viewById(ISynchronizeView
.VIEW_ID
).bot();
410 @SuppressWarnings("unchecked")
411 Matcher matcher
= allOf(widgetOfType(Label
.class),
412 withRegex("No changes in .*"));
414 @SuppressWarnings("unchecked")
415 SWTBotLabel l
= new SWTBotLabel((Label
) viewBot
.widget(matcher
));
419 // this test always fails with cause:
420 // Timeout after: 5000 ms.: Could not find context menu with text:
424 public void shouldLaunchSynchronizationFromGitRepositories()
427 bot
.menu("Window").menu("Show View").menu("Other...").click();
428 bot
.shell("Show View").bot().tree().expandNode("Git").getNode(
429 "Git Repositories").doubleClick();
431 SWTBotTree repositoriesTree
= bot
.viewById(RepositoriesView
.VIEW_ID
)
434 SWTBotTreeItem egitRoot
= repositoriesTree
.getAllItems()[0];
438 SWTBotTreeItem remoteBranch
= egitRoot
.expandNode("Branches")
439 .expandNode("Remote Branches");
440 SWTBotTreeItem branchNode
= remoteBranch
.getNode("origin/stable-0.7");
442 branchNode
.contextMenu("Synchronize").click();
447 SWTBotTree syncViewTree
= bot
.viewById(ISynchronizeView
.VIEW_ID
).bot().tree();
448 assertEquals(8, syncViewTree
.getAllItems().length
);
451 protected SWTBotTreeItem
getChangeSetTreeItem() {
452 SWTBotTree syncViewTree
= bot
.viewById(ISynchronizeView
.VIEW_ID
).bot().tree();
453 SWTBotTreeItem changeSetItem
= waitForNodeWithText(syncViewTree
,
454 UIText
.GitChangeSetModelProviderLabel
);
455 return changeSetItem
;
458 protected CompareEditorTester
getCompareEditorForFileInGitChangeSet(
460 boolean includeLocalChanges
) {
461 SWTBotTreeItem changeSetTreeItem
= getChangeSetTreeItem();
463 SWTBotTreeItem rootTree
;
464 if (includeLocalChanges
)
465 rootTree
= waitForNodeWithText(changeSetTreeItem
,
466 GitModelWorkingTree_workingTree
);
468 rootTree
= waitForNodeWithText(changeSetTreeItem
, TEST_COMMIT_MSG
);
470 SWTBotTreeItem projNode
= waitForNodeWithText(rootTree
, PROJ1
);
471 return getCompareEditor(projNode
, fileName
);
474 protected CompareEditorTester
getCompareEditorForNonWorkspaceFileInGitChangeSet(
475 final String fileName
) {
476 SWTBotTreeItem changeSetTreeItem
= getChangeSetTreeItem();
478 SWTBotTreeItem rootTree
= waitForNodeWithText(changeSetTreeItem
,
479 GitModelWorkingTree_workingTree
);
480 waitForNodeWithText(rootTree
, fileName
).doubleClick();
482 return CompareEditorTester
.forTitleContaining(fileName
);
485 private SWTBotTreeItem
getExpandedWorkingTreeItem() {
486 SWTBotTreeItem changeSetTreeItem
= getChangeSetTreeItem();
487 String workingTreeNodeNameString
= getWorkingTreeNodeName(changeSetTreeItem
);
488 SWTBotTreeItem node
= changeSetTreeItem
.getNode(workingTreeNodeNameString
);
490 return node
.doubleClick();
493 private String
getWorkingTreeNodeName(SWTBotTreeItem changeSetTreeItem
) {
494 for (SWTBotTreeItem item
: changeSetTreeItem
.getItems()) {
495 String nodeName
= item
.getText();
496 if (nodeName
.contains(UIText
.GitModelWorkingTree_workingTree
))
500 return UIText
.GitModelWorkingTree_workingTree
;