/*
* Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com
* The software in this package is published under the terms of the CPAL v1.0
* license, a copy of which has been included with this distribution in the
* LICENSE.txt file.
*/
package org.mule.munit.plugin;
/*******************************************************************************
* Copyright (c) 2000, 2010 IBM Corporation 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:
* IBM Corporation - initial API and implementation
* Sebastian Davids: sdavids@gmx.de bug: 26293, 27889
* David Saff (saff@mit.edu) - bug 102632: [JUnit] Support for JUnit 4.
* Robert Konigsberg <konigsberg@google.com> - [JUnit] Improve discoverability of the ability to run a single method under JUnit Tests - https://bugs.eclipse.org/bugs/show_bug.cgi?id=285637
*******************************************************************************/
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.jface.window.Window;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.ElementListSelectionDialog;
import org.eclipse.ui.dialogs.ElementTreeSelectionDialog;
import org.eclipse.ui.dialogs.SelectionDialog;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.debug.internal.ui.SWTFactory;
import org.eclipse.debug.ui.AbstractLaunchConfigurationTab;
import org.eclipse.jdt.core.IAnnotation;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaModel;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.ISourceReference;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.core.dom.Modifier;
import org.eclipse.jdt.core.search.IJavaSearchScope;
import org.eclipse.jdt.core.search.SearchEngine;
import org.eclipse.jdt.internal.junit.BasicElementLabels;
import org.eclipse.jdt.internal.junit.Messages;
import org.eclipse.jdt.internal.junit.launcher.ITestKind;
import org.eclipse.jdt.internal.junit.launcher.JUnitLaunchConfigurationConstants;
import org.eclipse.jdt.internal.junit.launcher.JUnitMigrationDelegate;
import org.eclipse.jdt.internal.junit.launcher.TestKind;
import org.eclipse.jdt.internal.junit.launcher.TestKindRegistry;
import org.eclipse.jdt.internal.junit.ui.IJUnitHelpContextIds;
import org.eclipse.jdt.internal.junit.ui.JUnitMessages;
import org.eclipse.jdt.internal.junit.ui.JUnitPlugin;
import org.eclipse.jdt.internal.junit.util.JUnitStubUtility;
import org.eclipse.jdt.internal.junit.util.LayoutUtil;
import org.eclipse.jdt.internal.junit.util.CoreTestSearchEngine;
import org.eclipse.jdt.internal.junit.util.TestSearchEngine;
import org.eclipse.jdt.launching.AbstractVMInstall;
import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
import org.eclipse.jdt.launching.IVMInstall;
import org.eclipse.jdt.launching.JavaRuntime;
import org.eclipse.jdt.ui.IJavaElementSearchConstants;
import org.eclipse.jdt.ui.JavaElementComparator;
import org.eclipse.jdt.ui.JavaElementLabelProvider;
import org.eclipse.jdt.ui.JavaUI;
import org.eclipse.jdt.ui.StandardJavaElementContentProvider;
import org.eclipse.jdt.ui.dialogs.ITypeInfoFilterExtension;
import org.eclipse.jdt.ui.dialogs.ITypeInfoRequestor;
import org.eclipse.jdt.ui.dialogs.TypeSelectionExtension;
import org.eclipse.jdt.internal.ui.wizards.TypedElementSelectionValidator;
import org.eclipse.jdt.internal.ui.wizards.TypedViewerFilter;
/**
* The launch configuration tab for JUnit.
* <p>
* This class may be instantiated but is not intended to be subclassed.
* </p>
*
* @noextend This class is not intended to be subclassed by clients.
* @since 3.3
*/
public class LaunchConfigurationTab extends AbstractLaunchConfigurationTab
{
private Label fProjLabel;
private Text fProjText;
private Text fTestText;
private Label fTestLabel;
/**
* Creates a JUnit launch configuration tab.
*/
public LaunchConfigurationTab()
{
}
public void createControl(Composite parent)
{
Composite comp = new Composite(parent, SWT.NONE);
setControl(comp);
GridLayout topLayout = new GridLayout();
topLayout.numColumns = 2;
comp.setLayout(topLayout);
createSingleTestSection(comp);
createSpacer(comp);
Dialog.applyDialogFont(comp);
validatePage();
}
private void createSpacer(Composite comp)
{
Label label = new Label(comp, SWT.NONE);
GridData gd = new GridData();
gd.horizontalSpan = 2;
label.setLayoutData(gd);
}
private void createSingleTestSection(Composite comp)
{
GridData gd = new GridData();
gd.horizontalSpan = 2;
fProjLabel = new Label(comp, SWT.NONE);
fProjLabel.setText("Project");
gd = new GridData();
gd.horizontalIndent = 25;
fProjLabel.setLayoutData(gd);
fProjText = new Text(comp, SWT.SINGLE | SWT.BORDER);
fProjText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
fTestLabel = new Label(comp, SWT.NONE);
gd = new GridData();
gd.horizontalIndent = 25;
fTestLabel.setLayoutData(gd);
fTestLabel.setText("Test");
fTestText = new Text(comp, SWT.SINGLE | SWT.BORDER);
fTestText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
fProjText.addModifyListener(new ModifyListener()
{
public void modifyText(ModifyEvent evt)
{
validatePage();
updateLaunchConfigurationDialog();
}
});
fTestText.addModifyListener(new ModifyListener()
{
public void modifyText(ModifyEvent evt)
{
validatePage();
updateLaunchConfigurationDialog();
}
});
}
private static Image createImage(String path)
{
return JUnitPlugin.getImageDescriptor(path).createImage();
}
/* (non-Javadoc)
* @see org.eclipse.debug.ui.ILaunchConfigurationTab#initializeFrom(org.eclipse.debug.core.ILaunchConfiguration)
*/
public void initializeFrom(ILaunchConfiguration config)
{
updateProjectFromConfig(config);
updateTestFromConfig(config);
String containerHandle = ""; //$NON-NLS-1$
try
{
containerHandle = config.getAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_CONTAINER, ""); //$NON-NLS-1$
}
catch (CoreException ce)
{
}
validatePage();
}
private void updateProjectFromConfig(ILaunchConfiguration config)
{
String projectName = ""; //$NON-NLS-1$
try
{
projectName = config.getAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, ""); //$NON-NLS-1$
}
catch (CoreException ce)
{
}
fProjText.setText(projectName);
}
private void updateTestFromConfig(ILaunchConfiguration config)
{
String testName = ""; //$NON-NLS-1$
try
{
testName = config.getAttribute("resource", ""); //$NON-NLS-1$
}
catch (CoreException ce)
{
}
fTestText.setText(testName);
}
protected void updateLaunchConfigurationDialog()
{
if (getLaunchConfigurationDialog() != null)
{
//order is important here due to the call to
//refresh the tab viewer in updateButtons()
//which ensures that the messages are up to date
getLaunchConfigurationDialog().updateButtons();
getLaunchConfigurationDialog().updateMessage();
}
}
public void performApply(ILaunchConfigurationWorkingCopy config)
{
config.setAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, fProjText.getText());
config.setAttribute(IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME, fTestText.getText());
config.setAttribute("resource", fTestText.getText()); //$NON-NLS-1$
config.setAttribute("Mpath", "/" + fProjText.getText() + "/src/test/munit/" + fTestText.getText()); //$NON-NLS-1$
try
{
mapResources(config);
}
catch (CoreException e)
{
JUnitPlugin.log(e.getStatus());
}
}
private void mapResources(ILaunchConfigurationWorkingCopy config) throws CoreException
{
JUnitMigrationDelegate.mapResources(config);
}
/* (non-Javadoc)
* @see org.eclipse.debug.ui.AbstractLaunchConfigurationTab#dispose()
*/
public void dispose()
{
super.dispose();
}
/* (non-Javadoc)
* @see org.eclipse.debug.ui.AbstractLaunchConfigurationTab#getImage()
*/
public Image getImage()
{
return null;
}
/*
* Return the IJavaProject corresponding to the project name in the project name
* text field, or null if the text does not match a project name.
*/
private IJavaProject getJavaProject()
{
String projectName = fProjText.getText().trim();
if (projectName.length() < 1)
{
return null;
}
return getJavaModel().getJavaProject(projectName);
}
/*
* Convenience method to get the workspace root.
*/
private IWorkspaceRoot getWorkspaceRoot()
{
return ResourcesPlugin.getWorkspace().getRoot();
}
/*
* Convenience method to get access to the java model.
*/
private IJavaModel getJavaModel()
{
return JavaCore.create(getWorkspaceRoot());
}
/* (non-Javadoc)
* @see org.eclipse.debug.ui.AbstractLaunchConfigurationTab#isValid(org.eclipse.debug.core.ILaunchConfiguration)
*/
public boolean isValid(ILaunchConfiguration config)
{
validatePage();
return true;
}
/*
* @see org.eclipse.debug.ui.AbstractLaunchConfigurationTab#setErrorMessage(java.lang.String)
* @since 3.6
*/
protected void setErrorMessage(String errorMessage)
{
super.setErrorMessage(errorMessage);
}
private void validatePage()
{
setErrorMessage(null);
setMessage(null);
String projectName = fProjText.getText().trim();
if (projectName.length() == 0)
{
setErrorMessage("Project not specified");
return;
}
IStatus status = ResourcesPlugin.getWorkspace().validatePath(IPath.SEPARATOR + projectName, IResource.PROJECT);
if (!status.isOK() || !Path.ROOT.isValidSegment(projectName))
{
setErrorMessage("Invalid Prject name");
return;
}
IProject project = getWorkspaceRoot().getProject(projectName);
if (!project.exists())
{
setErrorMessage("Project does not Exists.");
return;
}
IJavaProject javaProject = JavaCore.create(project);
try
{
String className = fTestText.getText().trim();
if (className.length() == 0)
{
setErrorMessage("Test file is not specified. You must enter the name of the file in the munit folder that you want to run");
return;
}
IType type = javaProject.findType(className);
if (type == null)
{
setErrorMessage("File not found in munit folder");
return;
}
}
catch (CoreException e)
{
JUnitPlugin.log(e);
}
}
private void setEnableSingleTestGroup(boolean enabled)
{
fProjLabel.setEnabled(enabled);
fProjText.setEnabled(enabled);
fTestLabel.setEnabled(enabled);
fTestText.setEnabled(enabled);
boolean projectTextHasContents = fProjText.getText().length() > 0;
}
/* (non-Javadoc)
* @see org.eclipse.debug.ui.ILaunchConfigurationTab#setDefaults(org.eclipse.debug.core.ILaunchConfigurationWorkingCopy)
*/
public void setDefaults(ILaunchConfigurationWorkingCopy config)
{
IJavaElement javaElement = getContext();
if (javaElement != null)
{
initializeJavaProject(javaElement, config);
}
else
{
// We set empty attributes for project & main type so that when one config is
// compared to another, the existence of empty attributes doesn't cause an
// incorrect result (the performApply() method can result in empty values
// for these attributes being set on a config if there is nothing in the
// corresponding text boxes)
config.setAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, ""); //$NON-NLS-1$
config.setAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_CONTAINER, ""); //$NON-NLS-1$
}
initializeTestAttributes(javaElement, config);
}
private void initializeTestAttributes(IJavaElement javaElement, ILaunchConfigurationWorkingCopy config)
{
if (javaElement != null && javaElement.getElementType() < IJavaElement.COMPILATION_UNIT)
nitializeTestContainer(javaElement, onfig);
else
nitializeTestType(javaElement, onfig);
}
private void initializeTestContainer(IJavaElement javaElement, ILaunchConfigurationWorkingCopy config)
{
config.setAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_CONTAINER, javaElement.getHandleIdentifier());
initializeName(config, javaElement.getElementName());
}
private void initializeName(ILaunchConfigurationWorkingCopy config, String name)
{
if (name == null)
{
name = ""; //$NON-NLS-1$
}
if (name.length() > 0)
{
int index = name.lastIndexOf('.');
if (index > 0)
{
name = name.substring(index + 1);
}
name = getLaunchConfigurationDialog().generateName(name);
config.rename(name);
}
}
/*
* Set the main type & name attributes on the working copy based on the IJavaElement
*/
private void initializeTestType(IJavaElement javaElement, ILaunchConfigurationWorkingCopy config)
{
String name = ""; //$NON-NLS-1$
String testKindId = null;
try
{
// we only do a search for compilation units or class files or
// or source references
if (javaElement instanceof ISourceReference)
{
ITestKind testKind = TestKindRegistry.getContainerTestKind(javaElement);
testKindId = testKind.getId();
IType[] types = TestSearchEngine.findTests(getLaunchConfigurationDialog(), javaElement, testKind);
if ((types == null) || (types.length < 1))
{
return;
}
// Simply grab the first main type found in the searched element
name = types[0].getFullyQualifiedName('.');
}
}
catch (InterruptedException ie)
{
}
catch (InvocationTargetException ite)
{
}
config.setAttribute(IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME, name);
if (testKindId != null)
onfig.setAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_RUNNER_KIND, estKindId);
initializeName(config, name);
}
/* (non-Javadoc)
* @see org.eclipse.debug.ui.ILaunchConfigurationTab#getName()
*/
public String getName()
{
return JUnitMessages.JUnitLaunchConfigurationTab_tab_label;
}
private IJavaElement chooseContainer(IJavaElement initElement)
{
Class[] acceptedClasses = new Class[] {IPackageFragmentRoot.class, IJavaProject.class, IPackageFragment.class};
TypedElementSelectionValidator validator = new TypedElementSelectionValidator(acceptedClasses, false)
{
public boolean isSelectedValid(Object element)
{
return true;
}
};
acceptedClasses = new Class[] {IJavaModel.class, IPackageFragmentRoot.class, IJavaProject.class, IPackageFragment.class};
ViewerFilter filter = new TypedViewerFilter(acceptedClasses)
{
public boolean select(Viewer viewer, Object parent, Object element)
{
if (element instanceof IPackageFragmentRoot && ((IPackageFragmentRoot) element).isArchive())
eturn alse;
try
{
if (element instanceof IPackageFragment && !((IPackageFragment) element).hasChildren())
{
return false;
}
}
catch (JavaModelException e)
{
return false;
}
return super.select(viewer, parent, element);
}
};
StandardJavaElementContentProvider provider = new StandardJavaElementContentProvider();
ILabelProvider labelProvider = new JavaElementLabelProvider(JavaElementLabelProvider.SHOW_DEFAULT);
ElementTreeSelectionDialog dialog = new ElementTreeSelectionDialog(getShell(), labelProvider, provider);
dialog.setValidator(validator);
dialog.setComparator(new JavaElementComparator());
dialog.setTitle(JUnitMessages.JUnitLaunchConfigurationTab_folderdialog_title);
dialog.setMessage(JUnitMessages.JUnitLaunchConfigurationTab_folderdialog_message);
dialog.addFilter(filter);
dialog.setInput(JavaCore.create(getWorkspaceRoot()));
dialog.setInitialSelection(initElement);
dialog.setAllowMultiple(false);
if (dialog.open() == Window.OK)
{
Object element = dialog.getFirstResult();
return (IJavaElement) element;
}
return null;
}
/*
* Returns the current Java element context from which to initialize
* default settings, or <code>null</code> if none.
*
* @return Java element context.
*/
private IJavaElement getContext()
{
IWorkbenchWindow activeWorkbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
if (activeWorkbenchWindow == null)
{
return null;
}
IWorkbenchPage page = activeWorkbenchWindow.getActivePage();
if (page != null)
{
ISelection selection = page.getSelection();
if (selection instanceof IStructuredSelection)
{
IStructuredSelection ss = (IStructuredSelection) selection;
if (!ss.isEmpty())
{
Object obj = ss.getFirstElement();
if (obj instanceof IJavaElement)
{
return (IJavaElement) obj;
}
if (obj instanceof IResource)
{
IJavaElement je = JavaCore.create((IResource) obj);
if (je == null)
{
IProject pro = ((IResource) obj).getProject();
je = JavaCore.create(pro);
}
if (je != null)
{
return je;
}
}
}
}
IEditorPart part = page.getActiveEditor();
if (part != null)
{
IEditorInput input = part.getEditorInput();
return (IJavaElement) input.getAdapter(IJavaElement.class);
}
}
return null;
}
private void initializeJavaProject(IJavaElement javaElement, ILaunchConfigurationWorkingCopy config)
{
IJavaProject javaProject = javaElement.getJavaProject();
String name = null;
if (javaProject != null && javaProject.exists())
{
name = javaProject.getElementName();
}
config.setAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, name);
}
private void setButtonGridData(Button button)
{
GridData gridData = new GridData();
button.setLayoutData(gridData);
LayoutUtil.setButtonDimensionHint(button);
}
/* (non-Javadoc)
* @see org.eclipse.debug.ui.AbstractLaunchConfigurationTab#getId()
*/
public String getId()
{
return "Munit Test"; //$NON-NLS-1$
}
}