blob: 9ffa810c8ade181d8e4005e601807aaca1598642 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2011 Tasktop Technologies and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Tasktop Technologies - initial API and implementation
* Itema AS - Corrected lazy initialisation of fields
*******************************************************************************/
package org.eclipse.mylyn.internal.builds.ui.util;
import java.lang.reflect.Method;
import java.util.concurrent.atomic.AtomicReference;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.search.IJavaSearchConstants;
import org.eclipse.jdt.core.search.SearchEngine;
import org.eclipse.jdt.core.search.SearchPattern;
import org.eclipse.jdt.core.search.TypeNameMatch;
import org.eclipse.jdt.core.search.TypeNameMatchRequestor;
import org.eclipse.jdt.internal.junit.model.JUnitModel;
import org.eclipse.jdt.internal.junit.model.TestRunHandler;
import org.eclipse.jdt.internal.junit.model.TestRunSession;
import org.eclipse.jdt.internal.junit.ui.TestRunnerViewPart;
import org.eclipse.jdt.ui.JavaUI;
import org.eclipse.mylyn.builds.core.IBuild;
import org.eclipse.mylyn.builds.core.IBuildPlan;
import org.eclipse.mylyn.builds.core.ITestCase;
import org.eclipse.mylyn.builds.core.ITestSuite;
import org.eclipse.mylyn.builds.internal.core.operations.OperationChangeEvent;
import org.eclipse.mylyn.builds.internal.core.operations.OperationChangeListener;
import org.eclipse.mylyn.builds.internal.core.operations.RefreshOperation;
import org.eclipse.mylyn.builds.internal.core.util.JUnitResultGenerator;
import org.eclipse.mylyn.commons.core.ICoreRunnable;
import org.eclipse.mylyn.commons.workbench.WorkbenchUtil;
import org.eclipse.mylyn.internal.builds.ui.BuildsUiInternal;
import org.eclipse.mylyn.internal.builds.ui.BuildsUiPlugin;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.statushandlers.StatusManager;
import org.xml.sax.SAXException;
/**
* @author Steffen Pingel
* @author Torkild U. Resheim
*/
public class TestResultManager {
/**
* Encapsulates JUnit dependencies to avoid ClassNotFoundException when JUnit is not available.
*/
static class Runner {
private static volatile JUnitModel junitModel;
/**
* @see {@link org.eclipse.jdt.internal.junit.ui.OpenTestAction}
*/
static IType findType(String className, IProgressMonitor monitor) throws CoreException {
final IType[] result = { null };
TypeNameMatchRequestor nameMatchRequestor = new TypeNameMatchRequestor() {
@Override
public void acceptTypeNameMatch(TypeNameMatch match) {
result[0] = match.getType();
}
};
int lastDot = className.lastIndexOf('.');
char[] packageName = lastDot >= 0 ? className.substring(0, lastDot).toCharArray() : null;
char[] typeName = (lastDot >= 0 ? className.substring(lastDot + 1) : className).toCharArray();
SearchEngine engine = new SearchEngine();
engine.searchAllTypeNames(packageName, SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE,
typeName, SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE, IJavaSearchConstants.TYPE,
SearchEngine.createWorkspaceScope(), nameMatchRequestor,
IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH, monitor);
return result[0];
}
static JUnitModel getJUnitModel() {
if (junitModel == null) {
try {
// Eclipse 3.6 or later
Class<?> clazz;
try {
clazz = Class.forName("org.eclipse.jdt.internal.junit.JUnitCorePlugin"); //$NON-NLS-1$
} catch (ClassNotFoundException e) {
// Eclipse 3.5 and earlier
clazz = Class.forName("org.eclipse.jdt.internal.junit.ui.JUnitPlugin"); //$NON-NLS-1$
}
Method method = clazz.getDeclaredMethod("getModel"); //$NON-NLS-1$
junitModel = (JUnitModel) method.invoke(null);
} catch (Exception e) {
NoClassDefFoundError error = new NoClassDefFoundError("Unable to locate container for JUnitModel"); //$NON-NLS-1$
error.initCause(e);
throw error;
}
}
return junitModel;
}
public static void openInEditor(final String className, final String testName) {
final AtomicReference<IJavaElement> result = new AtomicReference<IJavaElement>();
try {
WorkbenchUtil.busyCursorWhile(new ICoreRunnable() {
public void run(IProgressMonitor monitor) throws CoreException {
IType type = findType(className, monitor);
if (type == null) {
return;
}
result.set(type);
if (testName != null) {
IMethod method = type.getMethod(testName, new String[0]);
if (method != null && method.exists()) {
result.set(method);
}
}
}
});
if (result.get() == null) {
StatusManager.getManager()
.handle(new Status(IStatus.ERROR, BuildsUiPlugin.ID_PLUGIN,
"Failed to locate test in workspace."), //$NON-NLS-1$
StatusManager.SHOW | StatusManager.BLOCK);
return;
}
JavaUI.openInEditor(result.get(), true, true);
} catch (OperationCanceledException e) {
return;
} catch (Exception e) {
StatusManager.getManager()
.handle(new Status(IStatus.ERROR, BuildsUiPlugin.ID_PLUGIN,
"Failed to locate test in workspace.", e), //$NON-NLS-1$
StatusManager.SHOW | StatusManager.BLOCK | StatusManager.LOG);
return;
}
}
static void showInJUnitViewInternal(final IBuild build) {
final TestRunSession testRunSession = new TestResultSession(build);
try {
WorkbenchUtil.busyCursorWhile(new ICoreRunnable() {
public void run(IProgressMonitor monitor) throws CoreException {
JUnitResultGenerator generator = new JUnitResultGenerator(build.getTestResult());
generator.setIncludeIgnored(jUnitSupportIgnoredTests());
TestRunHandler handler = new TestRunHandler(testRunSession);
try {
generator.write(handler);
} catch (SAXException e) {
throw new CoreException(new Status(IStatus.ERROR, BuildsUiPlugin.ID_PLUGIN,
"Unexpected parsing error while preparing test results", e)); //$NON-NLS-1$
}
}
});
} catch (OperationCanceledException e) {
return;
} catch (CoreException e) {
StatusManager.getManager()
.handle(new Status(IStatus.ERROR, BuildsUiPlugin.ID_PLUGIN,
"Unexpected error while processing test results", e), //$NON-NLS-1$
StatusManager.SHOW | StatusManager.LOG);
return;
}
// show results in view
IViewPart part = WorkbenchUtil.showViewInActiveWindow(TestRunnerViewPart.NAME);
showFailuresOnly(part);
getJUnitModel().addTestRunSession(testRunSession);
}
static void showFailuresOnly(IViewPart part) {
try {
boolean showFailuresOnly = BuildsUiPlugin.getDefault()
.getPreferenceStore()
.getBoolean(BuildsUiInternal.PREF_SHOW_TEST_FAILURES_ONLY);
Method method = TestRunnerViewPart.class.getDeclaredMethod("setShowFailuresOnly", boolean.class); //$NON-NLS-1$
method.setAccessible(true);
method.invoke(part, showFailuresOnly);
} catch (Throwable t) {
// ignore
}
}
}
public static boolean isJUnitAvailable() {
return Platform.getBundle("org.eclipse.jdt.junit") != null; //$NON-NLS-1$
}
static boolean jUnitSupportIgnoredTests() {
// supported on Eclipse 3.6 and later
return Platform.getBundle("org.eclipse.jdt.junit.core") != null; //$NON-NLS-1$
}
public static void openInEditor(ITestCase testCase) {
if (!isJUnitAvailable()) {
return;
}
Runner.openInEditor(testCase.getClassName(), testCase.getLabel());
}
public static void openInEditor(ITestSuite suite) {
if (!isJUnitAvailable()) {
return;
}
Runner.openInEditor(suite.getLabel(), null);
}
public static void showInJUnitView(final IBuild build) {
Assert.isNotNull(build);
if (!isJUnitAvailable()) {
StatusManager.getManager().handle(
new Status(IStatus.ERROR, BuildsUiPlugin.ID_PLUGIN, "JUnit is not installed."), //$NON-NLS-1$
StatusManager.SHOW | StatusManager.BLOCK);
return;
}
if (build.getTestResult() == null) {
StatusManager.getManager()
.handle(new Status(IStatus.ERROR, BuildsUiPlugin.ID_PLUGIN,
"The build did not produce test results."), //$NON-NLS-1$
StatusManager.SHOW | StatusManager.BLOCK);
return;
}
// invoke separate method to avoid ClassNotFoundException when JUnit is not available
Runner.showInJUnitViewInternal(build);
}
public static void showInJUnitView(final IBuildPlan plan) {
if (plan.getLastBuild() != null) {
showInJUnitView(plan.getLastBuild());
} else {
RefreshOperation operation = BuildsUiInternal.getFactory().getRefreshOperation(plan);
operation.addOperationChangeListener(new OperationChangeListener() {
@Override
public void done(OperationChangeEvent event) {
event.getOperation().getService().getRealm().asyncExec(new Runnable() {
public void run() {
if (plan.getLastBuild() != null) {
showInJUnitView(plan.getLastBuild());
}
}
});
}
});
operation.execute();
}
}
}