# HG changeset patch # User Theofanis Oikonomou # Date 1329237131 -3600 # Branch TestNG_2012 # Node ID 8904f692d00e18a3b79cb01fd511ffb892f2b2ff # Parent c21292347fca518b25a21705cba7e222e3edf819 TestNG 2012 branch - initial commit diff --git a/junit/src/org/netbeans/modules/junit/ClassNameTextField.java b/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/ClassNameTextField.java rename from junit/src/org/netbeans/modules/junit/ClassNameTextField.java rename to gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/ClassNameTextField.java --- a/junit/src/org/netbeans/modules/junit/ClassNameTextField.java +++ b/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/ClassNameTextField.java @@ -42,7 +42,7 @@ * made subject to such option by the copyright holder. */ -package org.netbeans.modules.junit; +package org.netbeans.modules.gsf.testrunner; import javax.swing.JTextField; import javax.swing.event.ChangeEvent; diff --git a/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/CommonTestsCfgOfCreate.java b/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/CommonTestsCfgOfCreate.java new file mode 100644 --- /dev/null +++ b/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/CommonTestsCfgOfCreate.java @@ -0,0 +1,1203 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2008 Sun + * Microsystems, Inc. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ + +package org.netbeans.modules.gsf.testrunner; + +//import org.netbeans.modules.gsf.testrunner.CommonSettings; +//import org.netbeans.modules.gsf.testrunner.ClassNameTextField; +import java.awt.*; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.util.List; +import java.util.*; +import javax.swing.*; +import javax.swing.border.Border; +import javax.swing.border.CompoundBorder; +import javax.swing.border.TitledBorder; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.plaf.UIResource; +import javax.swing.text.JTextComponent; +import org.netbeans.api.java.classpath.ClassPath; +import org.netbeans.api.java.project.JavaProjectConstants; +import org.netbeans.api.project.FileOwnerQuery; +import org.netbeans.api.project.Project; +import org.netbeans.api.project.SourceGroup; +import org.netbeans.api.project.SourceGroupModifier; +import org.netbeans.modules.gsf.testrunner.ClassNameTextField; +//import org.netbeans.modules.gsf.testrunner.CommonSettings; +//import org.netbeans.modules.gsf.testrunner.GuiUtils; +import org.netbeans.modules.gsf.testrunner.MessageStack; +import org.netbeans.modules.gsf.testrunner.api.CommonSettings; +import org.netbeans.modules.gsf.testrunner.api.CommonTestUtil; +import org.netbeans.modules.gsf.testrunner.api.GuiUtils; +import org.netbeans.modules.gsf.testrunner.api.SelfResizingPanel; +import org.openide.DialogDescriptor; +import org.openide.DialogDisplayer; +import org.openide.awt.Mnemonics; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileUtil; +import org.openide.loaders.DataFolder; +import org.openide.loaders.DataObject; +import org.openide.nodes.Node; +import org.openide.util.HelpCtx; +import org.openide.util.Lookup; +import org.openide.util.NbBundle; + + +/** + * + * @author vstejskal + * @author Marian Petras + */ +@SuppressWarnings("serial") +public class CommonTestsCfgOfCreate extends SelfResizingPanel implements ChangeListener { + + /** suffix of test classes */ + private static final String TEST_CLASS_SUFFIX = "Test"; //NOI18N + + /** + * nodes selected when the Create Tests action was invoked + */ + private Node[] nodes; + /** whether the tests will be created for multiple classes */ + private boolean multipleClasses; + /** whether a single package/folder is selected */ + private boolean singlePackage; + /** whether a single class is selected */ + private boolean singleClass; + /** test class name specified in the form (or null) */ + private String testClassName; + /** registered change listeners */ + private List changeListeners; + /** */ + private String initialMessage; + /** */ + private List testingFrameworks; +// public static final String JUNIT_TEST_FRAMEWORK = "JUnit"; //NOI18N +// public static final String TESTNG_TEST_FRAMEWORK = "TestNG"; //NOI18N + private String selectedTestingFramework = null; + + /** + * is at least one target folder/source group available? + * + * @see #isAcceptable() + */ + private boolean hasTargetFolders = false; + + /** + * is the entered class name non-empty and valid? + * + * @see #isAcceptable() + */ + private boolean classNameValid; + + /** + * is the current form contents acceptable? + * + * @see #isAcceptable() + */ + private boolean isAcceptable; + + /** layer index for a message about an empty set of target folders */ + private static final int MSG_TYPE_NO_TARGET_FOLDERS = 0; + /** layer index for a message about invalid class name */ + private static final int MSG_TYPE_CLASSNAME_INVALID = 1; + /** layer index for a message about non-default class name */ + private static final int MSG_TYPE_CLASSNAME_NOT_DEFAULT = 2; + /** layer index for a message about modified files */ + private static final int MSG_TYPE_MODIFIED_FILES = 3; + /** */ + private MessageStack msgStack = new MessageStack(4); + + public CommonTestsCfgOfCreate(Node[] nodes) { + assert (nodes != null) && (nodes.length != 0); + this.nodes = nodes; + } + + /** + * Creates a configuration panel. + * + * @param nodes nodes selected when the Create Tests action was invoked + * @param isShowMsgFilesWillBeSaved if {@code true} then a warning message + * like "Warning: All modified files will be saved." will be + * displayed on the panel, otherwise (i.e. if {@code false}) then + * the message won't be displayed. + */ + public void createCfgPanel(boolean isShowMsgFilesWillBeSaved) { +// assert (nodes != null) && (nodes.length != 0); +// this.nodes = nodes; + multipleClasses = checkMultipleClasses(); + + initBundle(); + try { + initComponents(); + if(isShowMsgFilesWillBeSaved) { + String msg = bundle.getString("MSG_MODIFIED_FILES"); // NOI18N + setMessage(msg, MSG_TYPE_MODIFIED_FILES); + } + setBorder(BorderFactory.createEmptyBorder(12, 12, 0, 11)); + addAccessibleDescriptions(); + initializeCheckBoxStates(); + fillFormData(); + checkAcceptability(); + setupUserInteraction(); + + /* + * checkAcceptability() must not be called + * before initializeCheckBoxStates() and fillFormData() + * setupUserInteraction must not be called + * before initializeCheckBoxStates() + */ + + } finally { + unlinkBundle(); + } + } + + private void addAccessibleDescriptions() { + + // window + this.getAccessibleContext().setAccessibleDescription(bundle.getString("CommonTestsCfgOfCreate.AD")); + + // text-field and combo-box + + if (this.tfClassName != null) { + this.tfClassName.setToolTipText( + bundle.getString("CommonTestsCfgOfCreate.clsName.toolTip"));//NOI18N + this.tfClassName.getAccessibleContext().setAccessibleName( + bundle.getString("CommonTestsCfgOfCreate.clsName.AN")); //NOI18N + this.tfClassName.getAccessibleContext().setAccessibleDescription( + bundle.getString("CommonTestsCfgOfCreate.clsName.AD")); //NOI18N + } + + this.cboxLocation.setToolTipText( + bundle.getString("CommonTestsCfgOfCreate.location.toolTip")); //NOI18N + this.cboxLocation.getAccessibleContext().setAccessibleName( + bundle.getString("CommonTestsCfgOfCreate.location.AN")); //NOI18N + this.cboxLocation.getAccessibleContext().setAccessibleDescription( + bundle.getString("CommonTestsCfgOfCreate.location.AD")); //NOI18N + + this.cboxLocation.setToolTipText( + bundle.getString("CommonTestsCfgOfCreate.framework.toolTip")); //NOI18N + this.cboxLocation.getAccessibleContext().setAccessibleName( + bundle.getString("CommonTestsCfgOfCreate.framework.AN")); //NOI18N + this.cboxLocation.getAccessibleContext().setAccessibleDescription( + bundle.getString("CommonTestsCfgOfCreate.framework.AD")); //NOI18N + + // check boxes + this.chkPublic.setToolTipText(bundle.getString("CommonTestsCfgOfCreate.chkPublic.toolTip")); + this.chkPublic.getAccessibleContext().setAccessibleDescription(bundle.getString("CommonTestsCfgOfCreate.chkPublic.AD")); + + this.chkProtected.setToolTipText(bundle.getString("CommonTestsCfgOfCreate.chkProtected.toolTip")); + this.chkProtected.getAccessibleContext().setAccessibleDescription(bundle.getString("CommonTestsCfgOfCreate.chkProtected.AD")); + + this.chkPackage.setToolTipText(bundle.getString("CommonTestsCfgOfCreate.chkPackage.toolTip")); + this.chkPackage.getAccessibleContext().setAccessibleDescription(bundle.getString("CommonTestsCfgOfCreate.chkPackage.AD")); + + this.chkComments.setToolTipText(bundle.getString("CommonTestsCfgOfCreate.chkComments.toolTip")); + this.chkComments.getAccessibleContext().setAccessibleDescription(bundle.getString("CommonTestsCfgOfCreate.chkComments.AD")); + + this.chkContent.setToolTipText(bundle.getString("CommonTestsCfgOfCreate.chkContent.toolTip")); + this.chkContent.getAccessibleContext().setAccessibleDescription(bundle.getString("CommonTestsCfgOfCreate.chkContent.AD")); + + this.chkJavaDoc.setToolTipText(bundle.getString("CommonTestsCfgOfCreate.chkJavaDoc.toolTip")); + this.chkJavaDoc.getAccessibleContext().setAccessibleDescription(bundle.getString("CommonTestsCfgOfCreate.chkJavaDoc.AD")); + + if (multipleClasses) { + this.chkExceptions.setToolTipText(bundle.getString("CommonTestsCfgOfCreate.chkExceptions.toolTip")); + this.chkExceptions.getAccessibleContext().setAccessibleDescription(bundle.getString("CommonTestsCfgOfCreate.chkExceptions.AD")); + + this.chkAbstractImpl.setToolTipText(bundle.getString("CommonTestsCfgOfCreate.chkAbstractImpl.toolTip")); + this.chkAbstractImpl.getAccessibleContext().setAccessibleDescription(bundle.getString("CommonTestsCfgOfCreate.chkAbstractImpl.AD")); + + this.chkPackagePrivateClasses.setToolTipText(bundle.getString("CommonTestsCfgOfCreate.chkPackagePrivateClasses.toolTip")); + this.chkPackagePrivateClasses.getAccessibleContext().setAccessibleDescription(bundle.getString("CommonTestsCfgOfCreate.chkPackagePrivateClasses.AD")); + + this.chkGenerateSuites.setToolTipText(bundle.getString("CommonTestsCfgOfCreate.chkGenerateSuites.toolTip")); + this.chkGenerateSuites.getAccessibleContext().setAccessibleDescription(bundle.getString("CommonTestsCfgOfCreate.chkGenerateSuites.AD")); + } + + } + + /** + * Checks whether multiple classes may be selected. + * It also detects whether exactly one package/folder or exactly one class + * is selected and sets values of variables {@link #singlePackage} + * and {@link #singleClass} accordingly. + * + * @return false if there is exactly one node selected + * and the node represents a single DataObject, + * not a folder or another DataObject container; + * true otherwise + */ + private boolean checkMultipleClasses() { + if (nodes.length > 1) { + return true; + } + + Lookup nodeLookup = nodes[0].getLookup(); + if (nodeLookup.lookup(DataObject.Container.class) != null) { + singlePackage = nodeLookup.lookup(DataFolder.class) + != null; + return true; + } + + singleClass = false; + DataObject dataObj = nodeLookup.lookup(DataObject.class); + if (dataObj == null) { + return true; + } + + singleClass = dataObj.getPrimaryFile().isData(); + return !singleClass; + } + + /** + * Displays a configuration dialog and updates JUnit options according + * to the user's settings. + * + * @param nodes nodes selected when the Create Test action was invoked + */ + public boolean configure() { + + // create and display the dialog: + String title = NbBundle.getMessage(GuiUtils.class, + "CommonTestsCfgOfCreate.Title"); //NOI18N + ChangeListener changeListener; + final JButton btnOK = new JButton( + NbBundle.getMessage(GuiUtils.class, "LBL_OK")); //NOI18N + btnOK.getAccessibleContext().setAccessibleName(NbBundle.getMessage(GuiUtils.class, "AN_OK")); + btnOK.getAccessibleContext().setAccessibleDescription(NbBundle.getMessage(GuiUtils.class, "AD_OK")); + btnOK.setEnabled(isAcceptable()); + addChangeListener(changeListener = new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + btnOK.setEnabled(isAcceptable()); + } + }); + + Object returned = DialogDisplayer.getDefault().notify( + new DialogDescriptor ( + this, + title, + true, //modal + new Object[] {btnOK, DialogDescriptor.CANCEL_OPTION}, + btnOK, //initial value + DialogDescriptor.DEFAULT_ALIGN, + new HelpCtx(CommonTestsCfgOfCreate.class), + (ActionListener) null + )); + removeChangeListener(changeListener); + + if (returned == btnOK) { + rememberCheckBoxStates(); + testClassName = (tfClassName != null) ? tfClassName.getText() + : null; + return true; + } + return false; + } + + /** + * Returns whether a test for a single class is to be created. + * + * @return true if there is only one node selected and the node + * represents a class + */ + public boolean isSingleClass() { + return singleClass; + } + + public boolean isSinglePackage() { + return singlePackage; + } + + /** + * Returns the class name entered in the text-field. + * + * @return class name entered in the form, + * or null if the form did not contain + * the field for entering class name + */ + public String getTestClassName() { + return testClassName; + } + + /** resource bundle used during initialization of this panel */ + public ResourceBundle bundle; + + /** + * Reads JUnit settings and initializes checkboxes accordingly. + * + * @see #rememberCheckBoxStates + */ + private void initializeCheckBoxStates() { + final CommonSettings settings = CommonSettings.getDefault(); + + chkPublic.setSelected(settings.isMembersPublic()); + chkProtected.setSelected(settings.isMembersProtected()); + chkPackage.setSelected(settings.isMembersPackage()); + chkComments.setSelected(settings.isBodyComments()); + chkContent.setSelected(settings.isBodyContent()); + chkJavaDoc.setSelected(settings.isJavaDoc()); + if (multipleClasses) { + chkGenerateSuites.setSelected(settings.isGenerateSuiteClasses()); + chkPackagePrivateClasses.setSelected( + settings.isIncludePackagePrivateClasses()); + chkAbstractImpl.setSelected(settings.isGenerateAbstractImpl()); + chkExceptions.setSelected(settings.isGenerateExceptionClasses()); + } + chkSetUp.setSelected(settings.isGenerateSetUp()); + chkTearDown.setSelected(settings.isGenerateTearDown()); + } + + /** + * Stores settings given by checkbox states to JUnit settings. + * + * @see #initializeCheckBoxStatesf + */ + private void rememberCheckBoxStates() { + final CommonSettings settings = CommonSettings.getDefault(); + + settings.setMembersPublic(chkPublic.isSelected()); + settings.setMembersProtected(chkProtected.isSelected()); + settings.setMembersPackage(chkPackage.isSelected()); + settings.setBodyComments(chkComments.isSelected()); + settings.setBodyContent(chkContent.isSelected()); + settings.setJavaDoc(chkJavaDoc.isSelected()); + if (multipleClasses) { + settings.setGenerateSuiteClasses(chkGenerateSuites.isSelected()); + settings.setIncludePackagePrivateClasses( + chkPackagePrivateClasses.isSelected()); + settings.setGenerateAbstractImpl(chkAbstractImpl.isSelected()); + settings.setGenerateExceptionClasses(chkExceptions.isSelected()); + } + settings.setGenerateSetUp(chkSetUp.isSelected()); + settings.setGenerateTearDown(chkTearDown.isSelected()); + } + + /** + * Loads a resource bundle so that it can be used during intialization + * of this panel. + * + * @see #unlinkBundle + */ + private void initBundle() { + bundle = NbBundle.getBundle(GuiUtils.class); + } + + /** + * Nulls the resource bundle so that it is not held in memory when it is + * not used. + * + * @see #initBundle + */ + private void unlinkBundle() { + bundle = null; + } + + /** + * This method is called from within the constructor to initialize the form. + */ + private void initComponents() { + setLayout(new BorderLayout(0, 12)); + + add(createNameAndLocationPanel(), BorderLayout.NORTH); + add(createMessagePanel(), BorderLayout.CENTER); + add(createCodeGenPanel(), BorderLayout.SOUTH); + } + + /** + */ + private void setupUserInteraction() { + final ItemListener listener = new CheckBoxListener(); + + chkPublic.addItemListener(listener); + chkProtected.addItemListener(listener); + chkPackage.addItemListener(listener); + } + + /** + * Listener object that listens on state changes of some check-boxes. + */ + private final class CheckBoxListener implements ItemListener { + public CheckBoxListener () {} + + @Override + public void itemStateChanged(ItemEvent e) { + final Object source = e.getSource(); + + assert source == chkPublic + || source == chkProtected + || source == chkPackage; + checkAcceptability(); + } + + } + +// public String getTestingFramework() { +// Object selectedTestingFramework = cboxFramework.getSelectedItem(); +// if(selectedTestingFramework == null) { +// return null; +// } +// return selectedTestingFramework.toString().equals(TESTNG_TEST_FRAMEWORK) ? TESTNG_TEST_FRAMEWORK : JUNIT_TEST_FRAMEWORK; +// } + + private String getTestingFrameworkFolder() { + Object tf = cboxFramework.getSelectedItem(); + if(tf == null) { + return ""; + } + return tf.toString().equals(GuiUtils.TESTNG_TEST_FRAMEWORK) ? "testng." : ""; //NOI18N + } + + private void fireFrameworkChanged() { + if (tfClassName != null) { + DataObject dataObj = nodes[0].getLookup().lookup(DataObject.class); + FileObject fileObj = dataObj.getPrimaryFile(); + + ClassPath cp = ClassPath.getClassPath(fileObj, ClassPath.SOURCE); + String className = cp.getResourceName(fileObj, '.', false); + + String prefilledName = getTestingFrameworkFolder() + className + TEST_CLASS_SUFFIX; + tfClassName.setText(prefilledName); + tfClassName.setDefaultText(prefilledName); + tfClassName.setCaretPosition(prefilledName.length()); + } + setSelectedTestingFramework(); + } + + private void setSelectedTestingFramework() { + Object tf = cboxFramework.getSelectedItem(); + if(tf != null) { + selectedTestingFramework = tf.toString(); + } + } + + public String getSelectedTestingFramework() { + return selectedTestingFramework; + } + + public void addTestingFrameworks(ArrayList testingFrameworksToAdd) { + for(String testingFramework : testingFrameworksToAdd) { + testingFrameworks.add(testingFramework); + } + cboxFramework.setModel(new DefaultComboBoxModel(testingFrameworks.toArray())); + fireFrameworkChanged(); + } + + /** + */ + private Component createNameAndLocationPanel() { + JPanel panel = new JPanel(); + + final boolean askForClassName = singleClass; + + JLabel lblClassToTest = new JLabel(); + JLabel lblClassName = askForClassName ? new JLabel() : null; + JLabel lblLocation = new JLabel(); + JLabel lblFramework = new JLabel(); + + String classToTestKey = singlePackage + ? "LBL_PackageToTest" //NOI18N + : singleClass + ? "LBL_ClassToTest" //NOI18N + : "LBL_MultipleClassesSelected"; //NOI18N + + Mnemonics.setLocalizedText( + lblClassToTest, + NbBundle.getMessage(GuiUtils.class, classToTestKey)); + if (askForClassName) { + Mnemonics.setLocalizedText( + lblClassName, + NbBundle.getMessage(GuiUtils.class, "LBL_ClassName")); //NOI18N + } + Mnemonics.setLocalizedText( + lblLocation, + NbBundle.getMessage(GuiUtils.class, "LBL_Location")); //NOI18N + Mnemonics.setLocalizedText( + lblFramework, + NbBundle.getMessage(GuiUtils.class, "LBL_Framework")); //NOI18N + + if (singlePackage || singleClass) { + lblClassToTestValue = new JLabel(); + } + if (askForClassName) { + tfClassName = new ClassNameTextField(); + tfClassName.setChangeListener(this); + } + cboxLocation = new JComboBox(); + cboxFramework = new JComboBox(); + testingFrameworks = new ArrayList(); + cboxFramework.setModel(new DefaultComboBoxModel(testingFrameworks.toArray())); + cboxFramework.addItemListener(new java.awt.event.ItemListener() { + @Override + public void itemStateChanged(java.awt.event.ItemEvent evt) { + fireFrameworkChanged(); + } + }); + + if (askForClassName) { + lblClassName.setLabelFor(tfClassName); + } + lblLocation.setLabelFor(cboxLocation); + lblFramework.setLabelFor(cboxFramework); + + if (lblClassToTestValue != null) { + Font labelFont = javax.swing.UIManager.getDefaults() + .getFont("TextField.font"); //NOI18N + if (labelFont != null) { + lblClassToTestValue.setFont(labelFont); + } + } + + panel.setLayout(new GridBagLayout()); + + GridBagConstraints gbcLeft = new GridBagConstraints(); + gbcLeft.anchor = GridBagConstraints.WEST; + gbcLeft.insets.bottom = 12; + gbcLeft.insets.right = 6; + + GridBagConstraints gbcRight = new GridBagConstraints(); + gbcRight.anchor = GridBagConstraints.WEST; + gbcRight.insets.bottom = 12; + gbcRight.weightx = 1.0f; + gbcRight.fill = GridBagConstraints.BOTH; + gbcRight.gridwidth = GridBagConstraints.REMAINDER; + + if (lblClassToTestValue != null) { + panel.add(lblClassToTest, gbcLeft); + panel.add(lblClassToTestValue, gbcRight); + } else { + panel.add(lblClassToTest, gbcRight); + } + if (askForClassName) { + panel.add(lblClassName, gbcLeft); + panel.add(tfClassName, gbcRight); + } + panel.add(lblLocation, gbcLeft); + panel.add(cboxLocation, gbcRight); + gbcLeft.insets.bottom = 0; + gbcRight.insets.bottom = 0; + panel.add(lblFramework, gbcLeft); + panel.add(cboxFramework, gbcRight); + + return panel; + } + + /** + */ + private void checkClassNameValidity() { + if (tfClassName == null) { + classNameValid = true; + return; + } + + String key = null; + final int state = tfClassName.getStatus(); + switch (state) { + case ClassNameTextField.STATUS_EMPTY: + key = "MSG_ClassnameMustNotBeEmpty"; //NOI18N + break; + case ClassNameTextField.STATUS_INVALID: + key = "MSG_InvalidClassName"; //NOI18N + break; + case ClassNameTextField.STATUS_VALID_NOT_DEFAULT: + key = "MSG_ClassNameNotDefault"; //NOI18N + break; + case ClassNameTextField.STATUS_VALID_END_NOT_TEST: + key = "MSG_ClassNameEndNotTest"; //NOI18N + break; + } + if (state != ClassNameTextField.STATUS_VALID_NOT_DEFAULT) { + setMessage(null, MSG_TYPE_CLASSNAME_NOT_DEFAULT); + } + setMessage((key != null) + ? NbBundle.getMessage(GuiUtils.class, key) + : null, + MSG_TYPE_CLASSNAME_INVALID); + + classNameValid = + (state == ClassNameTextField.STATUS_VALID) + || (state == ClassNameTextField.STATUS_VALID_NOT_DEFAULT); + } + + /** + * This method gets called if status of contents of the Class Name + * text field changes. See STATUS_xxx constants + * in class ClassNameTextField. + * + * @param e event describing the state change event + * (unused in this method) + */ + @Override + public void stateChanged(ChangeEvent e) { + checkClassNameValidity(); + checkAcceptability(); + } + + /** + */ + private void checkAcceptability() { + final boolean wasAcceptable = isAcceptable; + isAcceptable = hasTargetFolders && classNameValid; + if (isAcceptable != wasAcceptable) { + fireStateChange(); + } + } + + /** + * Are the values filled in the form acceptable? + * + * @see #addChangeListener + */ + private boolean isAcceptable() { + return isAcceptable; + } + + /** + * This method is called the first time this panel's children are painted. + * By default, this method just calls {@link #adjustWindowSize()}. + * + * @param g Graphics used to paint this panel's children + */ + @Override + protected void paintedFirstTime(java.awt.Graphics g) { + if (initialMessage != null) { + displayMessage(initialMessage); + initialMessage = null; + } + } + + /** + * Displays a given message in the message panel and resizes the dialog + * if necessary. If the message cannot be displayed immediately, + * because of this panel not displayed (painted) yet, displaying the message + * is deferred until this panel is painted. + * + * @param message message to be displayed, or null if + * the currently displayed message (if any) should be + * removed + */ + private void setMessage(final String message, final int msgType) { + String msgToDisplay = msgStack.setMessage(msgType, message); + if (msgToDisplay == null) { + return; //no change + } + + /* display the message: */ + if (!isPainted()) { + initialMessage = msgToDisplay; + } else { + displayMessage(msgToDisplay); + } + } + + /** + * Displays a given message in the message panel and resizes the dialog + * if necessary. + * + * @param message message to be displayed, or null if + * the currently displayed message (if any) should be + * removed + * @see #adjustWindowSize() + */ + private void displayMessage(String message) { + if (message == null) { + message = ""; //NOI18N + } + + txtAreaMessage.setText(message); + adjustWindowSize(); + } + + /** + */ + private Component createMessagePanel() { + Color color = UIManager.getColor("nb.errorForeground"); //NOI18N + if (color == null) { + color = new Color(89, 79, 191); //RGB suggested by Bruce in #28466 + } + txtAreaMessage = GuiUtils.createMultilineLabel("", color); //NOI18N + return txtAreaMessage; + } + + /** + * Creates a panel containing controls for settings code generation options. + * + * @return created panel + */ + private Component createCodeGenPanel() { + + /* create the components: */ + String[] chkBoxIDs; + JCheckBox[] chkBoxes; + if (multipleClasses) { + chkBoxIDs = new String[] { + GuiUtils.CHK_PUBLIC, + GuiUtils.CHK_PROTECTED, + GuiUtils.CHK_PACKAGE, + GuiUtils.CHK_PACKAGE_PRIVATE_CLASSES, + GuiUtils.CHK_ABSTRACT_CLASSES, + GuiUtils.CHK_EXCEPTION_CLASSES, + GuiUtils.CHK_SUITES, + GuiUtils.CHK_SETUP, + GuiUtils.CHK_TEARDOWN, + GuiUtils.CHK_METHOD_BODIES, + GuiUtils.CHK_JAVADOC, + GuiUtils.CHK_HINTS + }; + } else { + chkBoxIDs = new String[] { + GuiUtils.CHK_PUBLIC, + GuiUtils.CHK_PROTECTED, + GuiUtils.CHK_PACKAGE, + null, // CHK_PACKAGE_PRIVATE_CLASSES, + null, // CHK_ABSTRACT_CLASSES, + null, // CHK_EXCEPTION_CLASSES, + null, // CHK_SUITES, + GuiUtils.CHK_SETUP, + GuiUtils.CHK_TEARDOWN, + GuiUtils.CHK_METHOD_BODIES, + GuiUtils.CHK_JAVADOC, + GuiUtils.CHK_HINTS + }; + } + chkBoxes = GuiUtils.createCheckBoxes(chkBoxIDs); + int i = 0; + chkPublic = chkBoxes[i++]; + chkProtected = chkBoxes[i++]; + chkPackage = chkBoxes[i++]; + chkPackagePrivateClasses = chkBoxes[i++]; //may be null + chkAbstractImpl = chkBoxes[i++]; //may be null + chkExceptions = chkBoxes[i++]; //may be null + chkGenerateSuites = chkBoxes[i++]; //may be null + chkSetUp = chkBoxes[i++]; + chkTearDown = chkBoxes[i++]; + chkContent = chkBoxes[i++]; + chkJavaDoc = chkBoxes[i++]; + chkComments = chkBoxes[i++]; + + /* create groups of checkboxes: */ + JComponent methodAccessLevels = GuiUtils.createChkBoxGroup( + bundle.getString("CommonTestsCfgOfCreate.groupAccessLevels"), //NOI18N + new JCheckBox[] {chkPublic, chkProtected, chkPackage}); + JComponent classTypes = null; + JComponent optionalClasses = null; + if (multipleClasses) { + classTypes = GuiUtils.createChkBoxGroup( + bundle.getString("CommonTestsCfgOfCreate.groupClassTypes"), //NOI18N + new JCheckBox[] {chkPackagePrivateClasses, + chkAbstractImpl, chkExceptions}); + optionalClasses = GuiUtils.createChkBoxGroup( + bundle.getString("CommonTestsCfgOfCreate.groupOptClasses"), //NOI18N + new JCheckBox[] {chkGenerateSuites}); + } + JComponent optionalCode = GuiUtils.createChkBoxGroup( + bundle.getString("CommonTestsCfgOfCreate.groupOptCode"), //NOI18N + new JCheckBox[] {chkSetUp, chkTearDown, chkContent}); + JComponent optionalComments = GuiUtils.createChkBoxGroup( + bundle.getString("CommonTestsCfgOfCreate.groupOptComments"), //NOI18N + new JCheckBox[] {chkJavaDoc, chkComments}); + + /* create the left column of options: */ + Box leftColumn = Box.createVerticalBox(); + leftColumn.add(methodAccessLevels); + if (multipleClasses) { + leftColumn.add(Box.createVerticalStrut(11)); + leftColumn.add(classTypes); + } else { + /* + * This strut ensures that width of the left column is not limited. + * If it was limited, the rigth column would not move when the + * dialog is horizontally resized. + */ + leftColumn.add(Box.createVerticalStrut(0)); + } + leftColumn.add(Box.createVerticalGlue()); + + /* create the right column of options: */ + Box rightColumn = Box.createVerticalBox(); + if (multipleClasses) { + rightColumn.add(optionalClasses); + rightColumn.add(Box.createVerticalStrut(11)); + } + rightColumn.add(optionalCode); + rightColumn.add(Box.createVerticalStrut(11)); + rightColumn.add(optionalComments); + rightColumn.add(Box.createVerticalGlue()); + + /* compose the final panel: */ + //JPanel jpCodeGen = new SizeRestrictedPanel(false, true); + JPanel jpCodeGen = new JPanel(); + jpCodeGen.setLayout(new BoxLayout(jpCodeGen, BoxLayout.X_AXIS)); + jpCodeGen.add(leftColumn); + jpCodeGen.add(Box.createHorizontalStrut(24)); + jpCodeGen.add(rightColumn); + + /* decorate the panel: */ + addTitledBorder(jpCodeGen, + new Insets(12, 12, 11, 12), + bundle.getString("CommonTestsCfgOfCreate.jpCodeGen.title"));//NOI18N + + /* tune the layout: */ + methodAccessLevels.setAlignmentX(0.0f); + if (multipleClasses) { + classTypes.setAlignmentX(0.0f); + optionalClasses.setAlignmentX(0.0f); + } + optionalCode.setAlignmentX(0.0f); + optionalComments.setAlignmentX(0.0f); + + return jpCodeGen; + } + + /** + * Adds a border and a title around a given component. + * If the component already has some border, it is overridden (not kept). + * + * @param component component the border and title should be added to + * @param insets insets between the component and the titled border + * @param title text of the title + */ + private static void addTitledBorder(JComponent component, + Insets insets, + String title) { + Border insideBorder = BorderFactory.createEmptyBorder( + insets.top, insets.left, insets.bottom, insets.right); + Border outsideBorder = new TitledBorder( + BorderFactory.createEtchedBorder(), title); + component.setBorder(new CompoundBorder(outsideBorder, insideBorder)); + } + + /** + */ + public FileObject getTargetFolder() { + Object selectedLocation = cboxLocation.getSelectedItem(); + + if (selectedLocation == null) { + return null; + } + + if (selectedLocation instanceof SourceGroup) { + return ((SourceGroup) selectedLocation).getRootFolder(); + } + assert selectedLocation instanceof FileObject; //root folder + return (FileObject) selectedLocation; + } + + /** + * Initializes form in the Test Settings panel of the dialog. + */ + private void fillFormData() { + final DataObject dataObj = nodes[0].getLookup().lookup(DataObject.class); + final FileObject fileObj = dataObj.getPrimaryFile(); + + if (singleClass) { + assert nodes.length == 1; + + ClassPath cp = ClassPath.getClassPath(fileObj, ClassPath.SOURCE); + String className = cp.getResourceName(fileObj, '.', false); + lblClassToTestValue.setText(className); + + if (tfClassName != null) { + String prefilledName = getTestingFrameworkFolder() + className + TEST_CLASS_SUFFIX; + tfClassName.setText(prefilledName); + tfClassName.setDefaultText(prefilledName); + tfClassName.setCaretPosition(prefilledName.length()); + } + } else if (singlePackage) { + assert nodes.length == 1; + + ClassPath cp = ClassPath.getClassPath(fileObj, ClassPath.SOURCE); + String packageName = cp.getResourceName(fileObj, '.', true); + if (packageName.length() == 0) { + packageName = NbBundle.getMessage( + GuiUtils.class, + "DefaultPackageName"); //NOI18N + } + lblClassToTestValue.setText(packageName); + } else { + //PENDING + } + + setupLocationChooser(fileObj); + + checkClassNameValidity(); + } + + /** + */ + private void setupLocationChooser(FileObject refFileObject) { + Object[] targetFolders = CommonTestUtil.getTestTargets(refFileObject); + if (targetFolders.length == 0) { + Project owner = FileOwnerQuery.getOwner(refFileObject); + if (owner != null) { + if (SourceGroupModifier.createSourceGroup(owner, JavaProjectConstants.SOURCES_TYPE_JAVA, JavaProjectConstants.SOURCES_HINT_TEST) != null) { + targetFolders = CommonTestUtil.getTestTargets(refFileObject); + } + } + } + + if (targetFolders.length != 0) { + hasTargetFolders = true; + cboxLocation.setModel(new DefaultComboBoxModel(targetFolders)); + cboxLocation.setRenderer(new LocationChooserRenderer()); + } else { + hasTargetFolders = false; + //PENDING - message text: + String msgNoTargetsFound = NbBundle.getMessage( + getClass(), + refFileObject.isFolder() + ? "MSG_NoTestTarget_Fo" //NOI18N + : "MSG_NoTestTarget_Fi",//NOI18N + refFileObject.getNameExt()); + setMessage(msgNoTargetsFound, MSG_TYPE_NO_TARGET_FOLDERS); + disableComponents(); + } + } + + /** + * Renderer which specially handles values of type + * SourceGroup and FileObject. + * It displays display names of these objects, instead of their default + * string representation (toString()). + * + * @see SourceGroup#getDisplayName() + * @see FileUtil#getFileDisplayName(FileObject) + */ + private final class LocationChooserRenderer extends JLabel implements ListCellRenderer, UIResource { + + public LocationChooserRenderer () { + setOpaque(true); + } + + @Override + public Component getListCellRendererComponent( + JList list, + Object value, + int index, + boolean isSelected, + boolean cellHasFocus) { + // #93658: GTK needs name to render cell renderer "natively" + setName("ComboBox.listRenderer"); // NOI18N + + String text = value instanceof SourceGroup + ? ((SourceGroup) value).getDisplayName() + : value instanceof FileObject + ? FileUtil.getFileDisplayName((FileObject) value) + : value.toString(); + setText(text); + + if ( isSelected ) { + setBackground(list.getSelectionBackground()); + setForeground(list.getSelectionForeground()); + } + else { + setBackground(list.getBackground()); + setForeground(list.getForeground()); + } + + return this; + } + + // #93658: GTK needs name to render cell renderer "natively" + @Override + public String getName() { + String name = super.getName(); + return name == null ? "ComboBox.renderer" : name; // NOI18N + } + + } + + /** + * Registers a change listener. + * Registered change listeners are notified when acceptability + * of values in the form changes. + * + * @param l listener to be registered + * @see #isAcceptable + * @see #removeChangeListener + */ + private void addChangeListener(ChangeListener l) { + if (changeListeners == null) { + changeListeners = new ArrayList(3); + } + changeListeners.add(l); + } + + /** + * Unregisters the given change listener. + * If the given listener has not been registered before, calling this + * method does not have any effect. + * + * @param l change listener to be removed + * @see #addChangeListener + */ + private void removeChangeListener(ChangeListener l) { + if (changeListeners != null + && changeListeners.remove(l) + && changeListeners.isEmpty()) { + changeListeners = null; + } + } + + /** + * Notifies all registered change listeners about a change. + * + * @see #addChangeListener + */ + private void fireStateChange() { + if (changeListeners != null) { + ChangeEvent e = new ChangeEvent(this); + for (Iterator i = changeListeners.iterator(); i.hasNext(); ) { + ((ChangeListener) i.next()).stateChanged(e); + } + } + } + + /** + * Disables all interactive visual components of this dialog + * except the OK, Cancel and Help buttons. + */ + private void disableComponents() { + final Stack stack = new Stack(); + stack.push(this); + + while (!stack.empty()) { + Container container = stack.pop(); + Component comps[] = container.getComponents(); + for (int i = 0; i < comps.length; i++) { + final java.awt.Component comp = comps[i]; + + if (comp == txtAreaMessage) { + continue; + } + if (comp instanceof JPanel) { + JPanel panel = (JPanel) comp; + stack.push(panel); + + final Border border = panel.getBorder(); + if (border != null) { + disableBorderTitles(border); + } + continue; + } + comp.setEnabled(false); + if (comp instanceof java.awt.Container) { + Container nestedCont = (Container) comp; + if (nestedCont.getComponentCount() != 0) { + stack.push(nestedCont); + } + } + } + } + } + + /** + */ + private static void disableBorderTitles(Border border) { + + if (border instanceof TitledBorder) { + disableBorderTitle((TitledBorder) border); + return; + } + + if (!(border instanceof CompoundBorder)) { + return; + } + + Stack stack = new Stack(); + stack.push((CompoundBorder) border); + while (!stack.empty()) { + CompoundBorder cb = stack.pop(); + + Border b; + b = cb.getOutsideBorder(); + if (b instanceof CompoundBorder) { + stack.push((CompoundBorder) b); + } else if (b instanceof TitledBorder) { + disableBorderTitle((TitledBorder) b); + } + + b = cb.getInsideBorder(); + if (b instanceof CompoundBorder) { + stack.push((CompoundBorder) b); + } else if (b instanceof TitledBorder) { + disableBorderTitle((TitledBorder) b); + } + } + } + + /** + */ + private static void disableBorderTitle(TitledBorder border) { + final Color color = UIManager.getColor( + "Label.disabledForeground"); //NOI18N + if (color != null) { + border.setTitleColor(color); + } + } + + private JLabel lblClassToTestValue; + private ClassNameTextField tfClassName; + private JTextComponent txtAreaMessage; + private JComboBox cboxLocation; + private JComboBox cboxFramework; + private JCheckBox chkAbstractImpl; + private JCheckBox chkComments; + private JCheckBox chkContent; + private JCheckBox chkExceptions; + private JCheckBox chkGenerateSuites; + private JCheckBox chkJavaDoc; + private JCheckBox chkPackage; + private JCheckBox chkPackagePrivateClasses; + private JCheckBox chkProtected; + private JCheckBox chkPublic; + private JCheckBox chkSetUp; + private JCheckBox chkTearDown; + +} diff --git a/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/EmptyTestCaseWizard.java b/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/EmptyTestCaseWizard.java new file mode 100644 --- /dev/null +++ b/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/EmptyTestCaseWizard.java @@ -0,0 +1,83 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 2004-2007 Sun + * Microsystems, Inc. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ + +package org.netbeans.modules.gsf.testrunner; + +//import org.netbeans.modules.junit.GuiUtils; +//import org.netbeans.modules.junit.CommonSettings; +import org.netbeans.modules.gsf.testrunner.api.GuiUtils; +import org.netbeans.modules.gsf.testrunner.api.CommonSettings; +import org.openide.loaders.TemplateWizard; + +/** + * Wizard for an empty test case. + * + * @author Marian Petras + */ +public class EmptyTestCaseWizard extends TemplateWizard { + + /** name of property "package" */ + static final String PROP_PACKAGE = "package"; //NOI18N + /** name of property "class name" */ + static final String PROP_CLASS_NAME = "className"; //NOI18N + + // PENDING - should not be hard-coded: + static final String TESTS_ROOT_NAME = "test"; //NOI18N + + /** + * initializes the settings for the settings panel + */ + @Override + public void initialize() { + CommonSettings settings = CommonSettings.getDefault(); + + putProperty(GuiUtils.CHK_SETUP, + Boolean.valueOf(settings.isGenerateSetUp())); + putProperty(GuiUtils.CHK_TEARDOWN, + Boolean.valueOf(settings.isGenerateTearDown())); + putProperty(GuiUtils.CHK_HINTS, + Boolean.valueOf(settings.isBodyComments())); + } + +} diff --git a/junit/src/org/netbeans/modules/junit/MessageStack.java b/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/MessageStack.java rename from junit/src/org/netbeans/modules/junit/MessageStack.java rename to gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/MessageStack.java --- a/junit/src/org/netbeans/modules/junit/MessageStack.java +++ b/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/MessageStack.java @@ -42,7 +42,7 @@ * made subject to such option by the copyright holder. */ -package org.netbeans.modules.junit; +package org.netbeans.modules.gsf.testrunner; /** * Manager of layered messages. diff --git a/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/Utils.java b/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/Utils.java new file mode 100644 --- /dev/null +++ b/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/Utils.java @@ -0,0 +1,782 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 2004-2007 Sun + * Microsystems, Inc. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ + +package org.netbeans.modules.gsf.testrunner; + +import org.netbeans.modules.gsf.testrunner.EmptyTestCaseWizard; +import org.netbeans.modules.gsf.testrunner.api.CommonTestUtil; +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.netbeans.api.java.project.JavaProjectConstants; +import org.netbeans.api.java.queries.UnitTestForSourceQuery; +import org.netbeans.api.project.FileOwnerQuery; +import org.netbeans.api.project.Project; +import org.netbeans.api.project.ProjectUtils; +import org.netbeans.api.project.SourceGroup; +//import org.netbeans.modules.junit.CommonTestUtil; +import org.openide.ErrorManager; +import org.openide.cookies.EditorCookie; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileUtil; +import org.openide.filesystems.URLMapper; +import org.openide.loaders.DataObject; +import org.openide.loaders.DataObjectNotFoundException; +import org.openide.text.Line; +import org.openide.text.Line.ShowOpenType; +import org.openide.text.Line.ShowVisibilityType; +import org.openide.util.Utilities; + +/** + * + * @author Marian Petras + */ +public final class Utils { + + /** */ + private final Project project; + /** */ + private boolean sourceGroupsOnly = true; + /** */ + private SourceGroup[] javaSourceGroups; + /** */ + private Map sourcesToTestsMap; + /** */ + private Map foldersToSourceGroupsMap; + + /** + * + */ + public Utils(Project project) { + this.project = project; + } + + /** */ + static FileObject findTestsRoot(Project project) { + final SourceGroup[] sourceGroups + = new Utils(project).getJavaSourceGroups(); + for (int i = 0; i < sourceGroups.length; i++) { + FileObject root = sourceGroups[i].getRootFolder(); + if (root.getName().equals(EmptyTestCaseWizard.TESTS_ROOT_NAME)) { + return root; + } + } + return null; + } + + /** */ + static FileObject getPackageFolder( + FileObject root, + String pkgName) throws IOException { + String relativePathName = pkgName.replace('.', '/'); + FileObject folder = root.getFileObject(relativePathName); + if (folder == null) { + folder = FileUtil.createFolder(root, relativePathName); + } + return folder; + } + + /** + * Identifies and collects SourceGroups and folders + * of a given project which may serve as target folders for newly created + * test classes. + * + * @param project project whose folders are to be checked + * @param sourceGroupsOnly return only SourceGroups + * - ignore target folders not having + * a corresponding SourceGroup + * @return collection which may contain FileObjects + * or SourceGroups (or both); + * it may be empty but not null + * @author Marian Petras + */ + static Collection getTestTargets(Project project, + final boolean sourceGroupsOnly) { + final Utils utils = new Utils(project); + return utils.getTestTargets(sourceGroupsOnly); + } + + /** + * Identifies and collects root test folders of a given project. + * + * @param project project whose test folders are to be found + * @return collection of found {@code FileObject}s, possibly empty + * (but not {@code null}) + */ + public static Collection getTestFolders(Project project) { + return new Utils(project).getTestFolders(); + } + + /** + * Builds a map that containing relation between SourceGroups + * and their respective test SourceGroups. + * Each entry of the map contains a SourceGroup as a key + * and an array of test SourceGroups returned by + * UnitTestForSourceQuery for that SourceGroup + * as a value. SourceGroups that have no test + * SourceGroups assigned are omitted, i.e. the resulting + * map does not contain entries that would have empty arrays as their + * values. + * + * @param project project whose SourceGroups are to be + * checked + * @param sourceGroupsOnly return only SourceGroups + * - ignore test folders not having + * a corresponding SourceGroup + * @return created map - may be empty, may be unmodifiable + * never null + */ + static Map getSourcesToTestsMap(Project project, + final boolean sourceGroupsOnly) { + final Utils utils = new Utils(project); + return utils.getSourcesToTestsMap(sourceGroupsOnly); + } + + /** + * + */ + Project getProject() { + return project; + } + + /** + * Identifies and collects root test folders of the project. + * + * @return collection of found {@code FileObject}s + * - may be empty but never {@code null} + */ + private Collection getTestFolders() { + + /* + * Idea: + * 1) Get all SourceGroups + * 2) For each SourceGroup, ask UnitTestForSourceQuery for its related + * test SourceGroups + */ + + /* .) get all SourceGroups: */ + final SourceGroup[] sourceGroups = getJavaSourceGroups(); + if (sourceGroups.length == 0) { + return Collections.emptyList(); + } + + List result = null; + + /* .) for each SourceGroup, ask for test root folders: */ + for (SourceGroup sourceGroup : sourceGroups) { + FileObject srcFolder = sourceGroup.getRootFolder(); + FileObject[] tstFoldersRaw = getTestFoldersRaw(srcFolder); + if (tstFoldersRaw.length == 0) { + continue; + } + + for (FileObject tstFolder : tstFoldersRaw) { + if (tstFolder == null) { + continue; + } + + if (result == null) { + result = new ArrayList(2); + } + if (!result.contains(tstFolder)) { + result.add(tstFolder); + } + } + } + + /* .) pack the results: */ + if (result == null) { + return Collections.emptyList(); + } else { + assert !result.isEmpty(); + return (result.size() == 1) + ? Collections.singleton(result.get(0)) + : result; + } + } + + /** + * Identifies and collects SourceGroups and folders + * which may serve as target folders for newly created test classes. + * + * @param sourceGroupsOnly return only SourceGroups + * (skip target folders without matching + * SourceGroup) + * @return collection which may contain FileObjects + * or SourceGroups (or both); + * it may be empty but not null + * @see #getTestTargets(Project, boolean) + * @author Marian Petras + */ + private Collection getTestTargets(final boolean sourceGroupsOnly) { + + /* + * Idea: + * 1) Get all SourceGroups + * 2) For each SourceGroup, ask UnitTestForSourceQuery for its related + * test SourceGroups + * + * Union of all SourceGroups returned by UnitTestForSourceQuery + * are the test SourceGroups. + */ + + /* .) get all SourceGroups: */ + final SourceGroup[] sourceGroups = getJavaSourceGroups(); + if (sourceGroups.length == 0) { + return Collections.emptyList(); + } + + /* .) */ + createFoldersToSourceGroupsMap(sourceGroups); + Object testTargetsUnion[] = new Object[sourceGroups.length]; + int size = 0; + for (int i = 0; i < sourceGroups.length; i++) { + Object[] testTargets = getTestTargets(sourceGroups[i], + sourceGroupsOnly); + size = merge(testTargets, testTargetsUnion, size); + } + + if (size != testTargetsUnion.length) { + testTargetsUnion = CommonTestUtil.skipNulls(testTargetsUnion, new Object[0]); + } + + return Collections.unmodifiableCollection( + Arrays.asList(testTargetsUnion)); + } + + /** + * + */ + Map getSourcesToTestsMap() { + if (sourcesToTestsMap == null) { + sourcesToTestsMap = createSourcesToTestsMap(sourceGroupsOnly); + } + return sourcesToTestsMap; + } + + /** + * + */ + Map getSourcesToTestsMap(final boolean sourceGroupsOnly) { + if (sourceGroupsOnly != this.sourceGroupsOnly) { + sourcesToTestsMap = null; + this.sourceGroupsOnly = sourceGroupsOnly; + } + return getSourcesToTestsMap(); + } + + /** + * Builds a map that containing relation between SourceGroups + * and their respective test SourceGroups. + * Each entry of the map contains a SourceGroup as a key + * and an array of test SourceGroups returned by + * UnitTestForSourceQuery for that SourceGroup + * as a value. SourceGroups that have no test + * SourceGroups assigned are omitted, i.e. the resulting + * map does not contain entries that would have empty arrays as their + * values. + * + * @param sourceGroupsOnly return only SourceGroups + * - ignore test folders not having + * a corresponding SourceGroup + * @return created map - may be empty, may be unmodifiable, + * cannot be null + */ + private Map createSourcesToTestsMap(final boolean sourceGroupsOnly) { + + /* + * Idea: + * 1) Get all SourceGroups + * 2) For each SourceGroup, ask UnitTestForSourceQuery for its related + * test SourceGroups + */ + + /* .) get all SourceGroups: */ + final SourceGroup[] sourceGroups = getJavaSourceGroups(); + if (sourceGroups.length == 0) { + return Collections.emptyMap(); + } + + /* .) get test SourceGroups for each SourceGroup: */ + createFoldersToSourceGroupsMap(sourceGroups); + Object testTargetsUnion[] = new Object[sourceGroups.length]; + Map map; + map = new HashMap( + (int) ((float) sourceGroups.length * 1.33f + 0.5f), + .75f); + for (int i = 0; i < sourceGroups.length; i++) { + Object[] testTargets = getTestTargets(sourceGroups[i], + sourceGroupsOnly); + if (testTargets.length != 0) { + map.put(sourceGroups[i], testTargets); + } + } + if (map.isEmpty()) { + return Collections.emptyMap(); + } + if (map.size() == 1) { + Map.Entry entry + = map.entrySet().iterator().next(); + return Collections.singletonMap(entry.getKey(), entry.getValue()); + } + + final int finalMapSize = map.size(); + if (finalMapSize >= (sourceGroups.length - 5)) { + return map; + } + + final Map targetMap; + targetMap = new HashMap( + (int) ((float) finalMapSize * 1.25f + .5f), + .8f); + targetMap.putAll(map); + return targetMap; + } + + /** + * Merges a given set of FileObjects and + * SourceGroups to the given target set (which may contain + * same types of elements). + * The source set (array) is not modified during merge. The target + * set (array) is not modified otherwise than by adding (overwriting + * nulls) elements from the source set or by replacing elements + * with equivalent elements (i.e. pointing to the same folder). Elements are + * always added after the last non-null element of the target + * set. After the merge, it is guaranteed that all null + * elements of the target array are located at the end. The above + * constraints can only be fulfilled if parameter + * currTargetSetSize is correct and if all null + * elements of the target set are placed at the end of the array at the + * moment this method is called. The target array must contain enough + * null elements so that all elements to be added to the set + * can fit. + * + * @param setToAdd elements to be added to the target set + * - must not contain null elements + * @param targetSet array to add elements to + * @param currTargetSetSize current count of non-null elements in the + * target set (null elements are + * always at the end of the array) + * @return new size of the target set + * (number of non-null elements) + */ + private static int merge(final Object[] setToAdd, + final Object[] targetSet, + final int currTargetSetSize) { + if (setToAdd.length == 0) { + return currTargetSetSize; + } + if (currTargetSetSize == 0) { + System.arraycopy(setToAdd, 0, targetSet, 0, setToAdd.length); + return setToAdd.length; + } + int targetSetSize = currTargetSetSize; + toAdd: + for (int i = 0; i < setToAdd.length; i++) { + final Object objToAdd = setToAdd[i]; + for (int j = 0; j < targetSetSize; j++) { + final Object chosen = chooseTarget(targetSet[j], objToAdd); + if (chosen != null) { //both point to the same folder + targetSet[j] = chosen; + continue toAdd; + } + } + targetSet[targetSetSize++] = objToAdd; + } + return targetSetSize; + } + + /** + * Finds whether the given two objects defining a target folder are equal + * or not and if so, suggests which one is preferred. + * Each of the folder targets may be either a SourceGroup + * object or a FileObject folder. If both targets point + * to the same folder, one of them which is preferred is returned. + * Otherwise null is returned. + *

+ * If both targets are SourceGroups, the first target is used. + * If none of the targets is a SourceGroup, the first target is + * used. + * Otherwise (i.e. one target is a SourceGroup, + * the other is not), the SourceGroup target is returned. + * + * @param target1 one target + * @param target2 second target + * @return null if the two targets define different folders; + * or the preferred one (of the passed targets) if the two + * are equal + */ + private static Object chooseTarget(Object target1, Object target2) { + final boolean isGroup1 = target1 instanceof SourceGroup; + final boolean isGroup2 = target2 instanceof SourceGroup; + + assert isGroup1 || (target1 instanceof FileObject); + assert isGroup2 || (target2 instanceof FileObject); + + if (isGroup1 && isGroup2 && target1.equals(target2)) { + return target1; + } + + final FileObject folder1 = isGroup1 + ? ((SourceGroup) target1).getRootFolder() + : ((FileObject) target1); + final FileObject folder2 = isGroup2 + ? ((SourceGroup) target2).getRootFolder() + : ((FileObject) target2); + if (!(folder1.isFolder())) { + throw new IllegalArgumentException("target1: not a folder");//NOI18N + } + if (!(folder2.isFolder())) { + throw new IllegalArgumentException("target2: not a folder");//NOI18N + } + if (folder1.equals(folder2)) { + return (isGroup1 == isGroup2) ? target1 + : (isGroup1 ? target1 : target2); + } + return null; + } + + /** + * Returns test targets for the given SourceGroup. + * The test targets are folders which are searched when tests for a class + * from the SourceGroup are to be found. Each of the returned + * test targets may be either SourceGroup (representing + * a folder plus additional information such as display name) or simply + * a FileObject representing a folder. + * If parameter includeSourceGroups is false, + * only SourceGroups are returned (target folders without + * corresponding SourceGroups are ignored). + * + * @param src source group to find test targets for + * @param sourceGroupsOnly skip target folders without matching + * SourceGroup + * @return array which may contain FileObjects + * or SourceGroups (or both); + * it may be empty but not null + * @see CommonTestUtil#getFileObject2SourceGroupMap + */ + public Object[] getTestTargets(SourceGroup sourceGroup, + final boolean sourceGroupsOnly) { + + /* .) find test root folders: */ + final FileObject[] testFolders + = getTestFoldersRaw(sourceGroup.getRootFolder()); + + if (testFolders.length == 0) { + return new Object[0]; + } + + /* .) find SourceGroups corresponding to the FileObjects: */ + final Object[] targets = new Object[testFolders.length]; + for (int i = 0; i < targets.length; i++) { + final FileObject testFolder = testFolders[i]; + if (testFolder == null) { + continue; + } + Object srcGroup = foldersToSourceGroupsMap.get(testFolder); + targets[i] = (srcGroup != null) + ? srcGroup + : sourceGroupsOnly ? null : testFolder; + } + return CommonTestUtil.skipNulls(targets, new Object[0]); + } + + /** + * Returns an array of test folders corresponding to the given source + * folder - may contain nulls. + * + * @param srcFolder FileObject representing source code root, + * for which test root folders should be found + * @return array of FileObjects representing test root + * folders, possibly with superfluous null elements + * @see #getSourceFoldersRaw + */ + public FileObject[] getTestFoldersRaw(FileObject srcFolder) { + return getFileObjects(UnitTestForSourceQuery.findUnitTests(srcFolder), + true); + } + + /** + * Returns an array of source folders corresponding to the given test + * folder - may contain nulls. + * + * @param srcFolder FileObject representing source code root, + * for which source root folders should be found + * @return array of FileObjects representing source root + * folders, possibly with superfluous null elements + * @see #getTestFoldersRaw + */ + public FileObject[] getSourceFoldersRaw(FileObject testFolder) { + return getFileObjects(UnitTestForSourceQuery.findSources(testFolder), + false); + } + + /** + * Returns FileObjects represented by the given URLs. + * + * @param rootURLs URLs representing FileObjects + * @param srcToTest true if we are searching for test + * folders, false if we are searching + * for source folders - affects only text of warning + * log messages + * @return array of FileObjects representing source root + * folders, possibly with superfluous null elements + */ + private FileObject[] getFileObjects(final URL[] rootURLs, + final boolean srcToTest) { + if (rootURLs.length == 0) { + return new FileObject[0]; + } + + FileObject[] sourceRoots = new FileObject[rootURLs.length]; + for (int i = 0; i < rootURLs.length; i++) { + if ((sourceRoots[i] = URLMapper.findFileObject(rootURLs[i])) + == null) { + final int severity = ErrorManager.INFORMATIONAL; + if (ErrorManager.getDefault().isLoggable(severity)) { + ErrorManager.getDefault().log( + severity, + (srcToTest ? "Test" : "Source") //NOI18N + + " directory " + rootURLs[i] //NOI18N + + " declared by project " //NOI18N + + ProjectUtils.getInformation(project).getName() + + " does not exist."); //NOI18N + } + continue; + } + Project sourceRootOwner = FileOwnerQuery.getOwner(sourceRoots[i]); + if (!project.equals(sourceRootOwner)) { + sourceRoots[i] = null; + + int severity = ErrorManager.INFORMATIONAL; + if (ErrorManager.getDefault().isNotifiable(severity)) { + ErrorManager.getDefault().notify( + severity, + new IllegalStateException( + "Malformed project: Found test root (" + //NOI18N + rootURLs[i] + ')' + ' ' + + (sourceRootOwner == null + ? "does not belong to any" //NOI18N + : "belongs to a different") + //NOI18N + " project.")); //NOI18N + } + continue; + } + } + return sourceRoots; + } + + /** + */ + public static FileObject[] skipNulls(final FileObject[] fileObjs) { + if (fileObjs.length == 0) { + return fileObjs; + } + + int nullsCount = 0; + for (int i = 0; i < fileObjs.length; i++) { + if (fileObjs[i] == null) { + nullsCount++; + } + } + + if (nullsCount == 0) { + return fileObjs; + } + if (nullsCount == fileObjs.length) { + return new FileObject[0]; + } + + final FileObject[] fileObjsNew + = new FileObject[fileObjs.length - nullsCount]; + int index = 0, indexNew = 0; + while (indexNew < fileObjsNew.length) { + FileObject fileObj = fileObjs[index++]; + if (fileObj != null) { + fileObjsNew[indexNew++] = fileObj; + } + } + return fileObjsNew; + } + + /** + * Creates a map mapping folders to source groups. + * For a folder as a key, the map returns the source group having that + * folder as a root. The created map is stored to variable + * {@link #foldersToSourceGroupsMap}. + * + * @param sourceGroup source group to create a map from + * @author Marian Petras + */ + private void createFoldersToSourceGroupsMap( + final SourceGroup[] sourceGroups) { + Map result; + + if (sourceGroups.length == 0) { + result = Collections.emptyMap(); + } else { + result = new HashMap(2 * sourceGroups.length, + .5f); + for (SourceGroup sourceGroup : sourceGroups) { + result.put(sourceGroup.getRootFolder(), sourceGroup); + } + } + + foldersToSourceGroupsMap = result; + } + + /** + * + */ + public SourceGroup[] getJavaSourceGroups() { + if (javaSourceGroups == null) { + javaSourceGroups = ProjectUtils.getSources(project).getSourceGroups( + JavaProjectConstants.SOURCES_TYPE_JAVA); + } + return javaSourceGroups; + } + + /** + * Finds a SourceGroup having the specified root folder. + * If there are more SourceGroups matching, the first one + * (according to the order of elements in the array) is returned. + * + * @param sourceGroups source groups to test + * @param rootFolder root folder of a source group to be found + * @return the found SourceGroup; + * or null if no matching SourceGroup + * was found + */ + private static SourceGroup findSourceGroup(SourceGroup[] sourceGroups, + FileObject rootFolder) { + for (int i = 0; i < sourceGroups.length; i++) { + if (sourceGroups[i].getRootFolder().equals(rootFolder)) { + return sourceGroups[i]; + } + } + return (SourceGroup) null; + } + + static boolean isValidClassName(String className) { + if (className.length() == 0) { + return false; + } + char[] chars = className.toCharArray(); + int segmentStart = 0; + int i; + for (i = 0; i < chars.length; i++) { + if (chars[i] == '.') { + if (i == segmentStart) { + return false; //empty segment + } + if (!Utilities.isJavaIdentifier( + className.substring(segmentStart, i))) { + return false; //illegal name of the segment + } + segmentStart = i + 1; + } + } + if (i == segmentStart) { + return false; //empty last segment + } + if (!Utilities.isJavaIdentifier( + className.substring(segmentStart, chars.length))) { + return false; //illegal name of the last segment + } + return true; + } + + /** + */ + public static void openFile(FileObject file, int lineNum) { + + /* + * Most of the following code was copied from the Ant module, method + * org.apache.tools.ant.module.run.Hyperlink.outputLineAction(...). + */ + + if (file == null) { + java.awt.Toolkit.getDefaultToolkit().beep(); + return; + } + + try { + DataObject dob = DataObject.find(file); + EditorCookie ed = dob.getCookie(EditorCookie.class); + if (ed != null && /* not true e.g. for *_ja.properties */ + file == dob.getPrimaryFile()) { + if (lineNum == -1) { + // OK, just open it. + ed.open(); + } else { + ed.openDocument();//XXX getLineSet doesn't do it for you + try { + Line l = ed.getLineSet().getOriginal(lineNum - 1); + if (!l.isDeleted()) { + l.show(ShowOpenType.OPEN, ShowVisibilityType.FOCUS); + } + } catch (IndexOutOfBoundsException ioobe) { + // Probably harmless. Bogus line number. + ed.open(); + } + } + } else { + java.awt.Toolkit.getDefaultToolkit().beep(); + } + } catch (DataObjectNotFoundException ex1) { + ErrorManager.getDefault().notify(ErrorManager.WARNING, ex1); + } catch (IOException ex2) { + // XXX see above, should not be necessary to call openDocument + // at all + ErrorManager.getDefault().notify(ErrorManager.WARNING, ex2); + } + } + +} diff --git a/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/api/CommonSettings.java b/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/api/CommonSettings.java new file mode 100644 --- /dev/null +++ b/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/api/CommonSettings.java @@ -0,0 +1,299 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2008 Sun + * Microsystems, Inc. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ + +package org.netbeans.modules.gsf.testrunner.api; + +import java.util.prefs.Preferences; +import org.openide.util.HelpCtx; +import org.openide.util.NbBundle; +import org.openide.util.NbPreferences; + +/** Options for JUnit module, control behavior of test creation and execution. + * + * @author vstejskal + * @author Marian Petras + */ +public class CommonSettings { + private static final CommonSettings INSTANCE = new CommonSettings(); + + /** prefix for names of generated test classes */ + public static final String TEST_CLASSNAME_PREFIX = NbBundle.getMessage( + CommonSettings.class, + "PROP_test_classname_prefix"); //NOI18N + /** suffix for names of generated test classes */ + public static final String TEST_CLASSNAME_SUFFIX = NbBundle.getMessage( + CommonSettings.class, + "PROP_test_classname_suffix"); //NOI18N + /** prefix for names of generated test suites */ + public static final String SUITE_CLASSNAME_PREFIX = NbBundle.getMessage( + CommonSettings.class, + "PROP_suite_classname_prefix"); //NOI18N + /** suffix for names of generated test suites */ + public static final String SUITE_CLASSNAME_SUFFIX = NbBundle.getMessage( + CommonSettings.class, + "PROP_suite_classname_suffix"); //NOI18N + /** should it be possible to create tests for tests? */ + public static final boolean GENERATE_TESTS_FROM_TEST_CLASSES = NbBundle.getMessage( + CommonSettings.class, + "PROP_generate_tests_from_test_classes").equals("true"); //NOI18N + /** generate test initializer method by default? */ + public static final boolean DEFAULT_GENERATE_SETUP = NbBundle.getMessage( + CommonSettings.class, + "PROP_generate_setUp_default").equals("true"); //NOI18N + /** generate test finalizer method by default? */ + public static final boolean DEFAULT_GENERATE_TEARDOWN = NbBundle.getMessage( + CommonSettings.class, + "PROP_generate_tearDown_default").equals("true"); //NOI18N + /** generate test class initializer method by default? */ + public static final boolean DEFAULT_GENERATE_CLASS_SETUP = NbBundle.getMessage( + CommonSettings.class, + "PROP_generate_class_setUp_default").equals("true"); //NOI18N + /** generate test class finalizer method by default? */ + public static final boolean DEFAULT_GENERATE_CLASS_TEARDOWN = NbBundle.getMessage( + CommonSettings.class, + "PROP_generate_class_tearDown_default").equals("true"); //NOI18N + + // XXX this property has to go too - will not work any longer, need some src -> test query + private static final String PROP_FILE_SYSTEM = "fileSystem"; + public static final String PROP_MEMBERS_PUBLIC = "membersPublic"; + public static final String PROP_MEMBERS_PROTECTED = "membersProtected"; + public static final String PROP_MEMBERS_PACKAGE = "membersPackage"; + public static final String PROP_BODY_COMMENTS = "bodyComments"; + public static final String PROP_BODY_CONTENT = "bodyContent"; + public static final String PROP_JAVADOC = "javaDoc"; + public static final String PROP_GENERATE_EXCEPTION_CLASSES = "generateExceptionClasses"; + public static final String PROP_GENERATE_ABSTRACT_IMPL = "generateAbstractImpl"; + public static final String PROP_GENERATE_SUITE_CLASSES = "generateSuiteClasses"; + + public static final String PROP_INCLUDE_PACKAGE_PRIVATE_CLASSES = "includePackagePrivateClasses"; + public static final String PROP_GENERATE_MAIN_METHOD = "generateMainMethod"; + public static final String PROP_GENERATE_MAIN_METHOD_BODY = "generateMainMethodBody"; + public static final String PROP_GENERATE_SETUP = "generateSetUp"; + public static final String PROP_GENERATE_TEARDOWN = "generateTearDown"; + public static final String PROP_GENERATE_CLASS_SETUP = "generateClassSetUp"; + public static final String PROP_GENERATE_CLASS_TEARDOWN = "generateClassTearDown"; + public static final String PROP_GENERATOR = "generator"; + public static final String PROP_ROOT_SUITE_CLASSNAME = "rootSuiteClassName"; + + public static final String PROP_RESULTS_SPLITPANE_DIVIDER = "resultsSplitDivider"; + + public String displayName () { + return NbBundle.getMessage (CommonSettings.class, "LBL_junit_settings"); + } + + public HelpCtx getHelpCtx () { + return new HelpCtx(CommonSettings.class); + } + + private static Preferences getPreferences() { + return NbPreferences.forModule(CommonSettings.class); + } + + /** Default instance of this system option, for the convenience of associated classes. */ + public static CommonSettings getDefault () { + return INSTANCE; + } + + public boolean isMembersPublic() { + return getPreferences().getBoolean(PROP_MEMBERS_PUBLIC,true); + } + + public void setMembersPublic(boolean newVal) { + getPreferences().putBoolean(PROP_MEMBERS_PUBLIC,newVal); + } + + public boolean isMembersProtected() { + return getPreferences().getBoolean(PROP_MEMBERS_PROTECTED,true); + } + + public void setMembersProtected(boolean newVal) { + getPreferences().putBoolean(PROP_MEMBERS_PROTECTED,newVal); + } + + public boolean isMembersPackage() { + return getPreferences().getBoolean(PROP_MEMBERS_PACKAGE,true); + } + + public void setMembersPackage(boolean newVal) { + getPreferences().putBoolean(PROP_MEMBERS_PACKAGE,newVal); + } + + public boolean isBodyComments() { + return getPreferences().getBoolean(PROP_BODY_COMMENTS,true); + + } + + public void setBodyComments(boolean newVal) { + getPreferences().putBoolean(PROP_BODY_COMMENTS,newVal); + } + + public boolean isBodyContent() { + return getPreferences().getBoolean(PROP_BODY_CONTENT,true); + } + + public void setBodyContent(boolean newVal) { + getPreferences().putBoolean(PROP_BODY_CONTENT,newVal); + } + + public boolean isJavaDoc() { + return getPreferences().getBoolean(PROP_JAVADOC,true); + } + + public void setJavaDoc(boolean newVal) { + getPreferences().putBoolean(PROP_JAVADOC,newVal); + } + + public boolean isGenerateExceptionClasses() { + return getPreferences().getBoolean(PROP_GENERATE_EXCEPTION_CLASSES,true); + } + + public void setGenerateExceptionClasses(boolean newVal) { + getPreferences().putBoolean(PROP_GENERATE_EXCEPTION_CLASSES,newVal); + } + + + public boolean isGenerateAbstractImpl() { + return getPreferences().getBoolean(PROP_GENERATE_ABSTRACT_IMPL,true); + } + + public void setGenerateAbstractImpl(boolean newVal) { + getPreferences().putBoolean(PROP_GENERATE_ABSTRACT_IMPL,newVal); + } + + public boolean isGenerateSuiteClasses() { + return getPreferences().getBoolean(PROP_GENERATE_SUITE_CLASSES,true); + } + + public void setGenerateSuiteClasses(boolean newVal) { + getPreferences().putBoolean(PROP_GENERATE_SUITE_CLASSES,newVal); + } + + + public boolean isIncludePackagePrivateClasses() { + return getPreferences().getBoolean(PROP_INCLUDE_PACKAGE_PRIVATE_CLASSES,true); + } + + public void setIncludePackagePrivateClasses(boolean newVal) { + getPreferences().putBoolean(PROP_INCLUDE_PACKAGE_PRIVATE_CLASSES,newVal); + } + + public boolean isGenerateMainMethod() { + return getPreferences().getBoolean(PROP_GENERATE_MAIN_METHOD,true); + } + + public void setGenerateMainMethod(boolean newVal) { + getPreferences().putBoolean(PROP_GENERATE_MAIN_METHOD,newVal); + } + + public boolean isGenerateSetUp() { + return getPreferences().getBoolean(PROP_GENERATE_SETUP, + DEFAULT_GENERATE_SETUP); + } + + public void setGenerateSetUp(boolean newVal) { + getPreferences().putBoolean(PROP_GENERATE_SETUP,newVal); + } + + public boolean isGenerateTearDown() { + return getPreferences().getBoolean(PROP_GENERATE_TEARDOWN, + DEFAULT_GENERATE_TEARDOWN); + } + + public void setGenerateTearDown(boolean newVal) { + getPreferences().putBoolean(PROP_GENERATE_TEARDOWN,newVal); + } + + public boolean isGenerateClassSetUp() { + return getPreferences().getBoolean(PROP_GENERATE_CLASS_SETUP, + DEFAULT_GENERATE_CLASS_SETUP); + } + + public void setGenerateClassSetUp(boolean newVal) { + getPreferences().putBoolean(PROP_GENERATE_CLASS_SETUP, newVal); + } + + public boolean isGenerateClassTearDown() { + return getPreferences().getBoolean(PROP_GENERATE_CLASS_TEARDOWN, + DEFAULT_GENERATE_CLASS_TEARDOWN); + } + + public void setGenerateClassTearDown(boolean newVal) { + getPreferences().putBoolean(PROP_GENERATE_CLASS_TEARDOWN, newVal); + } + + public String getGenerator() { + return null;//getPreferences().get(PROP_GENERATOR, DEFAULT_GENERATOR); + } + + public void setGenerator(String generator) { + getPreferences().put(PROP_GENERATOR, generator); + } + + public String getGenerateMainMethodBody() { + return getPreferences().get(PROP_GENERATE_MAIN_METHOD_BODY, + NbBundle.getMessage(CommonSettings.class, "PROP_generate_main_method_body_default_value")); + } + + public void setGenerateMainMethodBody(String newVal) { + getPreferences().put(PROP_GENERATE_MAIN_METHOD_BODY,newVal); + } + + public String getRootSuiteClassName() { + return getPreferences().get(PROP_ROOT_SUITE_CLASSNAME, + NbBundle.getMessage(CommonSettings.class, "PROP_root_suite_classname_default_value")); + } + + public void setRootSuiteClassName(String newVal) { + getPreferences().put(PROP_ROOT_SUITE_CLASSNAME,newVal); + } + + public int getResultsSplitPaneDivider() { + return getPreferences().getInt(PROP_RESULTS_SPLITPANE_DIVIDER, -1); + } + + public void setResultsSplitPaneDivider(int newVal) { + getPreferences().putInt(PROP_RESULTS_SPLITPANE_DIVIDER, newVal); + } + +} diff --git a/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/api/CommonTestUtil.java b/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/api/CommonTestUtil.java new file mode 100644 --- /dev/null +++ b/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/api/CommonTestUtil.java @@ -0,0 +1,381 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2008 Sun + * Microsystems, Inc. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ + +package org.netbeans.modules.gsf.testrunner.api; + +import java.net.URL; +import java.util.*; +import org.netbeans.api.java.queries.UnitTestForSourceQuery; +import org.netbeans.api.project.FileOwnerQuery; +import org.netbeans.api.project.Project; +import org.netbeans.api.project.SourceGroup; +import org.netbeans.modules.gsf.testrunner.Utils; +import org.netbeans.modules.gsf.testrunner.plugin.CommonPlugin.CreateTestParam; +import org.openide.ErrorManager; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileUtil; +import org.openide.filesystems.URLMapper; +import org.openide.loaders.DataFolder; +import org.openide.loaders.DataObject; +import org.openide.nodes.Node; + +/** + * + * @author rmatous + * @author Marian Petras + * @version 1.1 + */ +public class CommonTestUtil { + static private final String JAVA_SOURCES_SUFFIX = "java"; //NOI18N + + /** + */ + public static boolean isJavaFile(FileObject fileObj) { + return "java".equals(fileObj.getExt()) //NOI18N + || "text/x-java".equals(FileUtil.getMIMEType(fileObj)); //NOI18N + } + + static public FileObject getFileObjectFromNode(Node node) { + DataObject dO; + DataFolder df; + + dO = node.getLookup().lookup(DataObject.class); + if (null != dO) { + return dO.getPrimaryFile(); + } + + df = node.getLookup().lookup(DataFolder.class); + if (null != df) { + return df.getPrimaryFile(); + } + return null; + } + + /** + * Finds all SourceGroups of the given project + * containing a class of the given name. + * + * @param project project to be searched for matching classes + * @param className class name pattern + * @return unmodifiable collection of SourceGroups + * which contain files corresponding to the given name + * (may be empty but not null) + * @author Marian Petras + */ + public static Collection findSourceGroupOwners( + final Project project, + final String className) { + final SourceGroup[] sourceGroups + = new Utils(project).getJavaSourceGroups(); + if (sourceGroups.length == 0) { + return Collections.emptyList(); + } + + final String relativePath = className.replace('.', '/') + + ".java"; //NOI18N + + ArrayList result = new ArrayList(4); + for (int i = 0; i < sourceGroups.length; i++) { + SourceGroup srcGroup = sourceGroups[i]; + FileObject root = srcGroup.getRootFolder(); + FileObject file = root.getFileObject(relativePath); + if (file != null && FileUtil.isParentOf(root, file) + && srcGroup.contains(file)) { + result.add(srcGroup); + } + } + if (result.isEmpty()) { + return Collections.emptyList(); + } + result.trimToSize(); + return Collections.unmodifiableList(result); + } + + /** + * Finds SourceGroups where a test for the given class + * can be created (so that it can be found by the projects infrastructure + * when a test for the class is to be opened or run). + * + * @param fileObject FileObject to find target + * SourceGroup(s) for + * @return an array of objects - each of them can be either + * a SourceGroup for a possible target folder + * or simply a FileObject representing a possible + * target folder (if SourceGroup) for the folder + * was not found); + * the returned array may be empty but not null + * @author Marian Petras + */ + public static Object[] getTestTargets(FileObject fileObject) { + + /* .) get project owning the given FileObject: */ + final Project project = FileOwnerQuery.getOwner(fileObject); + if (project == null) { + return new Object[0]; + } + + SourceGroup sourceGroupOwner = findSourceGroupOwner(fileObject); + if (sourceGroupOwner == null) { + return new Object[0]; + } + + /* .) get URLs of target SourceGroup's roots: */ + final URL[] rootURLs = UnitTestForSourceQuery.findUnitTests( + sourceGroupOwner.getRootFolder()); + if (rootURLs.length == 0) { + return new Object[0]; + } + + /* .) convert the URLs to FileObjects: */ + boolean someSkipped = false; + FileObject[] sourceRoots = new FileObject[rootURLs.length]; + for (int i = 0; i < rootURLs.length; i++) { + if ((sourceRoots[i] = URLMapper.findFileObject(rootURLs[i])) + == null) { + ErrorManager.getDefault().notify( + ErrorManager.INFORMATIONAL, + new IllegalStateException( + "No FileObject found for the following URL: "//NOI18N + + rootURLs[i])); + someSkipped = true; + continue; + } + if (FileOwnerQuery.getOwner(sourceRoots[i]) != project) { + ErrorManager.getDefault().notify( + ErrorManager.INFORMATIONAL, + new IllegalStateException( + "Source root found by FileOwnerQuery points " //NOI18N + + "to a different project for the following URL: " //NOI18N + + rootURLs[i])); + sourceRoots[i] = null; + someSkipped = true; + continue; + } + } + + if (someSkipped) { + FileObject roots[] = skipNulls(sourceRoots, new FileObject[0]); + if (roots.length == 0) { + return new Object[0]; + } + sourceRoots = roots; + } + + /* .) find SourceGroups corresponding to the FileObjects: */ + final Object[] targets = new Object[sourceRoots.length]; + Map map = getFileObject2SourceGroupMap(project); + for (int i = 0; i < sourceRoots.length; i++) { + SourceGroup srcGroup = map.get(sourceRoots[i]); + targets[i] = srcGroup != null ? srcGroup : sourceRoots[i]; + } + return targets; + } + + /** + * Finds a SourceGroup the given file belongs to. + * Only Java SourceGroups are taken into account. + * + * @param file FileObject whose owning + * SourceGroup to be found + * @return Java SourceGroup containing the given + * file; or null if no such + * SourceGroup was found + * @author Marian Petras + */ + public static SourceGroup findSourceGroupOwner(FileObject file) { + final Project project = FileOwnerQuery.getOwner(file); + return findSourceGroupOwner(project, file); + } + + /** + * Finds a SourceGroup the given file belongs to. + * Only Java SourceGroups are taken into account. + * + * @param project the Project the file belongs to + * @param file FileObject whose owning + * SourceGroup to be found + * @return Java SourceGroup containing the given + * file; or null if no such + * SourceGroup was found + */ + + public static SourceGroup findSourceGroupOwner(Project project, FileObject file) { + final SourceGroup[] sourceGroups + = new Utils(project).getJavaSourceGroups(); + for (int i = 0; i < sourceGroups.length; i++) { + SourceGroup srcGroup = sourceGroups[i]; + FileObject root = srcGroup.getRootFolder(); + if (((file==root)||(FileUtil.isParentOf(root,file))) && + srcGroup.contains(file)) { + return srcGroup; + } + } + return null; + } + + /** + * Creates a copy of the given array, except that null objects + * are omitted. + * The length of the returned array is (l - n), where + * l is length of the passed array and n is number + * of null elements of the array. Order of + * non-null elements is kept in the returned array. + * The returned array is always a new array, even if the passed + * array does not contain any null elements. + * + * @param objs array to copy + * @param type an empty array of the correct type to be returned + * @return array containing the same objects as the passed array, in the + * same order, just with null elements missing + * @author Marian Petras + */ + public static T[] skipNulls(final T[] objs, final T[] type) { + List resultList = new ArrayList(objs.length); + + for (int i = 0; i < objs.length; i++) { + if (objs[i] != null) { + resultList.add(objs[i]); + } + } + + return resultList.toArray(type); + } + + /** + * Creates a map from folders to SourceGroups of a given + * project. + * The map allows to ascertian for a given folder + * which SourceGroup it is a root folder of. + * + * @param project project whose SourceGroups should be in the + * returned map + * @return map from containing all SourceGroups of a given + * project, having their root folders as keys + * @author Marian Petras + */ + public static Map getFileObject2SourceGroupMap( + Project project) { + final SourceGroup[] sourceGroups + = new Utils(project).getJavaSourceGroups(); + + if (sourceGroups.length == 0) { + return Collections.emptyMap(); + } else if (sourceGroups.length == 1) { + return Collections.singletonMap(sourceGroups[0].getRootFolder(), + sourceGroups[0]); + } else { + Map map; + map = new HashMap( + Math.round(sourceGroups.length * 1.4f + .5f), + .75f); + for (int i = 0; i < sourceGroups.length; i++) { + map.put(sourceGroups[i].getRootFolder(), + sourceGroups[i]); + } + return map; + } + } + + /** + * Creates a map of parameters according to the current JUnit module + * settings.
+ * Note: The map may not contain all the necessary settings, + * i.g. name of a test class is missing. + * + * @param multipleFiles if {@code true}, the map should contain + * also settings need for creation of multiple + * tests + * @return map of settings to be used by a + * {@link org.netbeans.modules.junit.plugin JUnitPlugin} + * @see org.netbeans.modules.junit.plugin.JUnitPlugin + */ + public static Map getSettingsMap( + boolean multipleFiles) { + final CommonSettings settings = CommonSettings.getDefault(); + final Map params + = new HashMap(17); + + params.put(CreateTestParam.INC_PUBLIC, + Boolean.valueOf(settings.isMembersPublic())); + params.put(CreateTestParam.INC_PROTECTED, + Boolean.valueOf(settings.isMembersProtected())); + params.put(CreateTestParam.INC_PKG_PRIVATE, + Boolean.valueOf(settings.isMembersPackage())); + params.put(CreateTestParam.INC_CODE_HINT, + Boolean.valueOf(settings.isBodyComments())); + params.put(CreateTestParam.INC_METHOD_BODIES, + Boolean.valueOf(settings.isBodyContent())); + params.put(CreateTestParam.INC_JAVADOC, + Boolean.valueOf(settings.isJavaDoc())); + + if (multipleFiles) { + params.put(CreateTestParam.INC_GENERATE_SUITE, + Boolean.valueOf(settings.isGenerateSuiteClasses())); + params.put(CreateTestParam.INC_PKG_PRIVATE_CLASS, + Boolean.valueOf(settings.isIncludePackagePrivateClasses())); + params.put(CreateTestParam.INC_ABSTRACT_CLASS, + Boolean.valueOf(settings.isGenerateAbstractImpl())); + params.put(CreateTestParam.INC_EXCEPTION_CLASS, + Boolean.valueOf(settings.isGenerateExceptionClasses())); + } + else { + // If a class is explicitly selected then corresponding test class + // should be generated in any cases. + params.put(CreateTestParam.INC_PKG_PRIVATE_CLASS, + Boolean.valueOf(true)); + params.put(CreateTestParam.INC_ABSTRACT_CLASS, + Boolean.valueOf(true)); + params.put(CreateTestParam.INC_EXCEPTION_CLASS, + Boolean.valueOf(true)); + } + + params.put(CreateTestParam.INC_SETUP, + Boolean.valueOf(settings.isGenerateSetUp())); + params.put(CreateTestParam.INC_TEAR_DOWN, + Boolean.valueOf(settings.isGenerateTearDown())); + + return params; + } + +} diff --git a/junit/src/org/netbeans/modules/junit/GuiUtils.java b/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/api/GuiUtils.java rename from junit/src/org/netbeans/modules/junit/GuiUtils.java rename to gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/api/GuiUtils.java --- a/junit/src/org/netbeans/modules/junit/GuiUtils.java +++ b/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/api/GuiUtils.java @@ -42,7 +42,7 @@ * made subject to such option by the copyright holder. */ -package org.netbeans.modules.junit; +package org.netbeans.modules.gsf.testrunner.api; import java.awt.BorderLayout; import java.awt.Color; @@ -75,6 +75,10 @@ /** */ public static final String TEMPLATES_DIR = "Templates/JUnit"; //NOI18N + + public static final String JUNIT_TEST_FRAMEWORK = "JUnit"; //NOI18N + public static final String TESTNG_TEST_FRAMEWORK = "TestNG"; //NOI18N + /** */ public static final String CHK_PUBLIC = "Public"; //NOI18N /** */ @@ -197,7 +201,7 @@ } JCheckBox chkBox = new JCheckBox(); - String baseName = "JUnitCfgOfCreate.chk" + id; //NOI18N + String baseName = "CommonTestsCfgOfCreate.chk" + id; //NOI18N AccessibleContext accessCtx = chkBox.getAccessibleContext(); Mnemonics.setLocalizedText( chkBox, diff --git a/junit/src/org/netbeans/modules/junit/NamedObject.java b/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/api/NamedObject.java rename from junit/src/org/netbeans/modules/junit/NamedObject.java rename to gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/api/NamedObject.java --- a/junit/src/org/netbeans/modules/junit/NamedObject.java +++ b/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/api/NamedObject.java @@ -42,7 +42,7 @@ * made subject to such option by the copyright holder. */ -package org.netbeans.modules.junit; +package org.netbeans.modules.gsf.testrunner.api; /** * Object wrapper which allows to assign a name to an object. diff --git a/junit/src/org/netbeans/modules/junit/SelfResizingPanel.java b/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/api/SelfResizingPanel.java rename from junit/src/org/netbeans/modules/junit/SelfResizingPanel.java rename to gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/api/SelfResizingPanel.java --- a/junit/src/org/netbeans/modules/junit/SelfResizingPanel.java +++ b/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/api/SelfResizingPanel.java @@ -42,7 +42,7 @@ * made subject to such option by the copyright holder. */ -package org.netbeans.modules.junit; +package org.netbeans.modules.gsf.testrunner.api; import java.awt.Dimension; import javax.swing.JPanel; diff --git a/junit/src/org/netbeans/modules/junit/SizeRestrictedPanel.java b/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/api/SizeRestrictedPanel.java rename from junit/src/org/netbeans/modules/junit/SizeRestrictedPanel.java rename to gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/api/SizeRestrictedPanel.java --- a/junit/src/org/netbeans/modules/junit/SizeRestrictedPanel.java +++ b/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/api/SizeRestrictedPanel.java @@ -42,7 +42,7 @@ * made subject to such option by the copyright holder. */ -package org.netbeans.modules.junit; +package org.netbeans.modules.gsf.testrunner.api; import java.awt.Dimension; import java.awt.LayoutManager; diff --git a/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/api/TestCreatorProvider.java b/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/api/TestCreatorProvider.java new file mode 100644 --- /dev/null +++ b/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/api/TestCreatorProvider.java @@ -0,0 +1,108 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2012 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2012 Sun Microsystems, Inc. + */ +package org.netbeans.modules.gsf.testrunner.api; + +import org.netbeans.api.java.project.JavaProjectConstants; +import org.netbeans.api.project.Project; +import org.netbeans.api.project.ProjectUtils; +import org.netbeans.api.project.SourceGroup; +import org.netbeans.api.project.Sources; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileUtil; +import org.openide.nodes.Node; + +/** + * + * @author theofanis + */ +public abstract class TestCreatorProvider { + + private boolean singleClass; + private String testClassName; + private FileObject targetFolder; + + public abstract String getDisplayName(); + + public abstract boolean canHandleMultipleClasses(Node[] activatedNodes); + + public abstract boolean enable(Node[] activatedNodes); + + public abstract void createTests(Node[] activatedNodes); + + public static SourceGroup getSourceGroup(FileObject file, Project prj) { + Sources src = ProjectUtils.getSources(prj); + SourceGroup[] srcGrps = src.getSourceGroups(JavaProjectConstants.SOURCES_TYPE_JAVA); + for (SourceGroup srcGrp : srcGrps) { + FileObject rootFolder = srcGrp.getRootFolder(); + if (((file == rootFolder) || FileUtil.isParentOf(rootFolder, file)) + && srcGrp.contains(file)) { + return srcGrp; + } + } + return null; + } + + public boolean isSingleClass() { + return singleClass; + } + + public void setSingleClass(boolean singleClass) { + this.singleClass = singleClass; + } + + public FileObject getTargetFolder() { + return targetFolder; + } + + public void setTargetFolder(FileObject targetFolder) { + this.targetFolder = targetFolder; + } + + public String getTestClassName() { + return testClassName; + } + + public void setTestClassName(String testClassName) { + this.testClassName = testClassName; + } + +} diff --git a/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/api/TestMethodDebuggerAction.java b/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/api/TestMethodDebuggerAction.java new file mode 100644 --- /dev/null +++ b/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/api/TestMethodDebuggerAction.java @@ -0,0 +1,109 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2012 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2012 Sun Microsystems, Inc. + */ +package org.netbeans.modules.gsf.testrunner.api; + +import java.util.Collection; +import org.openide.awt.ActionID; +import org.openide.awt.ActionReference; +import org.openide.awt.ActionReferences; +import org.openide.awt.ActionRegistration; +import org.openide.nodes.Node; +import org.openide.util.HelpCtx; +import org.openide.util.Lookup; +import org.openide.util.NbBundle; +import org.openide.util.actions.NodeAction; + +/** + * + * @author theofanis + */ +@ActionID(id = "org.netbeans.modules.gsf.testrunner.api.TestMethodDebuggerAction", category = "CommonTestRunner") +@ActionRegistration(displayName = "#LBL_Action_DebugTestMethod") +@ActionReferences(value = {@ActionReference(path = "Editors/text/x-java/Popup", position=1797)}) +public class TestMethodDebuggerAction extends NodeAction { + + /** Creates a new instance of TestMethodDebuggerAction */ + public TestMethodDebuggerAction() { + putValue("noIconInMenu", Boolean.TRUE); //NOI18N + } + + @Override + public String getName() { + return NbBundle.getMessage(TestMethodDebuggerAction.class, "LBL_Action_DebugTestMethod"); + } + + @Override + public HelpCtx getHelpCtx() { + return HelpCtx.DEFAULT_HELP; + } + + @Override + public boolean asynchronous() { + return false; + } + + @Override + protected void performAction(Node[] activatedNodes) { + Collection providers = Lookup.getDefault().lookupAll(TestMethodDebuggerProvider.class); + for (TestMethodDebuggerProvider provider : providers) { + if(provider.canHandle(activatedNodes[0])) { + provider.debugTestMethod(activatedNodes[0]); + break; + } + } + } + + @Override + protected boolean enable(Node[] activatedNodes) { + if (activatedNodes.length == 0) { + return false; + } + Collection providers = Lookup.getDefault().lookupAll(TestMethodDebuggerProvider.class); + for (TestMethodDebuggerProvider provider : providers) { + if(provider.canHandle(activatedNodes[0])) { + return true; + } + } + return false; + } + +} diff --git a/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/api/TestMethodDebuggerProvider.java b/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/api/TestMethodDebuggerProvider.java new file mode 100644 --- /dev/null +++ b/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/api/TestMethodDebuggerProvider.java @@ -0,0 +1,65 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2012 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2012 Sun Microsystems, Inc. + */ +package org.netbeans.modules.gsf.testrunner.api; + +import org.netbeans.api.java.classpath.ClassPath; +import org.netbeans.api.project.FileOwnerQuery; +import org.netbeans.api.project.Project; +import org.netbeans.api.project.SourceGroup; +import org.netbeans.spi.java.classpath.support.ClassPathSupport; +import org.openide.filesystems.FileObject; +import org.openide.nodes.Node; +import org.openide.util.NbBundle; + +/** + * + * @author theofanis + */ +public abstract class TestMethodDebuggerProvider { + + public abstract String getProviderName(); + + public abstract boolean canHandle(Node activatedNode); + + public abstract void debugTestMethod(Node activatedNode); + +} diff --git a/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/api/TestMethodRunnerAction.java b/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/api/TestMethodRunnerAction.java new file mode 100644 --- /dev/null +++ b/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/api/TestMethodRunnerAction.java @@ -0,0 +1,107 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2012 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2012 Sun Microsystems, Inc. + */ +package org.netbeans.modules.gsf.testrunner.api; + +import java.util.Collection; +import org.openide.awt.ActionID; +import org.openide.awt.ActionReference; +import org.openide.awt.ActionReferences; +import org.openide.awt.ActionRegistration; +import org.openide.nodes.Node; +import org.openide.util.*; +import org.openide.util.actions.NodeAction; + +/** + * + * @author theofanis + */ +@ActionID(id = "org.netbeans.modules.gsf.testrunner.api.TestMethodRunnerAction", category = "CommonTestRunner") +@ActionRegistration(displayName = "#LBL_Action_RunTestMethod") +@ActionReferences(value = {@ActionReference(path = "Editors/text/x-java/Popup", position=1795)}) +public class TestMethodRunnerAction extends NodeAction { + + /** Creates a new instance of TestMethodRunnerAction */ + public TestMethodRunnerAction() { + putValue("noIconInMenu", Boolean.TRUE); //NOI18N + } + + @Override + public String getName() { + return NbBundle.getMessage(TestMethodRunnerAction.class, "LBL_Action_RunTestMethod"); + } + + @Override + public HelpCtx getHelpCtx() { + return HelpCtx.DEFAULT_HELP; + } + + @Override + public boolean asynchronous() { + return false; + } + + @Override + protected void performAction(Node[] activatedNodes) { + Collection providers = Lookup.getDefault().lookupAll(TestMethodRunnerProvider.class); + for (TestMethodRunnerProvider provider : providers) { + if (provider.canHandle(activatedNodes[0])) { + provider.runTestMethod(activatedNodes[0]); + break; + } + } + } + + @Override + protected boolean enable(Node[] activatedNodes) { + if (activatedNodes.length == 0) { + return false; + } + Collection providers = Lookup.getDefault().lookupAll(TestMethodRunnerProvider.class); + for (TestMethodRunnerProvider provider : providers) { + if (provider.canHandle(activatedNodes[0])) { + return true; + } + } + return false; + } + +} diff --git a/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/api/TestMethodRunnerProvider.java b/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/api/TestMethodRunnerProvider.java new file mode 100644 --- /dev/null +++ b/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/api/TestMethodRunnerProvider.java @@ -0,0 +1,69 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2012 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2012 Sun Microsystems, Inc. + */ +package org.netbeans.modules.gsf.testrunner.api; + +import java.io.File; +import java.io.IOException; +import org.netbeans.api.java.classpath.ClassPath; +import org.netbeans.api.project.FileOwnerQuery; +import org.netbeans.api.project.Project; +import org.netbeans.api.project.ProjectManager; +import org.netbeans.api.project.SourceGroup; +import org.netbeans.spi.java.classpath.support.ClassPathSupport; +import org.openide.filesystems.FileObject; +import org.openide.nodes.Node; +import org.openide.util.Exceptions; +import org.openide.util.NbBundle; + +/** + * + * @author theofanis + */ +public abstract class TestMethodRunnerProvider { + + public abstract String getProviderName(); + + public abstract boolean canHandle(Node activatedNode); + + public abstract void runTestMethod(Node activatedNode); + +} diff --git a/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/plugin/CommonPlugin.java b/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/plugin/CommonPlugin.java new file mode 100644 --- /dev/null +++ b/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/plugin/CommonPlugin.java @@ -0,0 +1,329 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 2006-2007 Sun + * Microsystems, Inc. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ + +package org.netbeans.modules.gsf.testrunner.plugin; + +import java.util.Map; +//import org.netbeans.modules.junit.JUnitPluginTrampoline; +import org.openide.filesystems.FileObject; + +/** + * SPI for custom implementations of support for JUnit. + * It declares methods for: + *

    + *
  • navigation between source classes and corresponding test classes + * ({@link #getTestLocation getTestLocation}, + * {@link #getTestedLocation getTestedLocation})
  • + *
  • creation of test class skeletons + * ({@link #createTests createTests})
  • + *
+ * + * @author Marian Petras + */ +public abstract class CommonPlugin { + + /** + * Default constructor for use by subclasses. + */ + protected CommonPlugin() {} + + /** + * Enumeration of test creation parameters. + */ + public enum CreateTestParam { + + /** + * key for the map of test creation parameters + * - name of the test class + */ + CLASS_NAME(99310), + /** + * key for the map of test creation parameters + * - include tests for public methods? + */ + INC_PUBLIC(99311), + /** + * key for the map of test creation parameters + * - include tests for protected methods? + */ + INC_PROTECTED(99312), + /** + * key for the map of test creation parameters + * - include tests for package-private methods? + */ + INC_PKG_PRIVATE(99313), + /** + * key for the map of test creation parameters + * - generate test initializer method ({@code setup()}/{@code @Before})? + */ + INC_SETUP(99314), + /** + * key for the map of test creation parameters + * - generate test finalizer method ({@code tearDown()}/{@code @After})? + */ + INC_TEAR_DOWN(99315), + /** + * key for the map of test creation parameters + * - generate test class initializer method ({@code @BeforeClass})? + */ + INC_CLASS_SETUP(99323), + /** + * key for the map of test creation parameters + * - generate test class finalizer method ({@code @AfterClass})? + */ + INC_CLASS_TEAR_DOWN(99324), + /** + * key for the map of test creation parameters + * - generate default test method bodies? + */ + INC_METHOD_BODIES(99316), + /** + * key for the map of test creation parameters + * - generate Javadoc comments for test methods? + */ + INC_JAVADOC(99317), + /** + * key for the map of test creation parameters + * - generate source code hints? + */ + INC_CODE_HINT(99318), + /** + * key for the map of test creation parameters + * - generate test classes for package-private classes? + */ + INC_PKG_PRIVATE_CLASS(99319), + /** + * key for the map of test creation parameters + * - generate test classes for abstract classes? + */ + INC_ABSTRACT_CLASS(99320), + /** + * key for the map of test creation parameters + * - generate test classes for exception classes? + */ + INC_EXCEPTION_CLASS(99321), + /** + * key for the map of test creation parameters + * - generate test suites for packages? + */ + INC_GENERATE_SUITE(99322); + + private final int idNumber; + + CreateTestParam(int idNumber) { + this.idNumber = idNumber; + } + + /** + * Return a unique number of this enum element. + * + * @return unique number of this enum element + */ + public int getIdNumber() { + return idNumber; + } + + } + + /** + * Data structure for storage of specification of a Java element or + * a Java file. + */ + public static final class Location { + //** */ + //public static final Set CLASS_LIKE_ELEM_TYPES; + //** */ + //public static final Set SUPPORTED_ELEM_TYPES; + /** + * holds specification of a Java file + */ + private final FileObject fileObject; +// /** +// */ +// private final ElementHandle elementHandle; +// +// static { +// CLASS_LIKE_ELEM_TYPES = EnumSet.of(ElementKind.CLASS, +// ElementKind.INTERFACE, +// ElementKind.ENUM); +// EnumSet elemTypes; +// elemTypes = EnumSet.copyOf(CLASS_LIKE_ELEM_TYPES); +// elemTypes.addAll(EnumSet.of(ElementKind.METHOD, +// ElementKind.CONSTRUCTOR, +// ElementKind.STATIC_INIT)); +// SUPPORTED_ELEM_TYPES = Collections.unmodifiableSet(elemTypes); +// } + + /** + * Creates a new instance. + * + * @param fileObject the {@code FileObject} + * + * + * + */ + public Location(FileObject fileObject/*, + Element element*/) { + if (fileObject == null) { + throw new IllegalArgumentException("fileObject is null");//NOI18N + } + +// while ((element != null) +// && !SUPPORTED_ELEM_TYPES.contains(element.getKind())) { +// element = element.getEnclosingElement(); +// } + + this.fileObject = fileObject; + //this.elementHandle = (element != null) + // ? ElementHandle.create(element) + // : null; + } + + /** + * Returns the {@code FileObject}. + * + * @return the {@code FileObject} held in this instance + */ + public FileObject getFileObject() { + return fileObject; + } + +// /** +// */ +// public ElementHandle getElementHandle() { +// return elementHandle; +// } + + } + + /** + * Returns a specification of a Java element or file representing test + * for the given source Java element or file. + * + * @param sourceLocation specification of a Java element or file + * @return specification of a corresponding test Java element or file, + * or {@code null} if no corresponding test Java file is available + */ + protected abstract Location getTestLocation(Location sourceLocation); + + /** + * Returns a specification of a Java element or file that is tested + * by the given test Java element or test file. + * + * @param testLocation specification of a Java element or file + * @return specification of a Java element or file that is tested + * by the given Java element or file. + */ + protected abstract Location getTestedLocation(Location testLocation); + + /** + * Informs whether the plugin is capable of creating tests at the moment. + * The default implementation returns {@code true}. + * + * @return {@code true} if the plugin is able of creating tests + * for the given {@code FileObject}s, {@code false} otherwise + * @see #createTests + */ + protected boolean canCreateTests(FileObject... fileObjects) { + return true; + } + + /** + * Creates test classes for given source classes. + * If the plugin does not support creating tests, implementation of this + * method should return {@code null}. + * + * @param filesToTest source files for which test classes should be + * created + * @param targetRoot root folder of the target source root + * @param params parameters of creating test class + * - each key is an {@code Integer} whose value is equal + * to some of the constants defined in the class; + * the value is either + * a {@code String} (for key with value {@code CLASS_NAME}) + * or a {@code Boolean} (for other keys) + * @return created test files, or {@code null} if no test classes were + * created and/or updated + * @see #canCreateTests + */ + protected abstract FileObject[] createTests( + FileObject[] filesToTest, + FileObject targetRoot, + Map params); + +// /** +// * Determines whether the "create JUnit tests" functionality +// * should be enabled. +// * Before this method is called, other common pre-requisites are checked +// * (only Java classes or folders selected, all of them from the same source +// * of a Java project, all of them being valid {@code DataObject}s). +// * If some of the pre-requisites are not met, the functionality is disabled +// * and this method is not called. +// * +// * @return {@code true} if this action should be enabled, +// * {@code false} otherwise; +// * the default implementation returns always {@code true} +// */ +// protected boolean canCreateTests() { +// return true; +// } + + /** + * Called immediately after the Create Test action was called. + * It can be used as a trigger for additional checks and/or for displaying + * user dialogs etc. It is always called from the event-dispatching thread. + * + * @param selectedFiles files and folders/packages that were selected + * when the action was called + * @return {@code true} if the action can continue, + * {@code false} if the action should not continue; + * the default implementation returns always {@code true} + */ + protected boolean createTestActionCalled(FileObject[] selectedFiles) { + // assert EventQueue.isDispatchThread(); #170707 + + return true; + } + +} diff --git a/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/resources/ignored_16.png b/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/resources/ignored_16.png new file mode 100644 index 0000000000000000000000000000000000000000..7edff2fade8cc4cd788bec931cb2f0851275621b GIT binary patch literal 907 zc$@)?19bd}P)z?PCM1;1s zHUNO@x?pA~rJA~~uM*K_E|&{G1gop7A`HVHjYeZE5{Y1BWCY1%5~gW_h~Rl1?(gqW zEEeH;9-`6cPa(wk`ucjP1Aymwi?6S*W9f7nnM?-V-Q7@1LDMt{A;8Q?CX+~~(>Ojp z#`X2}SR@iz1n{?3tJMZtt=9KQBqAp#Ct=$*dV6~ji^ZUnf|L?cN+_jZ7zWbmG)kos zJkR^1SS)@g&+}$o*EPq-$I;W%1KYMyC=_sYbp;{<5kb>5EH5u3o6RB~k7I6b4zBB( zp67id-}i^5l<4g2gp?95FE6;eyTi`T4t95UQLonl0L^9-<#HLOX~MEBD5c>0{ukZ% z{h>r60U`o3wrxWQ0V0AB0znW!XXet=)6-Yq_rc7NQX(3S zLI{D0i3zN&tsx$dLrRHMDupl%!OW;sDq!Z44&c0AuYavnDzGdI@pv4uSPV-`OBfv; z{b*c!dplC86qp&+Y88&-Kq>XF&dmElh~=ZBBeTE1ADK)B3kwVA>gxJb@x8r01VI4T zb+Ns@4IxC6ng7u)E-ro@9v(Jowc4MK<6vfH=A(h{Ff)Q6K%>z>KA*?g*%@?Q|Lfr3 z;D-(XLWoVnFfym7r(?Ibx5#F*uq+FPVSIe2TCHMhYYXLa8A_?2LWs>zW160x7RnG*uq+EigolR*IF18N)0#xIN<^Fad_MdncxP&AY9I{5S!Ny%!*J;Tge4+6 h7eee83WZN|{tupadJ9z_E^Yt-002ovPDHLkV1hgNkNp4u diff --git a/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/resources/ok_withErrors_16.png b/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/resources/ok_withErrors_16.png new file mode 100644 index 0000000000000000000000000000000000000000..bc1e6be9d6e7c0bf4230930012210e1714582be8 GIT binary patch literal 725 zc$@*%0xJE9P)hitF)eJ1Cg7ENXYYJ19{ z?<~UA&O&kXzOh%2%+?fmarH_hTo1z$qgufG=Ke;^&(8}=pPWNXeK@#J1guG=g`_qWBC7mgcv=d}L_dzP zjgba_G1Hn7@a5ZQ%+1ZAWB4vqm2z-B_lW>E4MA;`Bj}0@mhnE=9d-;`2Sv}Z+9rjW z-@Fg4@D_UR69KMAX;IPO1^HzuQjF2C+rPu%aG>dBHSU;Auy%LDNaRHP*-hX+5#W+Y zgWHRx2&mYAZG|ql@uEruaJc!IR*Pwa0bj?)1ia?6;4pf>^bAo{?0Hgx!0L_gEtQB6 z%Xq&CsA1b|<>h#*(fs;}yyi3h?dMC%D3(UNFG{hyUIxE1DZ(mu;KQsHdM2_aCZboR zf~~I)HnUmOe5PL!K%}5l*Lc^D@=KecZt+EM-4-aSWGG>xNoIKN?~j4lSiFjj5jCHc zI0X>7QxK)o0UFtw?E&Srorr&^Kmij?goI$g#|N{cqXJ&@S-~FxOCdyoq@;4%PjBcT zEqW^nC7zy`QYxL`vopjL|2Q&603)2SH;U+VHruw6tYz~LYVftCqM~*K00000NkvXX Hu0mjfOD$gg diff --git a/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/resources/skipped_16.png b/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/resources/skipped_16.png new file mode 100644 index 0000000000000000000000000000000000000000..09f3651c0be99fb82e221c7e92039659f59af31b GIT binary patch literal 855 zc$@)O1E~CoP)V|9RgzXPf7&Hpb~J&z5sJCnAOsNH>Gb5+X^&-XQ0USywSCg6byeBJc%k z*+h*X5oRmVyz-(DoS=rKTbc)DYj5YcowIZHKmV8COBdxju=PX470K$9Wm$fcF*dTI$R)|w=r?EUq zSJz6W?@#YB%a*gHHC@MK!KSci;|U4C!I##sAyr4AWGx+82|<3o%-!(^batjG&MiFW zN9#-==qH~mF&&J<{_Zw9Sf{aPus)<~t0!bAM$;33Sa zT6qHHGmuK5(P*VGrSP)S6(nndm{KFF1U~!e2A>XHt#TkSw4%8oj&wbg@a~$?u>Zo? zUpZ2V8scFeTKv1h?qiquWpt7n|NkDOP$c3}o@i<0#ii>EaKq-`vShkB4iWSiy&#cd|ZdEg%e{x*4ty>lGT^jmYo*lWD8@n^P zwR`hw{Mx{>9UR9)coL-~LDNT5BF4tfG@I6EIC|&|m`2~J{kuk%UU}OGX9kk>HN88w zKSjk=WGCjB$`w#j(Uh#EE!{vQ-6jza(d002ovPDHLkV1hY!q+MessageStack. * - * @author Marian Petras + * @author theofanis */ public class MessageStackTest extends TestCase { @@ -326,5 +325,4 @@ return "ERROR IN TEST CODE"; } } - } diff --git a/junit/src/org/netbeans/modules/junit/CreateTestAction.java b/junit/src/org/netbeans/modules/junit/CreateTestAction.java deleted file mode 100644 --- a/junit/src/org/netbeans/modules/junit/CreateTestAction.java +++ /dev/null @@ -1,456 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved. - * - * Oracle and Java are registered trademarks of Oracle and/or its affiliates. - * Other names may be trademarks of their respective owners. - * - * The contents of this file are subject to the terms of either the GNU - * General Public License Version 2 only ("GPL") or the Common - * Development and Distribution License("CDDL") (collectively, the - * "License"). You may not use this file except in compliance with the - * License. You can obtain a copy of the License at - * http://www.netbeans.org/cddl-gplv2.html - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the - * specific language governing permissions and limitations under the - * License. When distributing the software, include this License Header - * Notice in each file and include the License file at - * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the GPL Version 2 section of the License file that - * accompanied this code. If applicable, add the following below the - * License Header, with the fields enclosed by brackets [] replaced by - * your own identifying information: - * "Portions Copyrighted [year] [name of copyright owner]" - * - * Contributor(s): - * - * The Original Software is NetBeans. The Initial Developer of the Original - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun - * Microsystems, Inc. All Rights Reserved. - * - * If you wish your version of this file to be governed by only the CDDL - * or only the GPL Version 2, indicate your decision by adding - * "[Contributor] elects to include this software in this distribution - * under the [CDDL or GPL Version 2] license." If you do not indicate a - * single choice of license, a recipient has the option to distribute - * your version of this file under either the CDDL, the GPL Version 2 or - * to extend the choice of license to its licensees as provided above. - * However, if you add GPL Version 2 code and therefore, elected the GPL - * Version 2 license, then the option applies only if the new code is - * made subject to such option by the copyright holder. - */ - -package org.netbeans.modules.junit; - -import java.awt.EventQueue; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import javax.swing.Action; -import org.netbeans.api.java.classpath.ClassPath; -import org.netbeans.api.project.FileOwnerQuery; -import org.netbeans.api.project.Project; -import org.netbeans.api.project.SourceGroup; -import org.netbeans.modules.junit.plugin.JUnitPlugin; -import org.netbeans.modules.junit.plugin.JUnitPlugin.CreateTestParam; -import org.netbeans.spi.java.classpath.support.ClassPathSupport; -import org.openide.DialogDisplayer; -import org.openide.NotifyDescriptor; -import org.openide.filesystems.FileObject; -import org.openide.loaders.DataObject; -import org.openide.loaders.DataObjectNotFoundException; -import org.openide.nodes.Node; -import org.openide.util.Exceptions; -import org.openide.util.HelpCtx; -import org.openide.util.NbBundle; -import org.openide.cookies.EditorCookie; -import org.openide.cookies.SaveCookie; -import org.openide.loaders.DataFolder; -import org.openide.util.RequestProcessor; - -/** Action sensitive to some cookie that does something useful. - * - * @author vstejskal, David Konecny - * @author Marian Petras - * @author Ondrej Rypacek - */ -public final class CreateTestAction extends TestAction { - - public CreateTestAction() { - putValue("noIconInMenu", Boolean.TRUE); //NOI18N - } - - /* public members */ - - @Override - public String getName() { - return NbBundle.getMessage(CreateTestAction.class, - "LBL_Action_CreateTest"); //NOI18N - } - - @Override - public HelpCtx getHelpCtx() { - return new HelpCtx(CreateTestAction.class); - } - - @Override - protected void initialize() { - super.initialize(); - putProperty(Action.SHORT_DESCRIPTION, - NbBundle.getMessage(CreateTestAction.class, - "HINT_Action_CreateTest")); //NOI18N - } - - @Override - protected String iconResource() { - return "org/netbeans/modules/junit/resources/" //NOI18N - + "CreateTestActionIcon.gif"; //NOI18N - } - - @Override - protected boolean enable(Node[] nodes) { - if (nodes.length == 0) { - return false; - } - - /* - * In most cases, there is just one node selected - that is why - * this case is handled in a special, more effective way - * (no collections and iterators created). - */ - if (nodes.length == 1) { - final Node node = nodes[0]; - DataObject dataObj; - FileObject fileObj; - Project project; - if (((dataObj = node.getCookie(DataObject.class)) != null) - && ((fileObj = dataObj.getPrimaryFile()) != null) - && fileObj.isValid() - && ((project = FileOwnerQuery.getOwner(fileObj)) != null) - && (getSourceGroup(fileObj, project) != null) - && (TestUtil.isJavaFile(fileObj) - || (node.getCookie(DataFolder.class) != null))) { - - JUnitPlugin plugin = TestUtil.getPluginForProject(project); - return JUnitPluginTrampoline.DEFAULT.canCreateTests(plugin, - fileObj); - } else { - return false; - } - } - - final Collection fileObjs - = new ArrayList(nodes.length); - Project theProject = null; - boolean result = false; - for (Node node : nodes) { - DataObject dataObj = node.getCookie(DataObject.class); - if (dataObj != null) { - FileObject fileObj = dataObj.getPrimaryFile(); - if ((fileObj == null) || !fileObj.isValid()) { - continue; - } - - fileObjs.add(fileObj); - - Project prj = FileOwnerQuery.getOwner(fileObj); - if (prj != null) { - if (theProject == null) { - theProject = prj; - } - if (prj != theProject) { - return false; /* files from different projects */ - } - - if ((getSourceGroup(fileObj, prj) != null) - && (TestUtil.isJavaFile(fileObj) - || (node.getCookie(DataFolder.class) != null))) { - result = true; - } - } - } - } - - if (theProject != null) { - JUnitPlugin plugin = TestUtil.getPluginForProject(theProject); - result &= JUnitPluginTrampoline.DEFAULT.canCreateTests( - plugin, - fileObjs.toArray(new FileObject[fileObjs.size()])); - } - - return result; - } - - /** - * Checks that the selection of nodes the dialog is invoked on is valid. - * @return String message describing the problem found or null, if the - * selection is ok - */ - private static String checkNodesValidity(Node[] nodes) { - FileObject[] files = getFiles(nodes); - - Project project = getProject(files); - if (project == null) { - return NbBundle.getMessage(CreateTestAction.class, - "MSG_multiproject_selection"); //NOI18N - } - - if (!checkPackages(files)) { - return NbBundle.getMessage(CreateTestAction.class, - "MSG_invalid_packages"); //NOI18N - } - - return null; - } - - /** - * Check that all the files (folders or java files) have correct java - * package names. - * @return true if all are fine - */ - private static boolean checkPackages(FileObject[] files) { - if (files.length == 0) { - return true; - } else { - Project project = FileOwnerQuery.getOwner(files[0]); - for (int i = 0 ; i < files.length; i++) { - String packageName = getPackage(project, files[i]); - if ((packageName == null) - || !TestUtil.isValidPackageName(packageName)) { - return false; - } - } - return true; - } - } - - /** - * Get the package name of file. - * - * @param project owner of the file (for performance reasons) - * @param file the FileObject whose packagename to get - * @return package name of the file or null if it cannot be retrieved - */ - private static String getPackage(Project project, FileObject file) { - SourceGroup srcGrp = TestUtil.findSourceGroupOwner(project, file); - if (srcGrp!= null) { - ClassPath cp = ClassPathSupport.createClassPath( - new FileObject [] {srcGrp.getRootFolder()}); - return cp.getResourceName(file, '.', false); - } else { - return null; - } - } - - - private static FileObject[] getFiles(Node[] nodes) { - FileObject[] ret = new FileObject[nodes.length]; - for (int i = 0 ; i < nodes.length ; i++) { - ret[i] = TestUtil.getFileObjectFromNode(nodes[i]); - } - return ret; - } - - /** - * Get the single project for nodes if there is such. - * If the nodes belong to different projects or some of the nodes doesn't - * have a project, return null. - */ - private static Project getProject(FileObject[] files) { - Project project = null; - for (int i = 0 ; i < files.length; i++) { - Project nodeProject = FileOwnerQuery.getOwner(files[i]); - if (project == null) { - project = nodeProject; - } else if (project != nodeProject) { - return null; - } - } - return project; - } - - @Override - protected void performAction(Node[] nodes) { - String problem; - if ((problem = checkNodesValidity(nodes)) != null) { - // TODO report problem - NotifyDescriptor msg = new NotifyDescriptor.Message( - problem, NotifyDescriptor.WARNING_MESSAGE); - DialogDisplayer.getDefault().notify(msg); - return; - } - - final FileObject[] filesToTest = getFileObjectsFromNodes(nodes); - if (filesToTest == null) { - return; //XXX: display some message - } - - /* Determine the plugin to be used: */ - final JUnitPlugin plugin = TestUtil.getPluginForProject( - FileOwnerQuery.getOwner(filesToTest[0])); - - if (!JUnitPluginTrampoline.DEFAULT.createTestActionCalled( - plugin, filesToTest)) { - return; - } - - final DataObject[] modified = DataObject.getRegistry().getModified(); - - // show configuration dialog - // when dialog is canceled, escape the action - JUnitCfgOfCreate cfg = new JUnitCfgOfCreate(nodes, - modified.length == 0 ? false: true); - if (!cfg.configure()) { - return; - } - - saveAll(modified); // #149048 - - /* Store the configuration data: */ - final boolean singleClass = cfg.isSingleClass(); - final Map params - = TestUtil.getSettingsMap(!singleClass); - if (singleClass) { - params.put(CreateTestParam.CLASS_NAME, cfg.getTestClassName()); - } - final FileObject targetFolder = cfg.getTargetFolder(); - cfg = null; - - RequestProcessor.getDefault().post(new Runnable() { - @Override - public void run() { - /* Now create the tests: */ - final FileObject[] testFileObjects - = JUnitPluginTrampoline.DEFAULT.createTests( - plugin, - filesToTest, - targetFolder, - params); - - /* Open the created/updated test class if appropriate: */ - if (testFileObjects.length == 1) { - try { - DataObject dobj = DataObject.find(testFileObjects[0]); - final EditorCookie ec = dobj.getCookie(EditorCookie.class); - if (ec != null) { - EventQueue.invokeLater(new Runnable() { - @Override - public void run() { - ec.open(); - } - }); - } - } catch (DataObjectNotFoundException ex) { - ex.printStackTrace(); - } - } - }}); - } - - /** - * Extracts {@code FileObject}s from the given nodes. - * Nodes that have (direct or indirect) parent nodes among the given - * nodes are ignored. - * - * @return a non-empty array of {@code FileObject}s - * represented by the given nodes; - * or {@code null} if no {@code FileObject} was found; - */ - private static FileObject[] getFileObjectsFromNodes(final Node[] nodes){ - FileObject[] fileObjects = new FileObject[nodes.length]; - List fileObjectsList = null; - - for (int i = 0; i < nodes.length; i++) { - final Node node = nodes[i]; - final FileObject fo; - if (!hasParentAmongNodes(nodes, i) - && ((fo = getTestFileObject(node)) != null)) { - if (fileObjects != null) { - fileObjects[i] = fo; - } else { - if (fileObjectsList == null) { - fileObjectsList = new ArrayList( - nodes.length - i); - } - fileObjectsList.add(fo); - } - } else { - fileObjects = null; //signs that some FOs were skipped - } - } - if (fileObjects == null) { - if (fileObjectsList != null) { - fileObjects = fileObjectsList.toArray( - new FileObject[fileObjectsList.size()]); - fileObjectsList = null; - } - } - - return fileObjects; - } - - /** - * Grabs and checks a FileObject from the given node. - * If either the file could not be grabbed or the file does not pertain - * to any project, a message is displayed. - * - * @param node node to get a FileObject from. - * @return the grabbed FileObject, - * or null in case of failure - */ - private static FileObject getTestFileObject(final Node node) { - final FileObject fo = TestUtil.getFileObjectFromNode(node); - if (fo == null) { - TestUtil.notifyUser(NbBundle.getMessage( - CreateTestAction.class, - "MSG_file_from_node_failed")); //NOI18N - return null; - } - ClassPath cp = ClassPath.getClassPath(fo, ClassPath.SOURCE); - if (cp == null) { - TestUtil.notifyUser(NbBundle.getMessage( - CreateTestAction.class, - "MSG_no_project", //NOI18N - fo)); - return null; - } - return fo; - } - - private static boolean hasParentAmongNodes(final Node[] nodes, - final int idx) { - Node node; - - node = nodes[idx].getParentNode(); - while (null != node) { - for (int i = 0; i < nodes.length; i++) { - if (i == idx) { - continue; - } - if (node == nodes[i]) { - return true; - } - } - node = node.getParentNode(); - } - return false; - } - - private void saveAll(DataObject[] dataObjects) { - for(DataObject dataObject: dataObjects) { - SaveCookie saveCookie = dataObject.getCookie(SaveCookie.class); - if(saveCookie != null) { - try { - saveCookie.save(); - } catch (IOException ex) { - Exceptions.printStackTrace(ex); - } - } - } - } - -} diff --git a/junit/src/org/netbeans/modules/junit/JUnitCfgOfCreate.java b/junit/src/org/netbeans/modules/junit/JUnitCfgOfCreate.java deleted file mode 100644 --- a/junit/src/org/netbeans/modules/junit/JUnitCfgOfCreate.java +++ /dev/null @@ -1,1128 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved. - * - * Oracle and Java are registered trademarks of Oracle and/or its affiliates. - * Other names may be trademarks of their respective owners. - * - * The contents of this file are subject to the terms of either the GNU - * General Public License Version 2 only ("GPL") or the Common - * Development and Distribution License("CDDL") (collectively, the - * "License"). You may not use this file except in compliance with the - * License. You can obtain a copy of the License at - * http://www.netbeans.org/cddl-gplv2.html - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the - * specific language governing permissions and limitations under the - * License. When distributing the software, include this License Header - * Notice in each file and include the License file at - * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the GPL Version 2 section of the License file that - * accompanied this code. If applicable, add the following below the - * License Header, with the fields enclosed by brackets [] replaced by - * your own identifying information: - * "Portions Copyrighted [year] [name of copyright owner]" - * - * Contributor(s): - * - * The Original Software is NetBeans. The Initial Developer of the Original - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2008 Sun - * Microsystems, Inc. All Rights Reserved. - * - * If you wish your version of this file to be governed by only the CDDL - * or only the GPL Version 2, indicate your decision by adding - * "[Contributor] elects to include this software in this distribution - * under the [CDDL or GPL Version 2] license." If you do not indicate a - * single choice of license, a recipient has the option to distribute - * your version of this file under either the CDDL, the GPL Version 2 or - * to extend the choice of license to its licensees as provided above. - * However, if you add GPL Version 2 code and therefore, elected the GPL - * Version 2 license, then the option applies only if the new code is - * made subject to such option by the copyright holder. - */ - -package org.netbeans.modules.junit; - -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Component; -import java.awt.Container; -import java.awt.Font; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; -import java.awt.Insets; -import java.awt.event.ActionListener; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.ResourceBundle; -import java.util.Stack; -import javax.swing.BorderFactory; -import javax.swing.Box; -import javax.swing.BoxLayout; -import javax.swing.DefaultComboBoxModel; -import javax.swing.JButton; -import javax.swing.JCheckBox; -import javax.swing.JComboBox; -import javax.swing.JComponent; -import javax.swing.JLabel; -import javax.swing.JList; -import javax.swing.JPanel; -import javax.swing.ListCellRenderer; -import javax.swing.UIManager; -import javax.swing.border.Border; -import javax.swing.border.CompoundBorder; -import javax.swing.border.TitledBorder; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; -import javax.swing.plaf.UIResource; -import javax.swing.text.JTextComponent; -import org.netbeans.api.java.classpath.ClassPath; -import org.netbeans.api.java.project.JavaProjectConstants; -import org.netbeans.api.project.FileOwnerQuery; -import org.netbeans.api.project.Project; -import org.netbeans.api.project.SourceGroup; -import org.netbeans.api.project.SourceGroupModifier; -import org.openide.DialogDescriptor; -import org.openide.DialogDisplayer; -import org.openide.awt.Mnemonics; -import org.openide.filesystems.FileObject; -import org.openide.filesystems.FileUtil; -import org.openide.loaders.DataFolder; -import org.openide.loaders.DataObject; -import org.openide.nodes.Node; -import org.openide.util.HelpCtx; -import org.openide.util.Lookup; -import org.openide.util.NbBundle; - - -/** - * - * @author vstejskal - * @author Marian Petras - */ -@SuppressWarnings("serial") -public final class JUnitCfgOfCreate extends SelfResizingPanel - implements ChangeListener { - - /** suffix of test classes */ - private static final String TEST_CLASS_SUFFIX = "Test"; //NOI18N - - /** - * nodes selected when the Create Tests action was invoked - */ - private final Node[] nodes; - /** whether the tests will be created for multiple classes */ - private final boolean multipleClasses; - /** whether a single package/folder is selected */ - private boolean singlePackage; - /** whether a single class is selected */ - private boolean singleClass; - /** test class name specified in the form (or null) */ - private String testClassName; - /** registered change listeners */ - private List changeListeners; - /** */ - private String initialMessage; - - /** - * is at least one target folder/source group available? - * - * @see #isAcceptable() - */ - private boolean hasTargetFolders = false; - - /** - * is the entered class name non-empty and valid? - * - * @see #isAcceptable() - */ - private boolean classNameValid; - - /** - * is the current form contents acceptable? - * - * @see #isAcceptable() - */ - private boolean isAcceptable; - - /** layer index for a message about an empty set of target folders */ - private static final int MSG_TYPE_NO_TARGET_FOLDERS = 0; - /** layer index for a message about invalid class name */ - private static final int MSG_TYPE_CLASSNAME_INVALID = 1; - /** layer index for a message about non-default class name */ - private static final int MSG_TYPE_CLASSNAME_NOT_DEFAULT = 2; - /** layer index for a message about modified files */ - private static final int MSG_TYPE_MODIFIED_FILES = 3; - /** */ - private MessageStack msgStack = new MessageStack(4); - - /** - * Creates a JUnit configuration panel. - * - * @param nodes nodes selected when the Create Tests action was invoked - * @param isShowMsgFilesWillBeSaved if {@code true} then a warning message - * like "Warning: All modified files will be saved." will be - * displayed on the panel, otherwise (i.e. if {@code false}) then - * the message won't be displayed. - */ - JUnitCfgOfCreate(Node[] nodes, boolean isShowMsgFilesWillBeSaved) { - assert (nodes != null) && (nodes.length != 0); - - this.nodes = nodes; - multipleClasses = checkMultipleClasses(); - - initBundle(); - try { - initComponents(); - if(isShowMsgFilesWillBeSaved) { - String msg = bundle.getString("MSG_MODIFIED_FILES"); // NOI18N - setMessage(msg, MSG_TYPE_MODIFIED_FILES); - } - setBorder(BorderFactory.createEmptyBorder(12, 12, 0, 11)); - addAccessibleDescriptions(); - initializeCheckBoxStates(); - fillFormData(); - checkAcceptability(); - setupUserInteraction(); - - /* - * checkAcceptability() must not be called - * before initializeCheckBoxStates() and fillFormData() - * setupUserInteraction must not be called - * before initializeCheckBoxStates() - */ - - } finally { - unlinkBundle(); - } - } - - private void addAccessibleDescriptions() { - - // window - this.getAccessibleContext().setAccessibleDescription(bundle.getString("JUnitCfgOfCreate.AD")); - - // text-field and combo-box - - if (this.tfClassName != null) { - this.tfClassName.setToolTipText( - bundle.getString("JUnitCfgOfCreate.clsName.toolTip"));//NOI18N - this.tfClassName.getAccessibleContext().setAccessibleName( - bundle.getString("JUnitCfgOfCreate.clsName.AN")); //NOI18N - this.tfClassName.getAccessibleContext().setAccessibleDescription( - bundle.getString("JUnitCfgOfCreate.clsName.AD")); //NOI18N - } - - this.cboxLocation.setToolTipText( - bundle.getString("JUnitCfgOfCreate.location.toolTip")); //NOI18N - this.cboxLocation.getAccessibleContext().setAccessibleName( - bundle.getString("JUnitCfgOfCreate.location.AN")); //NOI18N - this.cboxLocation.getAccessibleContext().setAccessibleDescription( - bundle.getString("JUnitCfgOfCreate.location.AD")); //NOI18N - - // check boxes - this.chkPublic.setToolTipText(bundle.getString("JUnitCfgOfCreate.chkPublic.toolTip")); - this.chkPublic.getAccessibleContext().setAccessibleDescription(bundle.getString("JUnitCfgOfCreate.chkPublic.AD")); - - this.chkProtected.setToolTipText(bundle.getString("JUnitCfgOfCreate.chkProtected.toolTip")); - this.chkProtected.getAccessibleContext().setAccessibleDescription(bundle.getString("JUnitCfgOfCreate.chkProtected.AD")); - - this.chkPackage.setToolTipText(bundle.getString("JUnitCfgOfCreate.chkPackage.toolTip")); - this.chkPackage.getAccessibleContext().setAccessibleDescription(bundle.getString("JUnitCfgOfCreate.chkPackage.AD")); - - this.chkComments.setToolTipText(bundle.getString("JUnitCfgOfCreate.chkComments.toolTip")); - this.chkComments.getAccessibleContext().setAccessibleDescription(bundle.getString("JUnitCfgOfCreate.chkComments.AD")); - - this.chkContent.setToolTipText(bundle.getString("JUnitCfgOfCreate.chkContent.toolTip")); - this.chkContent.getAccessibleContext().setAccessibleDescription(bundle.getString("JUnitCfgOfCreate.chkContent.AD")); - - this.chkJavaDoc.setToolTipText(bundle.getString("JUnitCfgOfCreate.chkJavaDoc.toolTip")); - this.chkJavaDoc.getAccessibleContext().setAccessibleDescription(bundle.getString("JUnitCfgOfCreate.chkJavaDoc.AD")); - - if (multipleClasses) { - this.chkExceptions.setToolTipText(bundle.getString("JUnitCfgOfCreate.chkExceptions.toolTip")); - this.chkExceptions.getAccessibleContext().setAccessibleDescription(bundle.getString("JUnitCfgOfCreate.chkExceptions.AD")); - - this.chkAbstractImpl.setToolTipText(bundle.getString("JUnitCfgOfCreate.chkAbstractImpl.toolTip")); - this.chkAbstractImpl.getAccessibleContext().setAccessibleDescription(bundle.getString("JUnitCfgOfCreate.chkAbstractImpl.AD")); - - this.chkPackagePrivateClasses.setToolTipText(bundle.getString("JUnitCfgOfCreate.chkPackagePrivateClasses.toolTip")); - this.chkPackagePrivateClasses.getAccessibleContext().setAccessibleDescription(bundle.getString("JUnitCfgOfCreate.chkPackagePrivateClasses.AD")); - - this.chkGenerateSuites.setToolTipText(bundle.getString("JUnitCfgOfCreate.chkGenerateSuites.toolTip")); - this.chkGenerateSuites.getAccessibleContext().setAccessibleDescription(bundle.getString("JUnitCfgOfCreate.chkGenerateSuites.AD")); - } - - } - - /** - * Checks whether multiple classes may be selected. - * It also detects whether exactly one package/folder or exactly one class - * is selected and sets values of variables {@link #singlePackage} - * and {@link #singleClass} accordingly. - * - * @return false if there is exactly one node selected - * and the node represents a single DataObject, - * not a folder or another DataObject container; - * true otherwise - */ - private boolean checkMultipleClasses() { - if (nodes.length > 1) { - return true; - } - - Lookup nodeLookup = nodes[0].getLookup(); - if (nodeLookup.lookup(DataObject.Container.class) != null) { - singlePackage = nodeLookup.lookup(DataFolder.class) - != null; - return true; - } - - singleClass = false; - DataObject dataObj = nodeLookup.lookup(DataObject.class); - if (dataObj == null) { - return true; - } - - singleClass = dataObj.getPrimaryFile().isData(); - return !singleClass; - } - - /** - * Displays a configuration dialog and updates JUnit options according - * to the user's settings. - * - * @param nodes nodes selected when the Create Test action was invoked - */ - boolean configure() { - - // create and display the dialog: - String title = NbBundle.getMessage(JUnitCfgOfCreate.class, - "JUnitCfgOfCreate.Title"); //NOI18N - ChangeListener changeListener; - final JButton btnOK = new JButton( - NbBundle.getMessage(JUnitCfgOfCreate.class, "LBL_OK")); //NOI18N - btnOK.getAccessibleContext().setAccessibleName(NbBundle.getMessage(JUnitCfgOfCreate.class, "AN_OK")); - btnOK.getAccessibleContext().setAccessibleDescription(NbBundle.getMessage(JUnitCfgOfCreate.class, "AD_OK")); - btnOK.setEnabled(isAcceptable()); - addChangeListener(changeListener = new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - btnOK.setEnabled(isAcceptable()); - } - }); - - Object returned = DialogDisplayer.getDefault().notify( - new DialogDescriptor ( - this, - title, - true, //modal - new Object[] {btnOK, DialogDescriptor.CANCEL_OPTION}, - btnOK, //initial value - DialogDescriptor.DEFAULT_ALIGN, - new HelpCtx(JUnitCfgOfCreate.class), - (ActionListener) null - )); - removeChangeListener(changeListener); - - if (returned == btnOK) { - rememberCheckBoxStates(); - testClassName = (tfClassName != null) ? tfClassName.getText() - : null; - return true; - } - return false; - } - - /** - * Returns whether a test for a single class is to be created. - * - * @return true if there is only one node selected and the node - * represents a class - */ - boolean isSingleClass() { - return singleClass; - } - - /** - * Returns the class name entered in the text-field. - * - * @return class name entered in the form, - * or null if the form did not contain - * the field for entering class name - */ - String getTestClassName() { - return testClassName; - } - - /** resource bundle used during initialization of this panel */ - public ResourceBundle bundle; - - /** - * Reads JUnit settings and initializes checkboxes accordingly. - * - * @see #rememberCheckBoxStates - */ - private void initializeCheckBoxStates() { - final JUnitSettings settings = JUnitSettings.getDefault(); - - chkPublic.setSelected(settings.isMembersPublic()); - chkProtected.setSelected(settings.isMembersProtected()); - chkPackage.setSelected(settings.isMembersPackage()); - chkComments.setSelected(settings.isBodyComments()); - chkContent.setSelected(settings.isBodyContent()); - chkJavaDoc.setSelected(settings.isJavaDoc()); - if (multipleClasses) { - chkGenerateSuites.setSelected(settings.isGenerateSuiteClasses()); - chkPackagePrivateClasses.setSelected( - settings.isIncludePackagePrivateClasses()); - chkAbstractImpl.setSelected(settings.isGenerateAbstractImpl()); - chkExceptions.setSelected(settings.isGenerateExceptionClasses()); - } - chkSetUp.setSelected(settings.isGenerateSetUp()); - chkTearDown.setSelected(settings.isGenerateTearDown()); - } - - /** - * Stores settings given by checkbox states to JUnit settings. - * - * @see #initializeCheckBoxStatesf - */ - private void rememberCheckBoxStates() { - final JUnitSettings settings = JUnitSettings.getDefault(); - - settings.setMembersPublic(chkPublic.isSelected()); - settings.setMembersProtected(chkProtected.isSelected()); - settings.setMembersPackage(chkPackage.isSelected()); - settings.setBodyComments(chkComments.isSelected()); - settings.setBodyContent(chkContent.isSelected()); - settings.setJavaDoc(chkJavaDoc.isSelected()); - if (multipleClasses) { - settings.setGenerateSuiteClasses(chkGenerateSuites.isSelected()); - settings.setIncludePackagePrivateClasses( - chkPackagePrivateClasses.isSelected()); - settings.setGenerateAbstractImpl(chkAbstractImpl.isSelected()); - settings.setGenerateExceptionClasses(chkExceptions.isSelected()); - } - settings.setGenerateSetUp(chkSetUp.isSelected()); - settings.setGenerateTearDown(chkTearDown.isSelected()); - } - - /** - * Loads a resource bundle so that it can be used during intialization - * of this panel. - * - * @see #unlinkBundle - */ - private void initBundle() { - bundle = NbBundle.getBundle(JUnitCfgOfCreate.class); - } - - /** - * Nulls the resource bundle so that it is not held in memory when it is - * not used. - * - * @see #initBundle - */ - private void unlinkBundle() { - bundle = null; - } - - /** - * This method is called from within the constructor to initialize the form. - */ - private void initComponents() { - setLayout(new BorderLayout(0, 12)); - - add(createNameAndLocationPanel(), BorderLayout.NORTH); - add(createMessagePanel(), BorderLayout.CENTER); - add(createCodeGenPanel(), BorderLayout.SOUTH); - } - - /** - */ - private void setupUserInteraction() { - final ItemListener listener = new CheckBoxListener(); - - chkPublic.addItemListener(listener); - chkProtected.addItemListener(listener); - chkPackage.addItemListener(listener); - } - - /** - * Listener object that listens on state changes of some check-boxes. - */ - private final class CheckBoxListener implements ItemListener { - public CheckBoxListener () {} - - @Override - public void itemStateChanged(ItemEvent e) { - final Object source = e.getSource(); - - assert source == chkPublic - || source == chkProtected - || source == chkPackage; - checkAcceptability(); - } - - } - - /** - */ - private Component createNameAndLocationPanel() { - JPanel panel = new JPanel(); - - final boolean askForClassName = singleClass; - - JLabel lblClassToTest = new JLabel(); - JLabel lblClassName = askForClassName ? new JLabel() : null; - JLabel lblLocation = new JLabel(); - - String classToTestKey = singlePackage - ? "LBL_PackageToTest" //NOI18N - : singleClass - ? "LBL_ClassToTest" //NOI18N - : "LBL_MultipleClassesSelected"; //NOI18N - - Mnemonics.setLocalizedText( - lblClassToTest, - NbBundle.getMessage(getClass(), classToTestKey)); - if (askForClassName) { - Mnemonics.setLocalizedText( - lblClassName, - NbBundle.getMessage(getClass(), "LBL_ClassName")); //NOI18N - } - Mnemonics.setLocalizedText( - lblLocation, - NbBundle.getMessage(getClass(), "LBL_Location")); //NOI18N - - if (singlePackage || singleClass) { - lblClassToTestValue = new JLabel(); - } - if (askForClassName) { - tfClassName = new ClassNameTextField(); - tfClassName.setChangeListener(this); - } - cboxLocation = new JComboBox(); - - if (askForClassName) { - lblClassName.setLabelFor(tfClassName); - } - lblLocation.setLabelFor(cboxLocation); - - if (lblClassToTestValue != null) { - Font labelFont = javax.swing.UIManager.getDefaults() - .getFont("TextField.font"); //NOI18N - if (labelFont != null) { - lblClassToTestValue.setFont(labelFont); - } - } - - panel.setLayout(new GridBagLayout()); - - GridBagConstraints gbcLeft = new GridBagConstraints(); - gbcLeft.anchor = GridBagConstraints.WEST; - gbcLeft.insets.bottom = 12; - gbcLeft.insets.right = 6; - - GridBagConstraints gbcRight = new GridBagConstraints(); - gbcRight.anchor = GridBagConstraints.WEST; - gbcRight.insets.bottom = 12; - gbcRight.weightx = 1.0f; - gbcRight.fill = GridBagConstraints.BOTH; - gbcRight.gridwidth = GridBagConstraints.REMAINDER; - - if (lblClassToTestValue != null) { - panel.add(lblClassToTest, gbcLeft); - panel.add(lblClassToTestValue, gbcRight); - } else { - panel.add(lblClassToTest, gbcRight); - } - if (askForClassName) { - panel.add(lblClassName, gbcLeft); - panel.add(tfClassName, gbcRight); - } - gbcLeft.insets.bottom = 0; - gbcRight.insets.bottom = 0; - panel.add(lblLocation, gbcLeft); - panel.add(cboxLocation, gbcRight); - - return panel; - } - - /** - */ - private void checkClassNameValidity() { - if (tfClassName == null) { - classNameValid = true; - return; - } - - String key = null; - final int state = tfClassName.getStatus(); - switch (state) { - case ClassNameTextField.STATUS_EMPTY: - key = "MSG_ClassnameMustNotBeEmpty"; //NOI18N - break; - case ClassNameTextField.STATUS_INVALID: - key = "MSG_InvalidClassName"; //NOI18N - break; - case ClassNameTextField.STATUS_VALID_NOT_DEFAULT: - key = "MSG_ClassNameNotDefault"; //NOI18N - break; - case ClassNameTextField.STATUS_VALID_END_NOT_TEST: - key = "MSG_ClassNameEndNotTest"; //NOI18N - break; - } - if (state != ClassNameTextField.STATUS_VALID_NOT_DEFAULT) { - setMessage(null, MSG_TYPE_CLASSNAME_NOT_DEFAULT); - } - setMessage((key != null) - ? NbBundle.getMessage(getClass(), key) - : null, - MSG_TYPE_CLASSNAME_INVALID); - - classNameValid = - (state == ClassNameTextField.STATUS_VALID) - || (state == ClassNameTextField.STATUS_VALID_NOT_DEFAULT); - } - - /** - * This method gets called if status of contents of the Class Name - * text field changes. See STATUS_xxx constants - * in class ClassNameTextField. - * - * @param e event describing the state change event - * (unused in this method) - */ - @Override - public void stateChanged(ChangeEvent e) { - checkClassNameValidity(); - checkAcceptability(); - } - - /** - */ - private void checkAcceptability() { - final boolean wasAcceptable = isAcceptable; - isAcceptable = hasTargetFolders && classNameValid; - if (isAcceptable != wasAcceptable) { - fireStateChange(); - } - } - - /** - * Are the values filled in the form acceptable? - * - * @see #addChangeListener - */ - private boolean isAcceptable() { - return isAcceptable; - } - - /** - * This method is called the first time this panel's children are painted. - * By default, this method just calls {@link #adjustWindowSize()}. - * - * @param g Graphics used to paint this panel's children - */ - @Override - protected void paintedFirstTime(java.awt.Graphics g) { - if (initialMessage != null) { - displayMessage(initialMessage); - initialMessage = null; - } - } - - /** - * Displays a given message in the message panel and resizes the dialog - * if necessary. If the message cannot be displayed immediately, - * because of this panel not displayed (painted) yet, displaying the message - * is deferred until this panel is painted. - * - * @param message message to be displayed, or null if - * the currently displayed message (if any) should be - * removed - */ - private void setMessage(final String message, final int msgType) { - String msgToDisplay = msgStack.setMessage(msgType, message); - if (msgToDisplay == null) { - return; //no change - } - - /* display the message: */ - if (!isPainted()) { - initialMessage = msgToDisplay; - } else { - displayMessage(msgToDisplay); - } - } - - /** - * Displays a given message in the message panel and resizes the dialog - * if necessary. - * - * @param message message to be displayed, or null if - * the currently displayed message (if any) should be - * removed - * @see #adjustWindowSize() - */ - private void displayMessage(String message) { - if (message == null) { - message = ""; //NOI18N - } - - txtAreaMessage.setText(message); - adjustWindowSize(); - } - - /** - */ - private Component createMessagePanel() { - Color color = UIManager.getColor("nb.errorForeground"); //NOI18N - if (color == null) { - color = new Color(89, 79, 191); //RGB suggested by Bruce in #28466 - } - txtAreaMessage = GuiUtils.createMultilineLabel("", color); //NOI18N - return txtAreaMessage; - } - - /** - * Creates a panel containing controls for settings code generation options. - * - * @return created panel - */ - private Component createCodeGenPanel() { - - /* create the components: */ - String[] chkBoxIDs; - JCheckBox[] chkBoxes; - if (multipleClasses) { - chkBoxIDs = new String[] { - GuiUtils.CHK_PUBLIC, - GuiUtils.CHK_PROTECTED, - GuiUtils.CHK_PACKAGE, - GuiUtils.CHK_PACKAGE_PRIVATE_CLASSES, - GuiUtils.CHK_ABSTRACT_CLASSES, - GuiUtils.CHK_EXCEPTION_CLASSES, - GuiUtils.CHK_SUITES, - GuiUtils.CHK_SETUP, - GuiUtils.CHK_TEARDOWN, - GuiUtils.CHK_METHOD_BODIES, - GuiUtils.CHK_JAVADOC, - GuiUtils.CHK_HINTS - }; - } else { - chkBoxIDs = new String[] { - GuiUtils.CHK_PUBLIC, - GuiUtils.CHK_PROTECTED, - GuiUtils.CHK_PACKAGE, - null, // CHK_PACKAGE_PRIVATE_CLASSES, - null, // CHK_ABSTRACT_CLASSES, - null, // CHK_EXCEPTION_CLASSES, - null, // CHK_SUITES, - GuiUtils.CHK_SETUP, - GuiUtils.CHK_TEARDOWN, - GuiUtils.CHK_METHOD_BODIES, - GuiUtils.CHK_JAVADOC, - GuiUtils.CHK_HINTS - }; - } - chkBoxes = GuiUtils.createCheckBoxes(chkBoxIDs); - int i = 0; - chkPublic = chkBoxes[i++]; - chkProtected = chkBoxes[i++]; - chkPackage = chkBoxes[i++]; - chkPackagePrivateClasses = chkBoxes[i++]; //may be null - chkAbstractImpl = chkBoxes[i++]; //may be null - chkExceptions = chkBoxes[i++]; //may be null - chkGenerateSuites = chkBoxes[i++]; //may be null - chkSetUp = chkBoxes[i++]; - chkTearDown = chkBoxes[i++]; - chkContent = chkBoxes[i++]; - chkJavaDoc = chkBoxes[i++]; - chkComments = chkBoxes[i++]; - - /* create groups of checkboxes: */ - JComponent methodAccessLevels = GuiUtils.createChkBoxGroup( - bundle.getString("JUnitCfgOfCreate.groupAccessLevels"), //NOI18N - new JCheckBox[] {chkPublic, chkProtected, chkPackage}); - JComponent classTypes = null; - JComponent optionalClasses = null; - if (multipleClasses) { - classTypes = GuiUtils.createChkBoxGroup( - bundle.getString("JUnitCfgOfCreate.groupClassTypes"), //NOI18N - new JCheckBox[] {chkPackagePrivateClasses, - chkAbstractImpl, chkExceptions}); - optionalClasses = GuiUtils.createChkBoxGroup( - bundle.getString("JUnitCfgOfCreate.groupOptClasses"), //NOI18N - new JCheckBox[] {chkGenerateSuites}); - } - JComponent optionalCode = GuiUtils.createChkBoxGroup( - bundle.getString("JUnitCfgOfCreate.groupOptCode"), //NOI18N - new JCheckBox[] {chkSetUp, chkTearDown, chkContent}); - JComponent optionalComments = GuiUtils.createChkBoxGroup( - bundle.getString("JUnitCfgOfCreate.groupOptComments"), //NOI18N - new JCheckBox[] {chkJavaDoc, chkComments}); - - /* create the left column of options: */ - Box leftColumn = Box.createVerticalBox(); - leftColumn.add(methodAccessLevels); - if (multipleClasses) { - leftColumn.add(Box.createVerticalStrut(11)); - leftColumn.add(classTypes); - } else { - /* - * This strut ensures that width of the left column is not limited. - * If it was limited, the rigth column would not move when the - * dialog is horizontally resized. - */ - leftColumn.add(Box.createVerticalStrut(0)); - } - leftColumn.add(Box.createVerticalGlue()); - - /* create the right column of options: */ - Box rightColumn = Box.createVerticalBox(); - if (multipleClasses) { - rightColumn.add(optionalClasses); - rightColumn.add(Box.createVerticalStrut(11)); - } - rightColumn.add(optionalCode); - rightColumn.add(Box.createVerticalStrut(11)); - rightColumn.add(optionalComments); - rightColumn.add(Box.createVerticalGlue()); - - /* compose the final panel: */ - //JPanel jpCodeGen = new SizeRestrictedPanel(false, true); - JPanel jpCodeGen = new JPanel(); - jpCodeGen.setLayout(new BoxLayout(jpCodeGen, BoxLayout.X_AXIS)); - jpCodeGen.add(leftColumn); - jpCodeGen.add(Box.createHorizontalStrut(24)); - jpCodeGen.add(rightColumn); - - /* decorate the panel: */ - addTitledBorder(jpCodeGen, - new Insets(12, 12, 11, 12), - bundle.getString("JUnitCfgOfCreate.jpCodeGen.title"));//NOI18N - - /* tune the layout: */ - methodAccessLevels.setAlignmentX(0.0f); - if (multipleClasses) { - classTypes.setAlignmentX(0.0f); - optionalClasses.setAlignmentX(0.0f); - } - optionalCode.setAlignmentX(0.0f); - optionalComments.setAlignmentX(0.0f); - - return jpCodeGen; - } - - /** - * Adds a border and a title around a given component. - * If the component already has some border, it is overridden (not kept). - * - * @param component component the border and title should be added to - * @param insets insets between the component and the titled border - * @param title text of the title - */ - private static void addTitledBorder(JComponent component, - Insets insets, - String title) { - Border insideBorder = BorderFactory.createEmptyBorder( - insets.top, insets.left, insets.bottom, insets.right); - Border outsideBorder = new TitledBorder( - BorderFactory.createEtchedBorder(), title); - component.setBorder(new CompoundBorder(outsideBorder, insideBorder)); - } - - /** - */ - FileObject getTargetFolder() { - Object selectedLocation = cboxLocation.getSelectedItem(); - - if (selectedLocation == null) { - return null; - } - - if (selectedLocation instanceof SourceGroup) { - return ((SourceGroup) selectedLocation).getRootFolder(); - } - assert selectedLocation instanceof FileObject; //root folder - return (FileObject) selectedLocation; - } - - /** - * Initializes form in the Test Settings panel of the dialog. - */ - private void fillFormData() { - final DataObject dataObj = nodes[0].getLookup().lookup(DataObject.class); - final FileObject fileObj = dataObj.getPrimaryFile(); - - if (singleClass) { - assert nodes.length == 1; - - ClassPath cp = ClassPath.getClassPath(fileObj, ClassPath.SOURCE); - String className = cp.getResourceName(fileObj, '.', false); - lblClassToTestValue.setText(className); - - if (tfClassName != null) { - String prefilledName = className + TEST_CLASS_SUFFIX; - tfClassName.setText(prefilledName); - tfClassName.setDefaultText(prefilledName); - tfClassName.setCaretPosition(prefilledName.length()); - } - } else if (singlePackage) { - assert nodes.length == 1; - - ClassPath cp = ClassPath.getClassPath(fileObj, ClassPath.SOURCE); - String packageName = cp.getResourceName(fileObj, '.', true); - if (packageName.length() == 0) { - packageName = NbBundle.getMessage( - getClass(), - "DefaultPackageName"); //NOI18N - } - lblClassToTestValue.setText(packageName); - } else { - //PENDING - } - - setupLocationChooser(fileObj); - - checkClassNameValidity(); - } - - /** - */ - private void setupLocationChooser(FileObject refFileObject) { - Object[] targetFolders = TestUtil.getTestTargets(refFileObject); - if (targetFolders.length == 0) { - Project owner = FileOwnerQuery.getOwner(refFileObject); - if (owner != null) { - if (SourceGroupModifier.createSourceGroup(owner, JavaProjectConstants.SOURCES_TYPE_JAVA, JavaProjectConstants.SOURCES_HINT_TEST) != null) { - targetFolders = TestUtil.getTestTargets(refFileObject); - } - } - } - - if (targetFolders.length != 0) { - hasTargetFolders = true; - cboxLocation.setModel(new DefaultComboBoxModel(targetFolders)); - cboxLocation.setRenderer(new LocationChooserRenderer()); - } else { - hasTargetFolders = false; - //PENDING - message text: - String msgNoTargetsFound = NbBundle.getMessage( - getClass(), - refFileObject.isFolder() - ? "MSG_NoTestTarget_Fo" //NOI18N - : "MSG_NoTestTarget_Fi",//NOI18N - refFileObject.getNameExt()); - setMessage(msgNoTargetsFound, MSG_TYPE_NO_TARGET_FOLDERS); - disableComponents(); - } - } - - /** - * Renderer which specially handles values of type - * SourceGroup and FileObject. - * It displays display names of these objects, instead of their default - * string representation (toString()). - * - * @see SourceGroup#getDisplayName() - * @see FileUtil#getFileDisplayName(FileObject) - */ - private final class LocationChooserRenderer extends JLabel implements ListCellRenderer, UIResource { - - public LocationChooserRenderer () { - setOpaque(true); - } - - @Override - public Component getListCellRendererComponent( - JList list, - Object value, - int index, - boolean isSelected, - boolean cellHasFocus) { - // #93658: GTK needs name to render cell renderer "natively" - setName("ComboBox.listRenderer"); // NOI18N - - String text = value instanceof SourceGroup - ? ((SourceGroup) value).getDisplayName() - : value instanceof FileObject - ? FileUtil.getFileDisplayName((FileObject) value) - : value.toString(); - setText(text); - - if ( isSelected ) { - setBackground(list.getSelectionBackground()); - setForeground(list.getSelectionForeground()); - } - else { - setBackground(list.getBackground()); - setForeground(list.getForeground()); - } - - return this; - } - - // #93658: GTK needs name to render cell renderer "natively" - @Override - public String getName() { - String name = super.getName(); - return name == null ? "ComboBox.renderer" : name; // NOI18N - } - - } - - /** - * Registers a change listener. - * Registered change listeners are notified when acceptability - * of values in the form changes. - * - * @param l listener to be registered - * @see #isAcceptable - * @see #removeChangeListener - */ - private void addChangeListener(ChangeListener l) { - if (changeListeners == null) { - changeListeners = new ArrayList(3); - } - changeListeners.add(l); - } - - /** - * Unregisters the given change listener. - * If the given listener has not been registered before, calling this - * method does not have any effect. - * - * @param l change listener to be removed - * @see #addChangeListener - */ - private void removeChangeListener(ChangeListener l) { - if (changeListeners != null - && changeListeners.remove(l) - && changeListeners.isEmpty()) { - changeListeners = null; - } - } - - /** - * Notifies all registered change listeners about a change. - * - * @see #addChangeListener - */ - private void fireStateChange() { - if (changeListeners != null) { - ChangeEvent e = new ChangeEvent(this); - for (Iterator i = changeListeners.iterator(); i.hasNext(); ) { - ((ChangeListener) i.next()).stateChanged(e); - } - } - } - - /** - * Disables all interactive visual components of this dialog - * except the OK, Cancel and Help buttons. - */ - private void disableComponents() { - final Stack stack = new Stack(); - stack.push(this); - - while (!stack.empty()) { - Container container = stack.pop(); - Component comps[] = container.getComponents(); - for (int i = 0; i < comps.length; i++) { - final java.awt.Component comp = comps[i]; - - if (comp == txtAreaMessage) { - continue; - } - if (comp instanceof JPanel) { - JPanel panel = (JPanel) comp; - stack.push(panel); - - final Border border = panel.getBorder(); - if (border != null) { - disableBorderTitles(border); - } - continue; - } - comp.setEnabled(false); - if (comp instanceof java.awt.Container) { - Container nestedCont = (Container) comp; - if (nestedCont.getComponentCount() != 0) { - stack.push(nestedCont); - } - } - } - } - } - - /** - */ - private static void disableBorderTitles(Border border) { - - if (border instanceof TitledBorder) { - disableBorderTitle((TitledBorder) border); - return; - } - - if (!(border instanceof CompoundBorder)) { - return; - } - - Stack stack = new Stack(); - stack.push((CompoundBorder) border); - while (!stack.empty()) { - CompoundBorder cb = stack.pop(); - - Border b; - b = cb.getOutsideBorder(); - if (b instanceof CompoundBorder) { - stack.push((CompoundBorder) b); - } else if (b instanceof TitledBorder) { - disableBorderTitle((TitledBorder) b); - } - - b = cb.getInsideBorder(); - if (b instanceof CompoundBorder) { - stack.push((CompoundBorder) b); - } else if (b instanceof TitledBorder) { - disableBorderTitle((TitledBorder) b); - } - } - } - - /** - */ - private static void disableBorderTitle(TitledBorder border) { - final Color color = UIManager.getColor( - "Label.disabledForeground"); //NOI18N - if (color != null) { - border.setTitleColor(color); - } - } - - private JLabel lblClassToTestValue; - private ClassNameTextField tfClassName; - private JTextComponent txtAreaMessage; - private JComboBox cboxLocation; - private JCheckBox chkAbstractImpl; - private JCheckBox chkComments; - private JCheckBox chkContent; - private JCheckBox chkExceptions; - private JCheckBox chkGenerateSuites; - private JCheckBox chkJavaDoc; - private JCheckBox chkPackage; - private JCheckBox chkPackagePrivateClasses; - private JCheckBox chkProtected; - private JCheckBox chkPublic; - private JCheckBox chkSetUp; - private JCheckBox chkTearDown; - -} diff --git a/junit/src/org/netbeans/modules/junit/JUnitTestCreatorProvider.java b/junit/src/org/netbeans/modules/junit/JUnitTestCreatorProvider.java new file mode 100644 --- /dev/null +++ b/junit/src/org/netbeans/modules/junit/JUnitTestCreatorProvider.java @@ -0,0 +1,412 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2012 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2012 Sun Microsystems, Inc. + */ +package org.netbeans.modules.junit; + +import java.awt.EventQueue; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import org.netbeans.api.java.classpath.ClassPath; +import org.netbeans.api.project.FileOwnerQuery; +import org.netbeans.api.project.Project; +import org.netbeans.api.project.SourceGroup; +import org.netbeans.modules.gsf.testrunner.api.GuiUtils; +import org.netbeans.modules.gsf.testrunner.api.TestCreatorProvider; +import org.netbeans.modules.gsf.testrunner.plugin.CommonPlugin; +import org.netbeans.modules.junit.plugin.JUnitPlugin; +import org.netbeans.spi.java.classpath.support.ClassPathSupport; +import org.openide.DialogDisplayer; +import org.openide.NotifyDescriptor; +import org.openide.cookies.EditorCookie; +import org.openide.filesystems.FileObject; +import org.openide.loaders.DataFolder; +import org.openide.loaders.DataObject; +import org.openide.loaders.DataObjectNotFoundException; +import org.openide.nodes.Node; +import org.openide.util.NbBundle; +import org.openide.util.RequestProcessor; +import org.openide.util.lookup.ServiceProvider; + +/** + * + * @author theofanis + */ +@ServiceProvider(service=TestCreatorProvider.class, position=10) +public class JUnitTestCreatorProvider extends TestCreatorProvider { + + @Override + public String getDisplayName() { + return GuiUtils.JUNIT_TEST_FRAMEWORK; + } + + @Override + public boolean canHandleMultipleClasses(Node[] activatedNodes) { + return true; + } + + @Override + public boolean enable(Node[] activatedNodes) { + if (activatedNodes.length == 0) { + return false; + } + + /* + * In most cases, there is just one node selected - that is why + * this case is handled in a special, more effective way + * (no collections and iterators created). + */ + if (activatedNodes.length == 1) { + final Node node = activatedNodes[0]; + DataObject dataObj; + FileObject fileObj; + Project project; + if (((dataObj = node.getLookup().lookup(DataObject.class)) != null) + && ((fileObj = dataObj.getPrimaryFile()) != null) + && fileObj.isValid() + && ((project = FileOwnerQuery.getOwner(fileObj)) != null) + && (getSourceGroup(fileObj, project) != null) + && (TestUtil.isJavaFile(fileObj) + || (node.getLookup().lookup(DataFolder.class) != null))) { + + JUnitPlugin plugin = TestUtil.getPluginForProject(project); + return JUnitPluginTrampoline.DEFAULT.canCreateTests(plugin, + fileObj); + } else { + return false; + } + } + + final Collection fileObjs + = new ArrayList(activatedNodes.length); + Project theProject = null; + boolean result = false; + for (Node node : activatedNodes) { + DataObject dataObj = node.getLookup().lookup(DataObject.class); + if (dataObj != null) { + FileObject fileObj = dataObj.getPrimaryFile(); + if ((fileObj == null) || !fileObj.isValid()) { + continue; + } + + fileObjs.add(fileObj); + + Project prj = FileOwnerQuery.getOwner(fileObj); + if (prj != null) { + if (theProject == null) { + theProject = prj; + } + if (prj != theProject) { + return false; /* files from different projects */ + } + + if ((getSourceGroup(fileObj, prj) != null) + && (TestUtil.isJavaFile(fileObj) + || (node.getLookup().lookup(DataFolder.class) != null))) { + result = true; + } + } + } + } + + if (theProject != null) { + JUnitPlugin plugin = TestUtil.getPluginForProject(theProject); + result &= JUnitPluginTrampoline.DEFAULT.canCreateTests( + plugin, + fileObjs.toArray(new FileObject[fileObjs.size()])); + } + + return result; + } + + @Override + public void createTests(Node[] activatedNodes) { + String problem; + if ((problem = checkNodesValidity(activatedNodes)) != null) { + // TODO report problem + NotifyDescriptor msg = new NotifyDescriptor.Message( + problem, NotifyDescriptor.WARNING_MESSAGE); + DialogDisplayer.getDefault().notify(msg); + return; + } + + final FileObject[] filesToTest = getFileObjectsFromNodes(activatedNodes); + if (filesToTest == null) { + return; //XXX: display some message + } + + /* + * Determine the plugin to be used: + */ + final JUnitPlugin plugin = TestUtil.getPluginForProject( + FileOwnerQuery.getOwner(filesToTest[0])); + + if (!JUnitPluginTrampoline.DEFAULT.createTestActionCalled( + plugin, filesToTest)) { + return; + } + + /* + * Store the configuration data: + */ + final boolean singleClass = isSingleClass(); + final Map params = TestUtil.getSettingsMap(!singleClass); + if (singleClass) { + params.put(CommonPlugin.CreateTestParam.CLASS_NAME, getTestClassName()); + } + final FileObject targetFolder = getTargetFolder(); + + RequestProcessor.getDefault().post(new Runnable() { + + @Override + public void run() { + /* + * Now create the tests: + */ + final FileObject[] testFileObjects = JUnitPluginTrampoline.DEFAULT.createTests( + plugin, + filesToTest, + targetFolder, + params); + + /* + * Open the created/updated test class if appropriate: + */ + if (testFileObjects.length == 1) { + try { + DataObject dobj = DataObject.find(testFileObjects[0]); + final EditorCookie ec = dobj.getLookup().lookup(EditorCookie.class); + if (ec != null) { + EventQueue.invokeLater(new Runnable() { + + @Override + public void run() { + ec.open(); + } + }); + } + } catch (DataObjectNotFoundException ex) { + ex.printStackTrace(); + } + } + } + }); + } + + /** + * Checks that the selection of nodes the dialog is invoked on is valid. + * @return String message describing the problem found or null, if the + * selection is ok + */ + private static String checkNodesValidity(Node[] nodes) { + FileObject[] files = getFiles(nodes); + + Project project = getProject(files); + if (project == null) { + return NbBundle.getMessage(JUnitTestCreatorProvider.class, + "MSG_multiproject_selection"); //NOI18N + } + + if (!checkPackages(files)) { + return NbBundle.getMessage(JUnitTestCreatorProvider.class, + "MSG_invalid_packages"); //NOI18N + } + + return null; + } + + /** + * Extracts {@code FileObject}s from the given nodes. + * Nodes that have (direct or indirect) parent nodes among the given + * nodes are ignored. + * + * @return a non-empty array of {@code FileObject}s + * represented by the given nodes; + * or {@code null} if no {@code FileObject} was found; + */ + private static FileObject[] getFileObjectsFromNodes(final Node[] nodes){ + FileObject[] fileObjects = new FileObject[nodes.length]; + List fileObjectsList = null; + + for (int i = 0; i < nodes.length; i++) { + final Node node = nodes[i]; + final FileObject fo; + if (!hasParentAmongNodes(nodes, i) + && ((fo = getTestFileObject(node)) != null)) { + if (fileObjects != null) { + fileObjects[i] = fo; + } else { + if (fileObjectsList == null) { + fileObjectsList = new ArrayList( + nodes.length - i); + } + fileObjectsList.add(fo); + } + } else { + fileObjects = null; //signs that some FOs were skipped + } + } + if (fileObjects == null) { + if (fileObjectsList != null) { + fileObjects = fileObjectsList.toArray( + new FileObject[fileObjectsList.size()]); + fileObjectsList = null; + } + } + + return fileObjects; + } + + /** + * Check that all the files (folders or java files) have correct java + * package names. + * @return true if all are fine + */ + private static boolean checkPackages(FileObject[] files) { + if (files.length == 0) { + return true; + } else { + Project project = FileOwnerQuery.getOwner(files[0]); + for (int i = 0 ; i < files.length; i++) { + String packageName = getPackage(project, files[i]); + if ((packageName == null) + || !TestUtil.isValidPackageName(packageName)) { + return false; + } + } + return true; + } + } + + /** + * Get the package name of file. + * + * @param project owner of the file (for performance reasons) + * @param file the FileObject whose packagename to get + * @return package name of the file or null if it cannot be retrieved + */ + private static String getPackage(Project project, FileObject file) { + SourceGroup srcGrp = TestUtil.findSourceGroupOwner(project, file); + if (srcGrp!= null) { + ClassPath cp = ClassPathSupport.createClassPath( + new FileObject [] {srcGrp.getRootFolder()}); + return cp.getResourceName(file, '.', false); + } else { + return null; + } + } + + + private static FileObject[] getFiles(Node[] nodes) { + FileObject[] ret = new FileObject[nodes.length]; + for (int i = 0 ; i < nodes.length ; i++) { + ret[i] = TestUtil.getFileObjectFromNode(nodes[i]); + } + return ret; + } + + /** + * Get the single project for nodes if there is such. + * If the nodes belong to different projects or some of the nodes doesn't + * have a project, return null. + */ + private static Project getProject(FileObject[] files) { + Project project = null; + for (int i = 0 ; i < files.length; i++) { + Project nodeProject = FileOwnerQuery.getOwner(files[i]); + if (project == null) { + project = nodeProject; + } else if (project != nodeProject) { + return null; + } + } + return project; + } + + /** + * Grabs and checks a FileObject from the given node. + * If either the file could not be grabbed or the file does not pertain + * to any project, a message is displayed. + * + * @param node node to get a FileObject from. + * @return the grabbed FileObject, + * or null in case of failure + */ + private static FileObject getTestFileObject(final Node node) { + final FileObject fo = TestUtil.getFileObjectFromNode(node); + if (fo == null) { + TestUtil.notifyUser(NbBundle.getMessage( + JUnitTestCreatorProvider.class, + "MSG_file_from_node_failed")); //NOI18N + return null; + } + ClassPath cp = ClassPath.getClassPath(fo, ClassPath.SOURCE); + if (cp == null) { + TestUtil.notifyUser(NbBundle.getMessage( + JUnitTestCreatorProvider.class, + "MSG_no_project", //NOI18N + fo)); + return null; + } + return fo; + } + + private static boolean hasParentAmongNodes(final Node[] nodes, + final int idx) { + Node node; + + node = nodes[idx].getParentNode(); + while (null != node) { + for (int i = 0; i < nodes.length; i++) { + if (i == idx) { + continue; + } + if (node == nodes[i]) { + return true; + } + } + node = node.getParentNode(); + } + return false; + } + +} diff --git a/junit/src/org/netbeans/modules/junit/actions/JUnitMethodDebuggerProvider.java b/junit/src/org/netbeans/modules/junit/actions/JUnitMethodDebuggerProvider.java new file mode 100644 --- /dev/null +++ b/junit/src/org/netbeans/modules/junit/actions/JUnitMethodDebuggerProvider.java @@ -0,0 +1,162 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2012 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2012 Sun Microsystems, Inc. + */ +package org.netbeans.modules.junit.actions; + +import java.io.IOException; +import java.util.Arrays; +import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.JEditorPane; +import javax.swing.text.Document; +import org.netbeans.api.java.source.JavaSource; +import org.netbeans.api.progress.ProgressUtils; +import org.netbeans.modules.gsf.testrunner.api.CommonTestUtil; +import org.netbeans.modules.gsf.testrunner.api.TestMethodDebuggerProvider; +import org.netbeans.modules.junit.output.OutputUtils; +import org.netbeans.spi.project.ActionProvider; +import org.netbeans.spi.project.SingleMethod; +import org.openide.cookies.EditorCookie; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileUtil; +import org.openide.nodes.Node; +import org.openide.text.NbDocument; +import org.openide.util.Exceptions; +import org.openide.util.Lookup; +import org.openide.util.NbBundle; +import org.openide.util.lookup.Lookups; +import org.openide.util.lookup.ServiceProvider; + +/** + * + * @author theofanis + */ +@ServiceProvider(service=TestMethodDebuggerProvider.class, position=10) +public class JUnitMethodDebuggerProvider extends TestMethodDebuggerProvider { + + private static final Logger LOGGER = Logger.getLogger(JUnitMethodDebuggerProvider.class.getName()); + private final String command = SingleMethod.COMMAND_DEBUG_SINGLE_METHOD; + + @Override + public String getProviderName() { + return NbBundle.getMessage(TestMethodDebuggerProvider.class, "NAME_JUnitMethodProvider"); + } + + @Override + public void debugTestMethod(Node activatedNode) { + final Node activeNode = activatedNode; + final Document doc; + final int caret; + + EditorCookie ec = activeNode.getLookup().lookup(EditorCookie.class); + if (ec != null) { + JEditorPane pane = NbDocument.findRecentEditorPane(ec); + if (pane != null) { + doc = pane.getDocument(); + caret = pane.getCaret().getDot(); + } else { + doc = null; + caret = -1; + } + } else { + doc = null; + caret = -1; + } + + ProgressUtils.runOffEventDispatchThread(new Runnable() { + + @Override + public void run() { + SingleMethod sm = getTestMethod(activeNode.getLookup(), doc, caret); + if (sm != null) { + ActionProvider ap = OutputUtils.getActionProvider(sm.getFile()); + if (ap != null) { + if(Arrays.asList(ap.getSupportedActions()).contains(command) && ap.isActionEnabled(command, Lookups.singleton(sm))) { + ap.invokeAction(command, Lookups.singleton(sm)); + } + } + } + } + }, + NbBundle.getMessage(JUnitMethodDebuggerProvider.class, "LBL_Action_RunTestMethod"), new AtomicBoolean(), false); + } + + private SingleMethod getTestMethod(Lookup lkp, Document doc, int cursor){ + SingleMethod sm = lkp.lookup(SingleMethod.class); + if (sm == null && doc != null){ + JavaSource js = JavaSource.forDocument(doc); + TestClassInfoTask task = new TestClassInfoTask(cursor); + try { + Future f = js.runWhenScanFinished(task, true); + if (f.isDone() && task.getFileObject() != null && task.getMethodName() != null){ + sm = new SingleMethod(task.getFileObject(), task.getMethodName()); + } + } catch (IOException ex) { + LOGGER.log(Level.WARNING, null, ex); + } + } + return sm; + } + + @Override + public boolean canHandle(Node activatedNode) { + FileObject fileO = CommonTestUtil.getFileObjectFromNode(activatedNode); + if (fileO != null) { + EditorCookie ec = activatedNode.getLookup().lookup(EditorCookie.class); + if (ec != null) { + JEditorPane pane = NbDocument.findRecentEditorPane(ec); + if (pane != null) { + String text = pane.getText(); + int index = text.indexOf("public"); //NOI18N + if (index != -1) { + if (text.substring(0, index).contains("org.junit.")) { //NOI18N + return true; + } + } + } + } + } + return false; + } + +} diff --git a/junit/src/org/netbeans/modules/junit/actions/JUnitMethodRunnerProvider.java b/junit/src/org/netbeans/modules/junit/actions/JUnitMethodRunnerProvider.java new file mode 100644 --- /dev/null +++ b/junit/src/org/netbeans/modules/junit/actions/JUnitMethodRunnerProvider.java @@ -0,0 +1,160 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2012 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2012 Sun Microsystems, Inc. + */ +package org.netbeans.modules.junit.actions; + +import java.io.IOException; +import java.util.Arrays; +import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.JEditorPane; +import javax.swing.text.Document; +import org.netbeans.api.java.source.JavaSource; +import org.netbeans.api.progress.ProgressUtils; +import org.netbeans.modules.gsf.testrunner.api.CommonTestUtil; +import org.netbeans.modules.gsf.testrunner.api.TestMethodRunnerProvider; +import org.netbeans.modules.junit.output.OutputUtils; +import org.netbeans.spi.project.ActionProvider; +import org.netbeans.spi.project.SingleMethod; +import org.openide.cookies.EditorCookie; +import org.openide.filesystems.FileObject; +import org.openide.nodes.Node; +import org.openide.text.NbDocument; +import org.openide.util.Lookup; +import org.openide.util.NbBundle; +import org.openide.util.lookup.Lookups; +import org.openide.util.lookup.ServiceProvider; + +/** + * + * @author theofanis + */ +@ServiceProvider(service=TestMethodRunnerProvider.class, position=10) +public class JUnitMethodRunnerProvider extends TestMethodRunnerProvider { + + private static final Logger LOGGER = Logger.getLogger(JUnitMethodRunnerProvider.class.getName()); + private final String command = SingleMethod.COMMAND_RUN_SINGLE_METHOD; + + @Override + public String getProviderName() { + return NbBundle.getMessage(TestMethodRunnerProvider.class, "NAME_JUnitMethodProvider"); + } + + @Override + public void runTestMethod(Node activatedNode) { + final Node activeNode = activatedNode; + final Document doc; + final int caret; + + EditorCookie ec = activeNode.getLookup().lookup(EditorCookie.class); + if (ec != null) { + JEditorPane pane = NbDocument.findRecentEditorPane(ec); + if (pane != null) { + doc = pane.getDocument(); + caret = pane.getCaret().getDot(); + } else { + doc = null; + caret = -1; + } + } else { + doc = null; + caret = -1; + } + + ProgressUtils.runOffEventDispatchThread(new Runnable() { + + @Override + public void run() { + SingleMethod sm = getTestMethod(activeNode.getLookup(), doc, caret); + if (sm != null) { + ActionProvider ap = OutputUtils.getActionProvider(sm.getFile()); + if (ap != null) { + if(Arrays.asList(ap.getSupportedActions()).contains(command) && ap.isActionEnabled(command, Lookups.singleton(sm))) { + ap.invokeAction(command, Lookups.singleton(sm)); + } + } + } + } + }, + NbBundle.getMessage(JUnitMethodRunnerProvider.class, "LBL_Action_RunTestMethod"), new AtomicBoolean(), false); + } + + private SingleMethod getTestMethod(Lookup lkp, Document doc, int cursor){ + SingleMethod sm = lkp.lookup(SingleMethod.class); + if (sm == null && doc != null){ + JavaSource js = JavaSource.forDocument(doc); + TestClassInfoTask task = new TestClassInfoTask(cursor); + try { + Future f = js.runWhenScanFinished(task, true); + if (f.isDone() && task.getFileObject() != null && task.getMethodName() != null){ + sm = new SingleMethod(task.getFileObject(), task.getMethodName()); + } + } catch (IOException ex) { + LOGGER.log(Level.WARNING, null, ex); + } + } + return sm; + } + + @Override + public boolean canHandle(Node activatedNode) { + FileObject fileO = CommonTestUtil.getFileObjectFromNode(activatedNode); + if (fileO != null) { + EditorCookie ec = activatedNode.getLookup().lookup(EditorCookie.class); + if (ec != null) { + JEditorPane pane = NbDocument.findRecentEditorPane(ec); + if (pane != null) { + String text = pane.getText(); + int index = text.indexOf("public"); //NOI18N + if (index != -1) { + if (text.substring(0, index).contains("org.junit.")) { //NOI18N + return true; + } + } + } + } + } + return false; + } + +}