blob: c4479be17e13f2474a92910efa376dadd2096bac [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.junit.ui;
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.TestCreatorProvider;
import static org.netbeans.modules.gsf.testrunner.api.TestCreatorProvider.getSourceGroup;
import org.netbeans.modules.gsf.testrunner.plugin.CommonPlugin;
import org.netbeans.modules.gsf.testrunner.ui.api.UICommonUtils;
import org.netbeans.modules.junit.api.JUnitVersion;
import org.netbeans.modules.junit.api.JUnitTestUtil;
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.DataObject;
import org.openide.loaders.DataObjectNotFoundException;
import org.openide.nodes.Node;
import org.openide.util.NbBundle;
import org.openide.util.RequestProcessor;
abstract class AbstractJUnitTestCreatorProvider extends TestCreatorProvider {
abstract JUnitVersion useVersion();
@Override
public boolean enable(FileObject[] activatedFOs) {
if (activatedFOs == null || activatedFOs.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 (activatedFOs.length == 1) {
FileObject fileObj = activatedFOs[0];
Project project;
if ((fileObj != null)
&& fileObj.isValid()
// selected FO might be folder or java file
&& (fileObj.isFolder() || JUnitTestUtil.isJavaFile(fileObj))
&& ((project = FileOwnerQuery.getOwner(fileObj)) != null)
&& (getSourceGroup(fileObj, project) != null)) {
JUnitPlugin plugin = JUnitTestUtil.getPluginForProject(project, useVersion());
return JUnitTestUtil.canCreateTests(plugin, fileObj);
} else {
return false;
}
}
final Collection<FileObject> fileObjs = new ArrayList<>(activatedFOs.length);
Project theProject = null;
boolean result = false;
for (FileObject fileObj : activatedFOs) {
if ((fileObj == null) || !fileObj.isValid()
// selected FO might be folder or java file
&& (fileObj.isFolder() || JUnitTestUtil.isJavaFile(fileObj))) {
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) {
result = true;
}
}
}
if (theProject != null) {
JUnitPlugin plugin = JUnitTestUtil.getPluginForProject(theProject);
result &= JUnitTestUtil.canCreateTests(
plugin,
fileObjs.toArray(new FileObject[fileObjs.size()]));
}
return result;
}
@Override
public void createTests(Context context) {
String problem;
if ((problem = checkNodesValidity(context.getActivatedFOs())) != null) {
// TODO report problem
NotifyDescriptor msg = new NotifyDescriptor.Message(
problem, NotifyDescriptor.WARNING_MESSAGE);
DialogDisplayer.getDefault().notify(msg);
return;
}
final FileObject[] filesToTest = context.getActivatedFOs();
if (filesToTest == null) {
return; //XXX: display some message
}
/*
* Determine the plugin to be used:
*/
final JUnitPlugin plugin = JUnitTestUtil.getPluginForProject(
FileOwnerQuery.getOwner(filesToTest[0]), useVersion()
);
if (!JUnitTestUtil.createTestActionCalled(
plugin, filesToTest)) {
return;
}
/*
* Store the configuration data:
*/
final boolean singleClass = context.isSingleClass();
final Map<CommonPlugin.CreateTestParam, Object> params = JUnitTestUtil.getSettingsMap(!singleClass);
if (singleClass) {
params.put(CommonPlugin.CreateTestParam.CLASS_NAME, context.getTestClassName());
}
final FileObject targetFolder = context.getTargetFolder();
if(context.isIntegrationTests()) {
params.put(CommonPlugin.CreateTestParam.INC_GENERATE_INTEGRATION_TEST, Boolean.TRUE);
} else {
params.put(CommonPlugin.CreateTestParam.INC_GENERATE_INTEGRATION_TEST, Boolean.FALSE);
}
RequestProcessor.getDefault().post(new Runnable() {
@Override
public void run() {
/*
* Now create the tests:
*/
final FileObject[] testFileObjects = JUnitTestUtil.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(FileObject[] files) {
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<FileObject> 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<FileObject>(
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)
|| !JUnitTestUtil.isValidPackageName(packageName)) {
return false;
}
}
return true;
}
}
/**
* Get the package name of <code>file</code>.
*
* @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 = JUnitTestUtil.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] = UICommonUtils.getFileObjectFromNode(nodes[i]);
}
return ret;
}
/**
* Get the single project for <code>nodes</code> 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 <code>FileObject</code> 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 <code>FileObject</code> from.
* @return the grabbed <code>FileObject</code>,
* or <code>null</code> in case of failure
*/
private static FileObject getTestFileObject(final Node node) {
final FileObject fo = UICommonUtils.getFileObjectFromNode(node);
if (fo == null) {
JUnitTestUtil.notifyUser(NbBundle.getMessage(
JUnitTestCreatorProvider.class,
"MSG_file_from_node_failed")); //NOI18N
return null;
}
ClassPath cp = ClassPath.getClassPath(fo, ClassPath.SOURCE);
if (cp == null) {
JUnitTestUtil.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;
}
}