Use try-with-resource to avoid leaks with RevWalk and TreeWalk
[egit/eclipse.git] / org.eclipse.egit.ui.test / src / org / eclipse / egit / ui / test / TestUtil.java
blob1bf1e586df586937f9137cd86c07515ab0fdefa2
1 /*******************************************************************************
2 * Copyright (c) 2010, 2014 SAP AG and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
8 * Contributors:
9 * Mathias Kinzler (SAP AG) - initial implementation
10 *******************************************************************************/
11 package org.eclipse.egit.ui.test;
13 import static org.eclipse.swtbot.eclipse.finder.waits.Conditions.waitForView;
14 import static org.junit.Assert.assertEquals;
15 import static org.junit.Assert.assertNotNull;
16 import static org.junit.Assert.assertTrue;
17 import static org.junit.Assert.fail;
19 import java.io.File;
20 import java.io.FileOutputStream;
21 import java.io.IOException;
22 import java.io.OutputStreamWriter;
23 import java.io.Writer;
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.HashMap;
27 import java.util.HashSet;
28 import java.util.List;
29 import java.util.Locale;
30 import java.util.MissingResourceException;
31 import java.util.ResourceBundle;
32 import java.util.Set;
33 import java.util.StringTokenizer;
35 import org.eclipse.core.net.proxy.IProxyService;
36 import org.eclipse.core.runtime.jobs.Job;
37 import org.eclipse.egit.ui.Activator;
38 import org.eclipse.egit.ui.internal.commit.CommitHelper;
39 import org.eclipse.egit.ui.internal.commit.CommitHelper.CommitInfo;
40 import org.eclipse.jgit.lib.ConfigConstants;
41 import org.eclipse.jgit.lib.Constants;
42 import org.eclipse.jgit.lib.ObjectId;
43 import org.eclipse.jgit.lib.Repository;
44 import org.eclipse.jgit.lib.StoredConfig;
45 import org.eclipse.jgit.revwalk.RevCommit;
46 import org.eclipse.jgit.revwalk.RevWalk;
47 import org.eclipse.jgit.treewalk.TreeWalk;
48 import org.eclipse.jgit.util.StringUtils;
49 import org.eclipse.osgi.service.localization.BundleLocalization;
50 import org.eclipse.swt.widgets.Display;
51 import org.eclipse.swt.widgets.Shell;
52 import org.eclipse.swtbot.eclipse.finder.SWTWorkbenchBot;
53 import org.eclipse.swtbot.eclipse.finder.widgets.SWTBotEditor;
54 import org.eclipse.swtbot.eclipse.finder.widgets.SWTBotView;
55 import org.eclipse.swtbot.swt.finder.SWTBot;
56 import org.eclipse.swtbot.swt.finder.exceptions.WidgetNotFoundException;
57 import org.eclipse.swtbot.swt.finder.waits.ICondition;
58 import org.eclipse.swtbot.swt.finder.widgets.SWTBotShell;
59 import org.eclipse.swtbot.swt.finder.widgets.SWTBotTable;
60 import org.eclipse.swtbot.swt.finder.widgets.SWTBotTree;
61 import org.eclipse.swtbot.swt.finder.widgets.SWTBotTreeItem;
62 import org.eclipse.swtbot.swt.finder.widgets.TimeoutException;
63 import org.eclipse.ui.IViewReference;
64 import org.eclipse.ui.IWorkbenchPage;
65 import org.eclipse.ui.IWorkbenchWindow;
66 import org.eclipse.ui.PartInitException;
67 import org.eclipse.ui.PlatformUI;
68 import org.hamcrest.BaseMatcher;
69 import org.hamcrest.Description;
70 import org.hamcrest.Matcher;
71 import org.hamcrest.TypeSafeMatcher;
72 import org.osgi.framework.BundleContext;
73 import org.osgi.framework.ServiceReference;
74 import org.osgi.util.tracker.ServiceTracker;
76 /**
77 * Utilities to be used by SWTBot tests
79 public class TestUtil {
81 public final static String TESTAUTHOR = "Test Author <test.author@test.com>";
83 public final static String TESTCOMMITTER = "Test Committer <test.committer@test.com>";
85 public final static String TESTCOMMITTER_NAME = "Test Committer";
87 public final static String TESTCOMMITTER_EMAIL = "test.committer@test.com";
89 private final static char AMPERSAND = '&';
91 private ResourceBundle myBundle;
93 /**
94 * Allows access to the localized values of the EGit UI Plug-in
95 * <p>
96 * This will effectively read the plugin.properties. Ampersands (often used
97 * in menu items and field labels for keyboard shortcuts) will be filtered
98 * out (see also {@link #getPluginLocalizedValue(String, boolean)} in order
99 * to be able to reference these fields using SWTBot).
101 * @param key
102 * the key, must not be null
103 * @return the localized value in the current default {@link Locale}, or
104 * null
105 * @throws MissingResourceException
106 * if no value is found for the given key
108 public synchronized String getPluginLocalizedValue(String key)
109 throws MissingResourceException {
110 return getPluginLocalizedValue(key, false);
114 * Allows access to the localized values of the EGit UI Plug-in
115 * <p>
117 * @param key
118 * see {@link #getPluginLocalizedValue(String)}
119 * @param keepAmpersands
120 * if <code>true</code>, ampersands will be kept
121 * @return see {@link #getPluginLocalizedValue(String)}
122 * @throws MissingResourceException
123 * see {@link #getPluginLocalizedValue(String)}
125 public synchronized String getPluginLocalizedValue(String key,
126 boolean keepAmpersands) throws MissingResourceException {
127 if (myBundle == null) {
129 BundleContext context = Activator.getDefault().getBundle()
130 .getBundleContext();
132 ServiceTracker<BundleLocalization, BundleLocalization> localizationTracker =
133 new ServiceTracker<BundleLocalization, BundleLocalization>(
134 context, BundleLocalization.class, null);
135 localizationTracker.open();
137 BundleLocalization location = localizationTracker.getService();
138 if (location != null)
139 myBundle = location.getLocalization(Activator.getDefault()
140 .getBundle(), Locale.getDefault().toString());
142 if (myBundle != null) {
143 String raw = myBundle.getString(key);
145 if (keepAmpersands || raw.indexOf(AMPERSAND) < 0)
146 return raw;
148 StringBuilder sb = new StringBuilder(raw.length());
149 for (int i = 0; i < raw.length(); i++) {
150 char c = raw.charAt(i);
151 if (c != AMPERSAND)
152 sb.append(c);
154 return sb.toString();
156 return null;
160 * Utility for waiting until the execution of jobs of a given
161 * family has finished.
162 * @param family
163 * @throws InterruptedException
165 public static void joinJobs(Object family) throws InterruptedException {
166 Job.getJobManager().join(family, null);
170 * Process all queued UI events. If called from background thread, blocks
171 * until all pending events are processed in UI thread.
173 public static void processUIEvents() {
174 if (Display.getCurrent() != null) {
175 while (Display.getCurrent().readAndDispatch()) {
176 // process queued ui events
178 } else {
179 // synchronously refresh UI
180 PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() {
181 public void run() {
182 processUIEvents();
189 * Appends content to given file.
191 * @param file
192 * @param content
193 * @param append
194 * if true, then bytes will be written to the end of the file
195 * rather than the beginning
196 * @throws IOException
198 public static void appendFileContent(File file, String content, boolean append)
199 throws IOException {
200 Writer fw = null;
201 try {
202 fw = new OutputStreamWriter(new FileOutputStream(file, append),
203 "UTF-8");
204 fw.append(content);
205 } finally {
206 if (fw != null)
207 fw.close();
212 * Waits until the given tree has a node whose label contains text
213 * @param bot
214 * @param tree
215 * @param text
216 * @param timeout
217 * @throws TimeoutException
219 public static void waitUntilTreeHasNodeContainsText(SWTBot bot,
220 final SWTBotTree tree, final String text, long timeout)
221 throws TimeoutException {
222 bot.waitUntil(new ICondition() {
224 public boolean test() throws Exception {
225 for (SWTBotTreeItem item : tree.getAllItems())
226 if (item.getText().contains(text))
227 return true;
228 return false;
231 public void init(SWTBot bot2) {
232 // empty
235 public String getFailureMessage() {
236 return null;
238 }, timeout);
242 * Waits until the given tree item has a node whose label contains text
243 * @param bot
244 * @param treeItem
245 * @param text
246 * @param timeout
247 * @throws TimeoutException
249 public static void waitUntilTreeHasNodeContainsText(SWTBot bot,
250 final SWTBotTreeItem treeItem, final String text, long timeout)
251 throws TimeoutException {
252 bot.waitUntil(new ICondition() {
254 public boolean test() throws Exception {
255 for (SWTBotTreeItem item : treeItem.getItems())
256 if (item.getText().contains(text))
257 return true;
258 return false;
261 public void init(SWTBot bot2) {
262 // empty
265 public String getFailureMessage() {
266 return null;
268 }, timeout);
272 * Waits until the given tree item has a selected node with the given text
274 * @param bot
275 * @param tree
276 * @param text
277 * @param timeout
278 * @throws TimeoutException
280 public static void waitUntilTreeHasSelectedNodeWithText(SWTBot bot,
281 final SWTBotTree tree, final String text, long timeout)
282 throws TimeoutException {
283 bot.waitUntil(new ICondition() {
285 public boolean test() throws Exception {
286 return tree.selection().get(0, 0).equals(text);
289 public void init(SWTBot bot2) {
290 // empty
293 public String getFailureMessage() {
294 return null;
296 }, timeout);
300 * Waits until the given table has an item with the given text
301 * @param bot
302 * @param table
303 * @param text
304 * @param timeout
305 * @throws TimeoutException
307 public static void waitUntilTableHasRowWithText(SWTBot bot, final SWTBotTable table,
308 final String text, long timeout) throws TimeoutException {
309 bot.waitUntil(new ICondition() {
311 public boolean test() throws Exception {
312 if (table.indexOf(text)<0)
313 return false;
314 return true;
317 public void init(SWTBot bot2) {
318 // empty
321 public String getFailureMessage() {
322 return null;
324 }, timeout);
327 public static void waitUntilEditorIsActive(SWTWorkbenchBot bot,
328 final SWTBotEditor editor, long timeout) {
329 bot.waitUntil(new ICondition() {
331 public boolean test() throws Exception {
332 return editor.isActive();
335 public void init(SWTBot bot2) {
336 // empty
339 public String getFailureMessage() {
340 return null;
342 }, timeout);
346 * Disables usage of proxy servers
348 public static void disableProxy() {
349 BundleContext context = Activator.getDefault().getBundle().getBundleContext();
350 ServiceReference<IProxyService> serviceReference = context.getServiceReference(IProxyService.class);
351 IProxyService proxyService = context.getService(serviceReference);
352 proxyService.setSystemProxiesEnabled(false);
353 proxyService.setProxiesEnabled(false);
356 // TODO: this method is both needed by UI tests and Core tests
357 // provide a common base for UI tests and core tests
359 * verifies that repository contains exactly the given files.
360 * @param repository
361 * @param paths
362 * @throws Exception
364 public static void assertRepositoryContainsFiles(Repository repository,
365 String[] paths) throws Exception {
366 Set<String> expectedfiles = new HashSet<String>();
367 for (String path : paths)
368 expectedfiles.add(path);
369 try (TreeWalk treeWalk = new TreeWalk(repository)) {
370 treeWalk.addTree(repository.resolve("HEAD^{tree}"));
371 treeWalk.setRecursive(true);
372 while (treeWalk.next()) {
373 String path = treeWalk.getPathString();
374 if (!expectedfiles.contains(path))
375 fail("Repository contains unexpected expected file "
376 + path);
377 expectedfiles.remove(path);
380 if (expectedfiles.size() > 0) {
381 StringBuilder message = new StringBuilder(
382 "Repository does not contain expected files: ");
383 for (String path : expectedfiles) {
384 message.append(path);
385 message.append(" ");
387 fail(message.toString());
392 * verifies that repository contains exactly the given files with the given
393 * content. Usage example:<br>
395 * <code>
396 * assertRepositoryContainsFiles(repository, "foo/a.txt", "content of A",
397 * "foo/b.txt", "content of B")
398 * </code>
399 * @param repository
400 * @param args
401 * @throws Exception
403 public static void assertRepositoryContainsFilesWithContent(Repository repository,
404 String... args) throws Exception {
405 HashMap<String, String> expectedfiles = mkmap(args);
406 try (TreeWalk treeWalk = new TreeWalk(repository)) {
407 treeWalk.addTree(repository.resolve("HEAD^{tree}"));
408 treeWalk.setRecursive(true);
409 while (treeWalk.next()) {
410 String path = treeWalk.getPathString();
411 assertTrue(expectedfiles.containsKey(path));
412 ObjectId objectId = treeWalk.getObjectId(0);
413 byte[] expectedContent = expectedfiles.get(path)
414 .getBytes("UTF-8");
415 byte[] repoContent = treeWalk.getObjectReader().open(objectId)
416 .getBytes();
417 if (!Arrays.equals(repoContent, expectedContent))
418 fail("File " + path + " has repository content "
419 + new String(repoContent, "UTF-8")
420 + " instead of expected content "
421 + new String(expectedContent, "UTF-8"));
422 expectedfiles.remove(path);
425 if (expectedfiles.size() > 0) {
426 StringBuilder message = new StringBuilder(
427 "Repository does not contain expected files: ");
428 for (String path : expectedfiles.keySet()) {
429 message.append(path);
430 message.append(" ");
432 fail(message.toString());
436 private static HashMap<String, String> mkmap(String... args) {
437 if ((args.length % 2) > 0)
438 throw new IllegalArgumentException("needs to be pairs");
439 HashMap<String, String> map = new HashMap<String, String>();
440 for (int i = 0; i < args.length; i += 2)
441 map.put(args[i], args[i+1]);
442 return map;
446 * @param projectExplorerTree
447 * @param projects
448 * name of a project
449 * @return the project item pertaining to the project
451 public SWTBotTreeItem[] getProjectItems(SWTBotTree projectExplorerTree,
452 String... projects) {
453 List<SWTBotTreeItem> items = new ArrayList<SWTBotTreeItem>();
454 for (SWTBotTreeItem item : projectExplorerTree.getAllItems()) {
455 String itemText = item.getText();
456 StringTokenizer tok = new StringTokenizer(itemText, " ");
457 String name = tok.nextToken();
458 // may be a dirty marker
459 if (name.equals(">"))
460 name = tok.nextToken();
461 for (String project : projects)
462 if (project.equals(name))
463 items.add(item);
465 return items.isEmpty() ? null : items.toArray(new SWTBotTreeItem[items.size()]);
469 * @param node
470 * @param childNodeText
471 * @return child node containing childNodeText
472 * @see #getNode(SWTBotTreeItem[], String)
474 public static SWTBotTreeItem getChildNode(SWTBotTreeItem node,
475 String childNodeText) {
476 return getNode(node.getItems(), childNodeText);
480 * Finds the node that contains the given text. Throws a nice message in
481 * case the item is not found or more than one matching node was found.
483 * @param nodes
484 * @param searchText
485 * @return node containing the text
487 public static SWTBotTreeItem getNode(SWTBotTreeItem[] nodes, String searchText) {
488 List<String> texts = new ArrayList<String>();
489 List<SWTBotTreeItem> matchingItems = new ArrayList<SWTBotTreeItem>();
491 for (SWTBotTreeItem item : nodes) {
492 String text = item.getText();
493 if (text.contains(searchText))
494 matchingItems.add(item);
495 texts.add(text);
498 if (matchingItems.isEmpty())
499 throw new WidgetNotFoundException(
500 "Tree item element containg text \"" + searchText
501 + "\" was not found. Existing tree items:\n"
502 + StringUtils.join(texts, "\n"));
503 else if (matchingItems.size() > 1)
504 throw new WidgetNotFoundException(
505 "Tree item element containg text \""
506 + searchText
507 + "\" could not be uniquely identified. All tree items:\n"
508 + StringUtils.join(texts, "\n"));
510 return matchingItems.get(0);
513 public static RevCommit getHeadCommit(Repository repository)
514 throws Exception {
515 RevCommit headCommit = null;
516 ObjectId parentId = repository.resolve(Constants.HEAD);
517 if (parentId != null) {
518 try (RevWalk rw = new RevWalk(repository)) {
519 headCommit = rw.parseCommit(parentId);
522 return headCommit;
525 public static void checkHeadCommit(Repository repository, String author,
526 String committer, String message) throws Exception {
527 CommitInfo commitInfo = CommitHelper.getHeadCommitInfo(repository);
528 assertEquals(author, commitInfo.getAuthor());
529 assertEquals(committer, commitInfo.getCommitter());
530 assertEquals(message, commitInfo.getCommitMessage());
533 public static void configureTestCommitterAsUser(Repository repository) {
534 StoredConfig config = repository.getConfig();
535 config.setString(ConfigConstants.CONFIG_USER_SECTION, null,
536 ConfigConstants.CONFIG_KEY_NAME, TestUtil.TESTCOMMITTER_NAME);
537 config.setString(ConfigConstants.CONFIG_USER_SECTION, null,
538 ConfigConstants.CONFIG_KEY_EMAIL, TestUtil.TESTCOMMITTER_EMAIL);
541 public static void waitUntilViewWithGivenIdShows(final String viewId) {
542 waitForView(new BaseMatcher<IViewReference>() {
543 public boolean matches(Object item) {
544 if (item instanceof IViewReference)
545 return viewId.equals(((IViewReference) item).getId());
546 return false;
549 public void describeTo(Description description) {
550 description.appendText("Wait for view with ID=" + viewId);
555 public static void waitUntilViewWithGivenTitleShows(final String viewTitle) {
556 waitForView(new BaseMatcher<IViewReference>() {
557 public boolean matches(Object item) {
558 if (item instanceof IViewReference)
559 return viewTitle.equals(((IViewReference) item).getTitle());
561 return false;
564 public void describeTo(Description description) {
565 description.appendText("Wait for view with title " + viewTitle);
570 public static SWTBotShell botForShellStartingWith(final String titlePrefix) {
571 SWTWorkbenchBot bot = new SWTWorkbenchBot();
573 Matcher<Shell> matcher = new TypeSafeMatcher<Shell>() {
574 @Override
575 protected boolean matchesSafely(Shell item) {
576 String title = item.getText();
577 return title != null && title.startsWith(titlePrefix);
580 public void describeTo(Description description) {
581 description.appendText("Shell with title starting with '"
582 + titlePrefix + "'");
586 Shell shell = bot.widget(matcher);
587 return new SWTBotShell(shell);
590 public static SWTBotView showView(final String viewId) {
591 Display.getDefault().syncExec(new Runnable() {
592 public void run() {
593 IWorkbenchWindow workbenchWindow = PlatformUI.getWorkbench()
594 .getActiveWorkbenchWindow();
595 IWorkbenchPage workbenchPage = workbenchWindow.getActivePage();
596 try {
597 workbenchPage.showView(viewId);
598 processUIEvents();
599 } catch (PartInitException e) {
600 throw new RuntimeException("Showing view with ID " + viewId
601 + " failed.", e);
606 SWTWorkbenchBot bot = new SWTWorkbenchBot();
607 SWTBotView viewbot = bot.viewById(viewId);
608 assertNotNull("View with ID " + viewId + " not found via SWTBot.",
609 viewbot);
610 return viewbot;
613 public static void hideView(final String viewId) {
614 Display.getDefault().syncExec(new Runnable() {
615 public void run() {
616 IWorkbenchWindow workbenchWindow = PlatformUI.getWorkbench()
617 .getActiveWorkbenchWindow();
618 IWorkbenchPage workbenchPage = workbenchWindow.getActivePage();
619 IViewReference[] views = workbenchPage.getViewReferences();
620 for (int i = 0; i < views.length; i++) {
621 IViewReference view = views[i];
622 if (viewId.equals(view.getId())) {
623 workbenchPage.hideView(view);
630 public static SWTBotView showHistoryView() {
631 return showView("org.eclipse.team.ui.GenericHistoryView");
634 public static SWTBotView showExplorerView() {
635 return showView("org.eclipse.jdt.ui.PackageExplorer");
638 public static SWTBotTree getExplorerTree() {
639 SWTBotView view = showExplorerView();
640 return view.bot().tree();