/******************************************************************************* * Copyright (c) 2012 BMW Car IT 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 *******************************************************************************/ package org.jnario.spec.ui.wizards; import static com.google.common.base.Strings.isNullOrEmpty; import java.io.ByteArrayInputStream; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.jdt.core.IClassFile; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IPackageFragment; import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.search.IJavaSearchScope; import org.eclipse.jdt.core.search.SearchEngine; import org.eclipse.jdt.internal.corext.util.JavaConventionsUtil; import org.eclipse.jdt.internal.junit.BasicElementLabels; import org.eclipse.jdt.internal.junit.JUnitCorePlugin; import org.eclipse.jdt.internal.junit.Messages; import org.eclipse.jdt.internal.junit.ui.JUnitPlugin; import org.eclipse.jdt.internal.junit.util.CoreTestSearchEngine; import org.eclipse.jdt.internal.junit.util.JUnitStatus; import org.eclipse.jdt.internal.junit.util.JUnitStubUtility; import org.eclipse.jdt.internal.junit.util.LayoutUtil; import org.eclipse.jdt.internal.junit.wizards.WizardMessages; import org.eclipse.jdt.internal.ui.refactoring.contentassist.ControlContentAssistHelper; import org.eclipse.jdt.internal.ui.refactoring.contentassist.JavaTypeCompletionProcessor; import org.eclipse.jdt.junit.wizards.NewTestCaseWizardPageOne; import org.eclipse.jdt.ui.IJavaElementSearchConstants; import org.eclipse.jdt.ui.JavaUI; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.window.Window; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; 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.Display; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Link; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.dialogs.SelectionDialog; import org.jnario.ui.wizards.NewJnarioFileWizardPageOne; /** * partially copied from {@link NewTestCaseWizardPageOne} */ @SuppressWarnings("restriction") public class NewSpecWizardPageOne extends NewJnarioFileWizardPageOne { private final static String PAGE_NAME= "NewTestCaseCreationWizardPage"; //$NON-NLS-1$ public final static String CLASS_UNDER_TEST= PAGE_NAME + ".classundertest"; //$NON-NLS-1$ private NewSpecWizardPageTwo fPage2; private String fClassUnderTestText; // model private IType fClassUnderTest; // resolved model, can be null private Text fClassUnderTestControl; // control private IStatus fClassUnderTestStatus; // status private Button fClassUnderTestButton; private JavaTypeCompletionProcessor fClassToTestCompletionProcessor; private Link fLink; private Label fImage; private IResource fResource; private SpecCreator specUtil; public NewSpecWizardPageOne(NewSpecWizardPageTwo page2, SpecCreator specUtil) { super(specUtil); fPage2= page2; this.specUtil = specUtil; setDescription("Select the name of the new Spec file. You have the options to specify\nthe description and/or the class under test."); fClassToTestCompletionProcessor= new JavaTypeCompletionProcessor(false, false, true); fClassUnderTestStatus= new JUnitStatus(); fClassUnderTestText= ""; //$NON-NLS-1$ } public void init(IStructuredSelection selection) { IJavaElement element= getInitialJavaElement(selection); initContainerPage(element); initTypePage(element); // put default class to test if (element != null) { IType classToTest= null; // evaluate the enclosing type IType typeInCompUnit= (IType) element.getAncestor(IJavaElement.TYPE); if (typeInCompUnit != null) { if (typeInCompUnit.getCompilationUnit() != null) { classToTest= typeInCompUnit; } } else { ICompilationUnit cu= (ICompilationUnit) element.getAncestor(IJavaElement.COMPILATION_UNIT); if (cu != null) classToTest= cu.findPrimaryType(); else { if (element instanceof IClassFile) { try { IClassFile cf= (IClassFile) element; if (cf.isStructureKnown()) classToTest= cf.getType(); } catch(JavaModelException e) { JUnitPlugin.log(e); } } } } if (classToTest != null) { try { if (!CoreTestSearchEngine.isTestImplementor(classToTest)) { setClassUnderTest(classToTest.getFullyQualifiedName('.')); } } catch (JavaModelException e) { JUnitPlugin.log(e); } } } updateStatus(getStatusList()); } /* (non-Javadoc) * @see org.eclipse.jdt.ui.wizards.NewContainerWizardPage#handleFieldChanged(String) */ @Override protected void handleFieldChanged(String fieldName) { super.handleFieldChanged(fieldName); if (fieldName.equals(CONTAINER)) { fClassUnderTestStatus= classUnderTestChanged(); if (fClassUnderTestButton != null && !fClassUnderTestButton.isDisposed()) { fClassUnderTestButton.setEnabled(getPackageFragmentRoot() != null); } updateBuildPathMessage(); } if(fieldName.equals(CLASS_UNDER_TEST)){ if(fClassUnderTest != null && isNullOrEmpty(getTypeName())){ setTypeName(fClassUnderTest.getElementName(), true); } } updateStatus(getStatusList()); } protected IStatus[] getStatusList() { return new IStatus[] { fContainerStatus, fPackageStatus, fTypeNameStatus, fClassUnderTestStatus, fModifierStatus, fSuperClassStatus }; } /* (non-Javadoc) * @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets.Composite) */ public void createControl(Composite parent) { initializeDialogUnits(parent); Composite composite= new Composite(parent, SWT.NONE); int nColumns= 4; GridLayout layout= new GridLayout(); layout.numColumns= nColumns; composite.setLayout(layout); createContainerControls(composite, nColumns); createPackageControls(composite, nColumns); createTypeNameControls(composite, nColumns); createSeparator(composite, nColumns); createDescriptionControls(composite, nColumns); createClassUnderTestControls(composite, nColumns); //createBuildPathConfigureControls(composite, nColumns); setControl(composite); //set default and focus Dialog.applyDialogFont(composite); setFocus(); } protected void createClassUnderTestControls(Composite composite, int nColumns) { Label classUnderTestLabel= new Label(composite, SWT.LEFT | SWT.WRAP); classUnderTestLabel.setFont(composite.getFont()); classUnderTestLabel.setText(WizardMessages.NewTestCaseWizardPageOne_class_to_test_label); classUnderTestLabel.setLayoutData(new GridData()); fClassUnderTestControl= new Text(composite, SWT.SINGLE | SWT.BORDER); fClassUnderTestControl.setEnabled(true); fClassUnderTestControl.setFont(composite.getFont()); fClassUnderTestControl.setText(fClassUnderTestText); fClassUnderTestControl.addModifyListener(new ModifyListener() { public void modifyText(ModifyEvent e) { internalSetClassUnderText(((Text) e.widget).getText()); } }); GridData gd= new GridData(); gd.horizontalAlignment= GridData.FILL; gd.grabExcessHorizontalSpace= true; gd.horizontalSpan= nColumns - 2; fClassUnderTestControl.setLayoutData(gd); fClassUnderTestButton= new Button(composite, SWT.PUSH); fClassUnderTestButton.setText(WizardMessages.NewTestCaseWizardPageOne_class_to_test_browse); fClassUnderTestButton.setEnabled(getPackageFragmentRoot() != null); fClassUnderTestButton.addSelectionListener(new SelectionListener() { public void widgetDefaultSelected(SelectionEvent e) { classToTestButtonPressed(); } public void widgetSelected(SelectionEvent e) { classToTestButtonPressed(); } }); gd= new GridData(); gd.horizontalAlignment= GridData.FILL; gd.grabExcessHorizontalSpace= false; gd.horizontalSpan= 1; gd.widthHint = LayoutUtil.getButtonWidthHint(fClassUnderTestButton); fClassUnderTestButton.setLayoutData(gd); ControlContentAssistHelper.createTextContentAssistant(fClassUnderTestControl, fClassToTestCompletionProcessor); } private void updateBuildPathMessage() { if (fLink == null || fLink.isDisposed()) { return; } String message= null; IPackageFragmentRoot root= getPackageFragmentRoot(); if (root != null) { IJavaProject project= root.getJavaProject(); if (project.exists()) { if (!JUnitStubUtility.is50OrHigher(project)) { message= WizardMessages.NewTestCaseWizardPageOne_linkedtext_java5required; } } } fLink.setVisible(message != null); fImage.setVisible(message != null); if (message != null) { fLink.setText(message); } } private void classToTestButtonPressed() { IType type= chooseClassToTestType(); if (type != null) { setClassUnderTest(type.getFullyQualifiedName('.')); } } private IType chooseClassToTestType() { IPackageFragmentRoot root= getPackageFragmentRoot(); if (root == null) return null; IJavaElement[] elements= new IJavaElement[] { root.getJavaProject() }; IJavaSearchScope scope= SearchEngine.createJavaSearchScope(elements); try { SelectionDialog dialog= JavaUI.createTypeDialog(getShell(), getWizard().getContainer(), scope, IJavaElementSearchConstants.CONSIDER_CLASSES_AND_ENUMS, false, getClassUnderTestText()); dialog.setTitle(WizardMessages.NewTestCaseWizardPageOne_class_to_test_dialog_title); dialog.setMessage(WizardMessages.NewTestCaseWizardPageOne_class_to_test_dialog_message); if (dialog.open() == Window.OK) { Object[] resultArray= dialog.getResult(); if (resultArray != null && resultArray.length > 0) return (IType) resultArray[0]; } } catch (JavaModelException e) { JUnitPlugin.log(e); } return null; } /* (non-Javadoc) * @see org.eclipse.jdt.ui.wizards.NewTypeWizardPage#packageChanged() */ @Override protected IStatus packageChanged() { IStatus status= super.packageChanged(); fClassToTestCompletionProcessor.setPackageFragment(getPackageFragment()); return status; } protected IStatus classUnderTestChanged() { JUnitStatus status= new JUnitStatus(); fClassUnderTest= null; IPackageFragmentRoot root= getPackageFragmentRoot(); if (root == null) { return status; } String classToTestName= getClassUnderTestText(); if (classToTestName.length() == 0) { return status; } IStatus val= JavaConventionsUtil.validateJavaTypeName(classToTestName, root); if (val.getSeverity() == IStatus.ERROR) { status.setError(WizardMessages.NewTestCaseWizardPageOne_error_class_to_test_not_valid); return status; } IPackageFragment pack= getPackageFragment(); // can be null try { IType type= resolveClassNameToType(root.getJavaProject(), pack, classToTestName); if (type == null) { status.setError(WizardMessages.NewTestCaseWizardPageOne_error_class_to_test_not_exist); return status; } if (type.isInterface()) { status.setWarning(Messages.format(WizardMessages.NewTestCaseWizardPageOne_warning_class_to_test_is_interface, BasicElementLabels.getJavaElementName(classToTestName))); } if (pack != null && !JUnitStubUtility.isVisible(type, pack)) { status.setWarning(Messages.format(WizardMessages.NewTestCaseWizardPageOne_warning_class_to_test_not_visible, BasicElementLabels.getJavaElementName(classToTestName))); } fClassUnderTest= type; fPage2.setClassUnderTest(fClassUnderTest); } catch (JavaModelException e) { status.setError(WizardMessages.NewTestCaseWizardPageOne_error_class_to_test_not_valid); } return status; } /** * Returns the content of the class to test text field. * * @return the name of the class to test */ public String getClassUnderTestText() { return fClassUnderTestText; } /** * Returns the class to be tested. * * @return the class under test or <code>null</code> if the entered values are not valid */ public IType getClassUnderTest() { return fClassUnderTest; } /** * Sets the name of the class under test. * * @param name The name to set */ public void setClassUnderTest(String name) { if (fClassUnderTestControl != null && !fClassUnderTestControl.isDisposed()) { fClassUnderTestControl.setText(name); } internalSetClassUnderText(name); } private void internalSetClassUnderText(String name) { fClassUnderTestText= name; fClassUnderTestStatus= classUnderTestChanged(); handleFieldChanged(CLASS_UNDER_TEST); } /** * The method is called when the container has changed to validate if the project * is suited for the JUnit test class. Clients can override to modify or remove that validation. * * @return the status of the validation */ protected IStatus validateIfJUnitProject() { JUnitStatus status= new JUnitStatus(); IPackageFragmentRoot root= getPackageFragmentRoot(); if (root != null) { try { IJavaProject project= root.getJavaProject(); if (project.exists()) { if (!JUnitStubUtility.is50OrHigher(project)) { status.setError(WizardMessages.NewTestCaseWizardPageOne_error_java5required); return status; } if (project.findType(JUnitCorePlugin.JUNIT4_ANNOTATION_NAME) == null) { status.setWarning(WizardMessages.NewTestCaseWizardPageOne__error_junit4NotOnbuildpath); return status; } } } catch (JavaModelException e) { } } return status; } /* (non-Javadoc) * @see org.eclipse.jface.wizard.IWizardPage#canFlipToNextPage() */ @Override public boolean canFlipToNextPage() { return getClassUnderTest() != null; } private IType resolveClassNameToType(IJavaProject jproject, IPackageFragment pack, String classToTestName) throws JavaModelException { if (!jproject.exists()) { return null; } IType type= jproject.findType(classToTestName); // search in current package if (type == null && pack != null && !pack.isDefaultPackage()) { type= jproject.findType(pack.getElementName(), classToTestName); } // search in java.lang if (type == null) { type= jproject.findType("java.lang", classToTestName); //$NON-NLS-1$ } return type; } public void createType(IProgressMonitor monitor){ if(monitor == null){ monitor = new NullProgressMonitor(); } if(!getPackageFragment().exists()) { try { getPackageFragmentRoot().createPackageFragment(getPackageFragment().getElementName(), true, monitor); } catch (JavaModelException e) { displayError("Could not create package", e.getMessage()); } } IResource res = getPackageFragment().getResource(); IFile specFile = null; specFile = ((IFolder) res).getFile(getTypeName() + ".spec"); //$NON-NLS-1$ try { String contents = specUtil.create( getJavaProject(), getDescriptionFieldValue(), getPackageFragment(), getClassUnderTestText(), fPage2.getCheckedMethods(), monitor); specFile.create(new ByteArrayInputStream(contents.getBytes()), true, monitor); this.fResource = specFile; } catch (CoreException e) { displayError("Could not create Spec", e.getMessage()); } } public IResource getResource() { return fResource; } private void displayError(final String title, final String message) { Display.getDefault().syncExec(new Runnable() { public void run() { MessageDialog .openError(getShell(),title, message); } }); } @Override public void setTypeName(String name, boolean canBeModified) { super.setTypeName(name, canBeModified); fTypeNameStatus = typeNameChanged(); } @Override protected String title() { return "Spec"; } @Override protected String fileExtension() { return "spec"; } }