blob: 87e27f84645f956abfb0ff4880ea6e7803019fb8 [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.maven.junit.ui;
import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.tree.Tree;
import com.sun.source.util.Trees;
import java.io.IOException;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.util.ElementFilter;
import javax.swing.Action;
import org.netbeans.api.annotations.common.NonNull;
import org.netbeans.api.extexecution.print.LineConvertors.FileLocator;
import org.netbeans.api.java.source.CompilationController;
import org.netbeans.api.java.source.JavaSource;
import org.netbeans.api.java.source.JavaSource.Phase;
import org.netbeans.api.java.source.Task;
import org.netbeans.modules.gsf.testrunner.api.CommonUtils;
import org.netbeans.modules.gsf.testrunner.ui.api.TestMethodNode;
import org.netbeans.modules.gsf.testrunner.ui.api.TestsuiteNode;
import org.netbeans.modules.junit.ui.api.JUnitTestMethodNode;
import org.netbeans.modules.java.testrunner.ui.api.NodeOpener;
import org.netbeans.modules.java.testrunner.ui.api.UIJavaUtils;
import org.netbeans.modules.junit.ui.api.JUnitCallstackFrameNode;
import org.openide.ErrorManager;
import org.openide.filesystems.FileObject;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
/**
*
* @author Marian Petras
*/
@NodeOpener.Registration(projectType = CommonUtils.MAVEN_PROJECT_TYPE, testingFramework = CommonUtils.JUNIT_TF)
public final class MavenJUnitNodeOpener extends NodeOpener {
private static final Logger LOG = Logger.getLogger(MavenJUnitNodeOpener.class.getName());
static final Action[] NO_ACTIONS = new Action[0];
public void openTestsuite(TestsuiteNode node) {
Children childrens = node.getChildren();
if (childrens != null) {
Node child = childrens.getNodeAt(0);
if ((child != null) && (child instanceof MavenJUnitTestMethodNode)) {
final FileObject fo = ((MavenJUnitTestMethodNode) child).getTestcaseFileObject();
if (fo != null) {
final long[] line = new long[]{0};
JavaSource javaSource = JavaSource.forFileObject(fo);
if (javaSource != null) {
try {
javaSource.runUserActionTask(new Task<CompilationController>() {
@Override
public void run(CompilationController compilationController) throws Exception {
compilationController.toPhase(Phase.ELEMENTS_RESOLVED);
Trees trees = compilationController.getTrees();
CompilationUnitTree compilationUnitTree = compilationController.getCompilationUnit();
List<? extends Tree> typeDecls = compilationUnitTree.getTypeDecls();
for (Tree tree : typeDecls) {
Element element = trees.getElement(trees.getPath(compilationUnitTree, tree));
if (element != null && element.getKind() == ElementKind.CLASS && element.getSimpleName().contentEquals(fo.getName())) {
long pos = trees.getSourcePositions().getStartPosition(compilationUnitTree, tree);
line[0] = compilationUnitTree.getLineMap().getLineNumber(pos);
break;
}
}
}
}, true);
} catch (IOException ioe) {
ErrorManager.getDefault().notify(ioe);
}
}
UIJavaUtils.openFile(fo, (int) line[0]);
}
}
}
}
public void openTestMethod(final TestMethodNode node) {
if (!(node instanceof MavenJUnitTestMethodNode)) {
return;
}
final FileObject fo = ((MavenJUnitTestMethodNode) node).getTestcaseFileObject();
if (fo != null) {
final FileObject[] fo2open = new FileObject[]{fo};
final long[] line = new long[]{0};
JavaSource javaSource = JavaSource.forFileObject(fo2open[0]);
if (javaSource != null) {
try {
javaSource.runUserActionTask(new Task<CompilationController>() {
@Override
public void run(CompilationController compilationController) throws Exception {
compilationController.toPhase(Phase.ELEMENTS_RESOLVED);
Trees trees = compilationController.getTrees();
CompilationUnitTree compilationUnitTree = compilationController.getCompilationUnit();
List<? extends Tree> typeDecls = compilationUnitTree.getTypeDecls();
for (Tree tree : typeDecls) {
Element element = trees.getElement(trees.getPath(compilationUnitTree, tree));
if (element != null && element.getKind() == ElementKind.CLASS && element.getSimpleName().contentEquals(fo2open[0].getName())) {
List<? extends ExecutableElement> methodElements = ElementFilter.methodsIn(element.getEnclosedElements());
for (Element child : methodElements) {
String name = node.getTestcase().getName(); // package.name.method.name
if (child.getSimpleName().contentEquals(name.substring(name.lastIndexOf(".") + 1))) {
long pos = trees.getSourcePositions().getStartPosition(compilationUnitTree, trees.getTree(child));
line[0] = compilationUnitTree.getLineMap().getLineNumber(pos);
break;
}
}
// method not found in this FO, so try to find where this method belongs
if (line[0] == 0) {
UIJavaUtils.searchAllMethods(node, fo2open, line, compilationController, element);
}
break;
}
}
}
}, true);
} catch (IOException ioe) {
ErrorManager.getDefault().notify(ioe);
}
}
UIJavaUtils.openFile(fo2open[0], (int) line[0]);
}
}
public void openCallstackFrame(Node node, @NonNull String frameInfo) {
if(frameInfo.isEmpty()) { // user probably clicked on a failed test method node, find failing line within the testMethod using the stacktrace
if (!(node instanceof JUnitTestMethodNode)) {
return;
}
} else { // user probably clicked on a stacktrace node
if (!(node instanceof JUnitCallstackFrameNode)) {
return;
}
}
JUnitTestMethodNode methodNode = (JUnitTestMethodNode) UIJavaUtils.getTestMethodNode(node);
if (!(methodNode instanceof MavenJUnitTestMethodNode)) {
return;
}
FileLocator locator = methodNode.getTestcase().getSession().getFileLocator();
if (locator == null) {
return;
}
FileObject testfo = ((MavenJUnitTestMethodNode) methodNode).getTestcaseFileObject();
if (testfo == null) {
//#221053 more logging
StringBuilder stack = new StringBuilder();
if (methodNode.getTestcase().getTrouble() != null) {
String[] st = methodNode.getTestcase().getTrouble().getStackTrace();
if (st != null) {
stack.append("\n");
for (String s : st) {
stack.append(s).append("\n");
}
} else {
stack.append("<none>");
}
} else {
stack.append("<none>");
}
LOG.log(Level.INFO, "#221053: unknown location: {0} classname:{1}, stacktrace:", new Object[]{methodNode.getTestcase().getLocation(), methodNode.getTestcase().getClassName(), stack});
}
final int[] lineNumStorage = new int[1];
FileObject file = UIJavaUtils.getFile(frameInfo, lineNumStorage, locator);
//lineNumStorage -1 means no regexp for stacktrace was matched.
if (testfo != null && file == null && methodNode.getTestcase().getTrouble() != null && lineNumStorage[0] == -1) {
//213935 we could not recognize the stack trace line and map it to known file
//if it's a failure text, grab the testcase's own line from the stack.
String[] st = methodNode.getTestcase().getTrouble().getStackTrace();
if ((st != null) && (st.length > 0)) {
int index = st.length - 1;
//213935 we need to find the testcase linenumber to jump to.
// and ignore the infrastructure stack lines in the process
while (!testfo.equals(file) && index != -1) {
file = UIJavaUtils.getFile(st[index], lineNumStorage, locator);
index = index - 1;
}
}
}
// Is this a @Test(expected = *Exception.class) test method that failed?
if (file == null && lineNumStorage[0] == -1 && node instanceof MavenJUnitTestMethodNode) {
openTestMethod((MavenJUnitTestMethodNode) node);
}
UIJavaUtils.openFile(file, lineNumStorage[0]);
}
}