/*******************************************************************************
* Copyright (c) 2017 Rogue Wave Software Inc. 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:
* Rogue Wave Software Inc. - initial implementation
*******************************************************************************/
package org.eclipse.php.phpunit.ui.wizards;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.dltk.ast.Modifiers;
import org.eclipse.dltk.core.*;
import org.eclipse.dltk.core.index2.search.ISearchEngine.MatchRule;
import org.eclipse.dltk.core.search.IDLTKSearchConstants;
import org.eclipse.dltk.core.search.IDLTKSearchScope;
import org.eclipse.dltk.core.search.SearchEngine;
import org.eclipse.dltk.ui.dialogs.ITypeInfoFilterExtension;
import org.eclipse.dltk.ui.dialogs.ITypeInfoRequestor;
import org.eclipse.dltk.ui.dialogs.TypeSelectionExtension;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.window.Window;
import org.eclipse.jface.wizard.IWizardContainer;
import org.eclipse.php.core.compiler.PHPFlags;
import org.eclipse.php.internal.core.PHPLanguageToolkit;
import org.eclipse.php.internal.core.model.PHPModelAccess;
import org.eclipse.php.internal.ui.util.StatusInfo;
import org.eclipse.php.internal.ui.wizards.fields.*;
import org.eclipse.php.phpunit.PHPUnitMessages;
import org.eclipse.php.phpunit.PHPUnitPlugin;
import org.eclipse.php.phpunit.model.PHPUnitSearchEngine;
import org.eclipse.php.phpunit.model.PHPUnitValidator;
import org.eclipse.php.phpunit.ui.ElementSelectionDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.*;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.SelectionDialog;
import org.eclipse.ui.dialogs.SelectionStatusDialog;
public class TestCaseWizardPage extends PHPUnitWizardPage {
private boolean isClassOrMethodElementToTest = true;
class ElementToTestFieldAdapter implements IStringButtonAdapter, IDialogFieldListener {
@Override
public void changeControlPressed(final DialogField field) {
elementToTestButtonPressed(field);
}
@Override
public void dialogFieldChanged(final DialogField field) {
elementToTestFieldChanged(field);
}
}
private final static String PAGE_NAME = "TestCaseWizardPage"; //$NON-NLS-1$
private final static String TEST_SUFFIX = "Test"; //$NON-NLS-1$
private IModelElement fElementToTest; // resolved model, can be null
private StringButtonDialogField fElementToTestField; // control
private Label fElementToTestFileNameLabel;
private IType[] PHP_UNIT_CASE_BASE_CLASS_CACHE;
public TestCaseWizardPage() {
super(PAGE_NAME);
setTitle(PHPUnitMessages.PHPUnitWizardPage_5);
setDescription(PHPUnitMessages.PHPUnitWizardPage_6);
fSuperClassDialogField.setText(PHPUnitSearchEngine.CLASS_CASE);
final ElementToTestFieldAdapter elementAdapter = new ElementToTestFieldAdapter();
fElementToTestField = new StringButtonDialogField(elementAdapter);
fElementToTestField.setDialogFieldListener(elementAdapter);
fElementToTestField.setLabelText(PHPUnitMessages.TestCaseWizardPage_0);
fElementToTestField.setButtonLabel(PHPUnitMessages.TestCaseWizardPage_1);
fElementToTestStatus = new StatusInfo();
}
private IModelElement chooseElementToTest() {
final IContainer root = getTestContainer();
if (root == null)
return null;
IProject project = getTestContainer().getProject();
SelectionStatusDialog dialog = null;
final IDLTKSearchScope searchScope = SearchEngine.createSearchScope(DLTKCore.create(project),
IDLTKSearchScope.SOURCES);
if (isClassOrMethodElementToTest) {
dialog = new PHPUnitFilteredTypesSelectionDialog(getShell(), false,
PlatformUI.getWorkbench().getProgressService(), searchScope, IDLTKSearchConstants.TYPE,
new TypeSelectionExtension() {
@Override
public ITypeInfoFilterExtension getFilterExtension() {
return new ITypeInfoFilterExtension() {
@Override
public boolean select(ITypeInfoRequestor typeInfoRequestor) {
int modifiers = typeInfoRequestor.getModifiers();
if (!PHPFlags.isInterface(modifiers) && !PHPFlags.isNamespace(modifiers)
&& !PHPFlags.isAbstract(modifiers)) {
return true;
}
return false;
}
};
}
}, PHPLanguageToolkit.getDefault());
((PHPUnitFilteredTypesSelectionDialog) dialog).setInitialPattern("."); //$NON-NLS-1$
} else {
final List<IMethod> staticOrGlobalMethods = new LinkedList<>();
IMethod[] globalFunctions = PHPModelAccess.getDefault().findMethods(null, MatchRule.PREFIX,
Modifiers.AccGlobal, 0, searchScope, new NullProgressMonitor());
if (globalFunctions != null) {
staticOrGlobalMethods.addAll(Arrays.asList(globalFunctions));
}
IMethod[] staticMethods = PHPModelAccess.getDefault().findMethods(null, MatchRule.PREFIX,
Modifiers.AccStatic, Modifiers.AccGlobal | Modifiers.AccPrivate, searchScope,
new NullProgressMonitor());
if (staticMethods != null) {
staticOrGlobalMethods.addAll(Arrays.asList(staticMethods));
}
IMethod[] methodScope = staticOrGlobalMethods.toArray(new IMethod[staticOrGlobalMethods.size()]);
dialog = new PHPUnitMethodSelectionDialog(getShell(), methodScope);
}
dialog.setTitle(PHPUnitMessages.TestCaseWizardPage_2);
dialog.setMessage(PHPUnitMessages.TestCaseWizardPage_3);
if (dialog.open() == Window.OK) {
Object[] resultArray = dialog.getResult();
if ((resultArray != null) && (resultArray.length > 0)) {
return (IModelElement) resultArray[0];
}
}
return null;
}
@Override
protected IType chooseSuperClass() {
final IContainer root = getTestContainer();
if (root == null) {
return null;
}
Shell shell = getShell();
IProject project = root.getProject();
final IScriptProject scriptProject = DLTKCore.create(project);
findTestCases(scriptProject);
if (PHP_UNIT_CASE_BASE_CLASS_CACHE != null && PHP_UNIT_CASE_BASE_CLASS_CACHE.length > 0) {
SelectionDialog dialog = new ElementSelectionDialog(shell, PHP_UNIT_CASE_BASE_CLASS_CACHE); // $NON-NLS-1$
dialog.setTitle(PHPUnitMessages.PHPUnitWizardPage_10);
dialog.setMessage(PHPUnitMessages.PHPUnitWizardPage_11);
if (dialog.open() == Window.OK) {
final Object[] resultArray = dialog.getResult();
if (resultArray != null && resultArray.length > 0) {
return (IType) resultArray[0];
}
}
}
return null;
}
/**
* @param scriptProject
*/
private void findTestCases(final IScriptProject scriptProject) {
if (PHP_UNIT_CASE_BASE_CLASS_CACHE == null) {
final PHPUnitSearchEngine searchEngine = new PHPUnitSearchEngine(scriptProject);
final List<IType> elementsList = new ArrayList<>();
try {
IWizardContainer container = getContainer();
if (container != null && getControl() != null) {
getWizard().getContainer().run(true, true, pm -> {
pm.beginTask(PHPUnitMessages.PHPUnitSearchEngine_Searching, IProgressMonitor.UNKNOWN);
List<IType> elements = searchEngine.findPHPUnitClassesByTestCase(scriptProject, true, false,
new SubProgressMonitor(pm, IProgressMonitor.UNKNOWN));
elementsList.addAll(elements);
pm.done();
});
if (!elementsList.isEmpty()) {
PHP_UNIT_CASE_BASE_CLASS_CACHE = elementsList.toArray(new IType[elementsList.size()]);
}
}
} catch (InvocationTargetException | InterruptedException e) {
PHPUnitPlugin.log(e);
}
}
final List<IType> nonAbstractElementsList = new ArrayList<>();
try {
if (PHP_UNIT_CASE_BASE_CLASS_CACHE != null) {
for (IType type : PHP_UNIT_CASE_BASE_CLASS_CACHE) {
if (!PHPFlags.isAbstract(type.getFlags())) {
nonAbstractElementsList.add(type);
}
}
}
} catch (ModelException e) {
PHPUnitPlugin.log(e);
}
}
@Override
protected void superClassChanged() {
super.superClassChanged();
if (!fSuperClassStatus.isOK()) {
return;
}
final StatusInfo status = new StatusInfo();
String elementName = getSuperClassName();
final IContainer root = getTestContainer();
if (PHP_UNIT_CASE_BASE_CLASS_CACHE == null && root != null) {
findTestCases(DLTKCore.create(root.getProject()));
}
boolean result = false;
if (PHP_UNIT_CASE_BASE_CLASS_CACHE != null) {
for (IType type : PHP_UNIT_CASE_BASE_CLASS_CACHE) {
if (type.getElementName().equals(elementName)) {
result = true;
}
}
if (!result) {
status.setError(PHPUnitMessages.PHPUnitWizardPage_21);
}
}
fSuperClassStatus = status;
updateStatus(getStatusList());
}
@Override
protected void containerChanged() {
super.containerChanged();
if (getTestContainer() != null) {
elementToTestChanged();
}
}
@Override
protected void createElementToTestControls(final Composite composite, final int nColumns) {
createSeparator(composite, nColumns);
new Label(composite, SWT.NONE);
Composite selectionContainer = new Composite(composite, SWT.NULL);
RowLayout rowLayout = new RowLayout();
selectionContainer.setLayout(rowLayout);
rowLayout.spacing = 10;
Button clasOrFunctionElementToTestButton = new Button(selectionContainer, SWT.RADIO);
clasOrFunctionElementToTestButton.setText(PHPUnitMessages.TestCaseWizardPage_5);
clasOrFunctionElementToTestButton.setSelection(isClassOrMethodElementToTest);
clasOrFunctionElementToTestButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
isClassOrMethodElementToTest = true;
fElementToTest = null;
elementToTestChanged();
}
});
Button newPHPBlockBtn = new Button(selectionContainer, SWT.RADIO);
newPHPBlockBtn.setText(PHPUnitMessages.TestCaseWizardPage_4);
newPHPBlockBtn.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
isClassOrMethodElementToTest = false;
fElementToTest = null;
elementToTestChanged();
}
});
new Label(composite, SWT.NONE);
fElementToTestField.doFillIntoGrid(composite, nColumns);
final Text text = fElementToTestField.getTextControl(null);
LayoutUtil.setWidthHint(text, getMaxFieldWidth());
new Label(composite, SWT.NONE);
fElementToTestFileNameLabel = new Label(composite, SWT.NONE);
final GridData gridData = new GridData(GridData.FILL_HORIZONTAL);
gridData.grabExcessHorizontalSpace = true;
fElementToTestFileNameLabel.setLayoutData(gridData);
LayoutUtil.setWidthHint(fElementToTestFileNameLabel, getMaxFieldWidth());
// set default and focus
final IModelElement elementToTest = getElementToTest();
if (elementToTest != null)
setClassName(elementToTest.getElementName() + testSuffix());
}
@Override
protected void setFocus() {
fElementToTestField.setFocus();
}
@Override
protected String defaultSuperClass() {
return PHPUnitSearchEngine.CLASS_CASE;
}
private void elementToTestButtonPressed(final DialogField field) {
final IModelElement codeData = chooseElementToTest();
if (codeData != null) {
setElementToTest(codeData);
}
}
protected void elementToTestChanged() {
final StatusInfo status = new StatusInfo();
Object element = fElementToTest;
if (fElementToTest == null || !fElementToTest.getElementName().equals(fElementToTestField.getText())) {
fElementToTest = null;
element = fElementToTestField.getText();
}
final Object finalElementToTest = element;
try {
if (getContainer() != null && getContainer().getCurrentPage() != null
&& getContainer().getCurrentPage().isPageComplete()) {
getContainer().run(true, true, pm -> {
pm.beginTask(PHPUnitMessages.PHPUnitSearchEngine_Searching, IProgressMonitor.UNKNOWN);
int elementTypeToValidate;
if (isClassOrMethodElementToTest) {
elementTypeToValidate = IModelElement.TYPE;
} else {
elementTypeToValidate = IModelElement.METHOD;
}
fElementToTest = PHPUnitValidator.validateElement(finalElementToTest,
getTestContainer() != null ? getTestContainer().getProject() : null, false,
elementTypeToValidate, status);
pm.done();
});
}
} catch (InvocationTargetException | InterruptedException e) {
PHPUnitPlugin.log(e);
}
final String elementToTestName = fElementToTest != null ? fElementToTest.getPath().lastSegment() : ""; //$NON-NLS-1$
if (fElementToTestFileNameLabel != null && !fElementToTestFileNameLabel.isDisposed())
fElementToTestFileNameLabel.setText(elementToTestName);
fClassNameProposal = (fElementToTest != null ? fElementToTest.getElementName() : fElementToTestField.getText())
+ testSuffix();
if (!fClassNameManual && fClassNameDialogField != null) {
fClassNameDialogField.setText(fClassNameProposal);
}
fElementToTestStatus = status;
updateStatus(getStatusList());
}
private void elementToTestFieldChanged(final DialogField field) {
elementToTestChanged();
}
public IModelElement getElementToTest() {
return fElementToTest;
}
public String getElementToTestName() {
return fElementToTestField.getText().trim();
}
@Override
protected IStatus[] getStatusList() {
return new IStatus[] { fContainerStatus, fClassNameStatus, fFileNameStatus, fElementToTestStatus,
fSuperClassStatus };
}
@Override
public Object init(final IStructuredSelection selection) {
final Object result = super.init(selection);
if (result instanceof IType && !(result instanceof ISourceModule)) {
setElementToTest((IType) result);
}
return result;
}
public void setElementToTest(final IModelElement codeData) {
fElementToTest = codeData;
String elementName = ""; //$NON-NLS-1$
if (codeData != null) {
elementName = codeData.getElementName();
}
fElementToTestField.setText(elementName);
}
@Override
protected String testSuffix() {
return TEST_SUFFIX;
}
@Override
protected void invalidatCachedElements() {
PHP_UNIT_CASE_BASE_CLASS_CACHE = null;
}
}