diff --git a/ide/gsf.testrunner.ui/nbproject/project.xml b/ide/gsf.testrunner.ui/nbproject/project.xml
index b54d0943cfcc..1fd2cb0553f6 100644
--- a/ide/gsf.testrunner.ui/nbproject/project.xml
+++ b/ide/gsf.testrunner.ui/nbproject/project.xml
@@ -266,6 +266,7 @@
org.netbeans.modules.groovy.support
org.netbeans.modules.hudson.ui
org.netbeans.modules.java.lsp.server
+ org.netbeans.modules.java.openjdk.project
org.netbeans.modules.java.testrunner.ui
org.netbeans.modules.javascript.jstestdriver
org.netbeans.modules.javascript.karma
diff --git a/java/java.openjdk.project/nbproject/project.xml b/java/java.openjdk.project/nbproject/project.xml
index dcbf9178d00a..5a1aac40d2ba 100644
--- a/java/java.openjdk.project/nbproject/project.xml
+++ b/java/java.openjdk.project/nbproject/project.xml
@@ -127,6 +127,14 @@
1.49
+
+ org.netbeans.modules.gsf.testrunner.ui
+
+
+
+ 1.34
+
+
org.netbeans.modules.java.lexer
@@ -179,6 +187,14 @@
2.36
+
+ org.netbeans.modules.java.testrunner.ui
+
+
+
+ 1.23
+
+
org.netbeans.modules.lexer
@@ -188,6 +204,15 @@
1.66
+
+ org.netbeans.modules.parsing.api
+
+
+
+ 1
+ 9.26
+
+
org.netbeans.modules.parsing.indexing
diff --git a/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/jtreg/ActionProviderImpl.java b/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/jtreg/ActionProviderImpl.java
index 6bc5d24c4db8..6f200eec4323 100644
--- a/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/jtreg/ActionProviderImpl.java
+++ b/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/jtreg/ActionProviderImpl.java
@@ -64,6 +64,7 @@
import org.netbeans.spi.java.classpath.support.ClassPathSupport;
import org.netbeans.spi.project.ActionProgress;
import org.netbeans.spi.project.ActionProvider;
+import org.netbeans.spi.project.SingleMethod;
import org.netbeans.spi.project.ui.CustomizerProvider2;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
@@ -97,7 +98,7 @@
*
* @author lahvac
*/
-@ServiceProvider(service=ActionProvider.class)
+@ServiceProvider(service=ActionProvider.class, position=1_000_000)
public class ActionProviderImpl implements ActionProvider {
private static final Logger LOG = Logger.getLogger(ActionProviderImpl.class.getName());
@@ -107,6 +108,8 @@ public class ActionProviderImpl implements ActionProvider {
COMMAND_TEST_SINGLE,
COMMAND_DEBUG_TEST_SINGLE,
COMMAND_PROFILE_TEST_SINGLE,
+ SingleMethod.COMMAND_RUN_SINGLE_METHOD,
+ SingleMethod.COMMAND_DEBUG_SINGLE_METHOD
};
@Override
@@ -129,9 +132,29 @@ public void invokeAction(String command, Lookup context) throws IllegalArgumentE
"DN_Running=Running ({0})",
"LBL_IncorrectVersionSelectJTReg=Location of JTReg:",
"TITLE_IncorrectVersionSelectJTReg=Version of JTReg appears to be incorrect, please select a correct version"})
- public static ExecutorTask createAndRunTest(Lookup context, String command) {
- final FileObject file = context.lookup(FileObject.class);
+ public static ExecutorTask createAndRunTest(Lookup context, String inputCommand) {
+ FileObject file;
+ String query;
+ String command;
+
+ if (SingleMethod.COMMAND_RUN_SINGLE_METHOD.equals(inputCommand) ||
+ SingleMethod.COMMAND_DEBUG_SINGLE_METHOD.equals(inputCommand)) {
+ SingleMethod singleMethod = context.lookup(SingleMethod.class);
+
+ assert singleMethod != null;
+
+ file = singleMethod.getFile();
+ query = singleMethod.getMethodName();
+ command = SingleMethod.COMMAND_RUN_SINGLE_METHOD.equals(inputCommand) ? COMMAND_TEST_SINGLE
+ : COMMAND_DEBUG_TEST_SINGLE;
+ } else {
+ file = context.lookup(FileObject.class);
+ query = null;
+ command = inputCommand;
+ }
+
ensureProjectsRegistered(file);
+
String ioName = COMMAND_DEBUG_TEST_SINGLE.equals(command) ? Bundle.DN_Debugging(file.getName()) : Bundle.DN_Running(file.getName());
StopAction newStop = new StopAction();
ReRunAction newReRun = new ReRunAction(COMMAND_TEST_SINGLE);
@@ -305,7 +328,11 @@ public String[] getExtraMakeTargets() {
}
break;
}
- options.add(FileUtil.toFile(file).getAbsolutePath());
+ String testPath = FileUtil.toFile(file).getAbsolutePath();
+ if (query != null) {
+ testPath += "?" + query;
+ }
+ options.add(testPath);
try {
stop.started();
Process jtregProcess = new ProcessBuilder(options).start();
@@ -702,6 +729,12 @@ private static File findJTRegJar(String installDir) {
public boolean isActionEnabled(String command, Lookup context) throws IllegalArgumentException {
FileObject file = context.lookup(FileObject.class);
+ if (file == null) {
+ SingleMethod singleMethod = context.lookup(SingleMethod.class);
+
+ file = singleMethod != null ? singleMethod.getFile() : null;
+ }
+
if (file == null)
return false;
diff --git a/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/jtreg/ClassPathProviderImpl.java b/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/jtreg/ClassPathProviderImpl.java
index 36ce45d091f6..88f5f3b2d080 100644
--- a/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/jtreg/ClassPathProviderImpl.java
+++ b/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/jtreg/ClassPathProviderImpl.java
@@ -77,10 +77,21 @@ public ClassPath findClassPath(FileObject file, String type) {
if (javac) {
ClassPath langtoolsCP = ClassPath.getClassPath(keyRoot, ClassPath.COMPILE);
Library testngLib = LibraryManager.getDefault().getLibrary("testng");
+ Library junit5Lib = LibraryManager.getDefault().getLibrary("junit_5");
- if (testngLib != null) {
- return ClassPathSupport.createProxyClassPath(ClassPathSupport.createClassPath(testngLib.getContent("classpath").toArray(new URL[0])),
- langtoolsCP);
+ if (testngLib != null || junit5Lib != null) {
+ List parts = new ArrayList<>();
+
+ if (testngLib != null) {
+ parts.add(ClassPathSupport.createClassPath(testngLib.getContent("classpath").toArray(new URL[0])));
+ }
+ if (junit5Lib != null) {
+ parts.add(ClassPathSupport.createClassPath(junit5Lib.getContent("classpath").toArray(new URL[0])));
+ }
+
+ parts.add(langtoolsCP);
+
+ return ClassPathSupport.createProxyClassPath(parts.toArray(new ClassPath[0]));
}
if (langtoolsCP == null)
diff --git a/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/jtreg/TestClassInfoTask.java b/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/jtreg/TestClassInfoTask.java
new file mode 100644
index 000000000000..f2df2ea03a07
--- /dev/null
+++ b/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/jtreg/TestClassInfoTask.java
@@ -0,0 +1,213 @@
+/*
+ * 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.java.openjdk.jtreg;
+
+import com.sun.source.tree.ClassTree;
+import com.sun.source.tree.MethodTree;
+import com.sun.source.tree.Tree;
+import com.sun.source.tree.Tree.Kind;
+import com.sun.source.util.SourcePositions;
+import com.sun.source.util.TreePath;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.stream.Collectors;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.util.Elements;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+import javax.swing.text.Position;
+import org.netbeans.api.java.source.CancellableTask;
+import org.netbeans.api.java.source.CompilationController;
+import org.netbeans.api.java.source.CompilationInfo;
+import org.netbeans.api.java.source.JavaSource.Phase;
+import org.netbeans.modules.gsf.testrunner.ui.api.TestMethodController.TestMethod;
+import org.netbeans.modules.java.testrunner.ui.spi.ComputeTestMethods;
+import org.netbeans.modules.java.testrunner.ui.spi.ComputeTestMethods.Factory;
+import org.netbeans.spi.project.SingleMethod;
+import org.openide.filesystems.FileObject;
+import org.openide.util.lookup.ServiceProvider;
+
+/**
+ *
+ * @author lukas
+ */
+public final class TestClassInfoTask implements CancellableTask {
+
+ private final int caretPosition;
+ private String packageName;
+ private String className;
+ private String methodName;
+ private FileObject fo;
+
+ /**
+ * DO NOT USE! Package private due to use in tests
+ */
+ static String ANNOTATION = "toolbox.TestRunner.Test"; //NOI18N
+
+ TestClassInfoTask(int caretPosition) {
+ this.caretPosition = caretPosition;
+ }
+
+ public void cancel() {
+ }
+
+ public void run(CompilationController controller) throws Exception {
+ controller.toPhase(Phase.RESOLVED);
+ fo = controller.getFileObject();
+ TypeElement typeElement = null;
+ List extends TypeElement> topLevelElements = controller.getTopLevelElements();
+ for (Iterator extends TypeElement> it = topLevelElements.iterator(); it.hasNext();) {
+ typeElement = it.next();
+ if (typeElement.getKind() == ElementKind.CLASS) {
+ className = typeElement.getSimpleName().toString();
+ break;
+ }
+ }
+ Elements elements = controller.getElements();
+ if (typeElement != null) {
+ packageName = elements.getPackageOf(typeElement).getQualifiedName().toString();
+ }
+ List testMethods = computeTestMethods(controller, new AtomicBoolean(), caretPosition);
+ if (!testMethods.isEmpty()) {
+ methodName = testMethods.iterator().next().method().getMethodName();
+ }
+ }
+
+ String getClassName() {
+ return className;
+ }
+
+ String getMethodName() {
+ return methodName;
+ }
+
+ String getPackageName() {
+ return packageName;
+ }
+
+ FileObject getFileObject() {
+ return fo;
+ }
+
+ public static List computeTestMethods(CompilationInfo info, AtomicBoolean cancel, int caretPosIfAny) {
+ //TODO: first verify if this is a test class/class in a test source group?
+ FileObject fileObject = info.getFileObject();
+ ClassTree clazz;
+ List methods;
+ if (caretPosIfAny == (-1)) {
+ Optional extends Tree> anyClass = info.getCompilationUnit().getTypeDecls().stream().filter(t -> t.getKind() == Kind.CLASS).findAny();
+ if (!anyClass.isPresent()) {
+ return Collections.emptyList();
+ }
+ clazz = (ClassTree) anyClass.get();
+ TreePath pathToClass = new TreePath(new TreePath(info.getCompilationUnit()), clazz);
+ methods = clazz.getMembers().stream().filter(m -> m.getKind() == Kind.METHOD).map(m -> new TreePath(pathToClass, m)).collect(Collectors.toList());
+ } else {
+ TreePath tp = info.getTreeUtilities().pathFor(caretPosIfAny);
+ while (tp != null && tp.getLeaf().getKind() != Kind.METHOD) {
+ tp = tp.getParentPath();
+ }
+ if (tp != null) {
+ clazz = (ClassTree) tp.getParentPath().getLeaf();
+ methods = Collections.singletonList(tp);
+ } else {
+ return Collections.emptyList();
+ }
+ }
+ TypeElement typeElement = (TypeElement) info.getTrees().getElement(new TreePath(new TreePath(info.getCompilationUnit()), clazz));
+ Elements elements = info.getElements();
+ List result = new ArrayList<>();
+ for (TreePath tp : methods) {
+ if (cancel.get()) {
+ return null;
+ }
+ Element element = info.getTrees().getElement(tp);
+ if (element != null) {
+ List extends AnnotationMirror> allAnnotationMirrors = elements.getAllAnnotationMirrors(element);
+ for (Iterator extends AnnotationMirror> it = allAnnotationMirrors.iterator(); it.hasNext();) {
+ AnnotationMirror annotationMirror = it.next();
+ TypeElement annTypeElement = (TypeElement) annotationMirror.getAnnotationType().asElement();
+ if (annTypeElement.getQualifiedName().contentEquals(ANNOTATION)) {
+ String mn = element.getSimpleName().toString();
+ SourcePositions sp = info.getTrees().getSourcePositions();
+ int start = (int) sp.getStartPosition(tp.getCompilationUnit(), tp.getLeaf());
+ int preferred = info.getTreeUtilities().findNameSpan((MethodTree) tp.getLeaf())[0];
+ int end = (int) sp.getEndPosition(tp.getCompilationUnit(), tp.getLeaf());
+ Document doc = info.getSnapshot().getSource().getDocument(false);
+ try {
+ result.add(new TestMethod(typeElement.getQualifiedName().toString(), new SingleMethod(fileObject, mn),
+ doc != null ? doc.createPosition(start) : new SimplePosition(start),
+ doc != null ? doc.createPosition(preferred) : new SimplePosition(preferred),
+ doc != null ? doc.createPosition(end) : new SimplePosition(end)));
+ } catch (BadLocationException ex) {
+ //ignore
+ }
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ @ServiceProvider(service=Factory.class)
+ public static final class ComputeTestMethodsImpl implements Factory {
+
+ @Override
+ public ComputeTestMethods create() {
+ return new TaskImpl();
+ }
+
+ private static class TaskImpl implements ComputeTestMethods {
+
+ private final AtomicBoolean cancel = new AtomicBoolean();
+
+ @Override
+ public void cancel() {
+ cancel.set(true);
+ }
+
+ @Override
+ public List computeTestMethods(CompilationInfo info) {
+ return TestClassInfoTask.computeTestMethods(info, cancel, -1);
+ }
+ }
+
+ }
+
+ private static class SimplePosition implements Position {
+
+ private final int offset;
+
+ private SimplePosition(int offset) {
+ this.offset = offset;
+ }
+
+ @Override
+ public int getOffset() {
+ return offset;
+ }
+ }
+}
diff --git a/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/project/ActionProviderImpl.java b/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/project/ActionProviderImpl.java
index b39c5683b816..cba40fd7d7ae 100644
--- a/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/project/ActionProviderImpl.java
+++ b/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/project/ActionProviderImpl.java
@@ -38,6 +38,7 @@
import org.netbeans.spi.java.classpath.support.ClassPathSupport;
import org.netbeans.spi.project.ActionProgress;
import org.netbeans.spi.project.ActionProvider;
+import org.netbeans.spi.project.SingleMethod;
import org.netbeans.spi.project.ui.support.ProjectSensitiveActions;
import org.openide.execution.ExecutorTask;
import org.openide.filesystems.FileObject;
@@ -151,6 +152,8 @@ private String[] readSupportedActions(FileObject from) {
filteredActions.retainAll(Arrays.asList(actions));
filteredActions.add(COMMAND_BUILD_GENERIC_FAST);
filteredActions.add(COMMAND_PROFILE_TEST_SINGLE);
+ filteredActions.add(SingleMethod.COMMAND_RUN_SINGLE_METHOD);
+ filteredActions.add(SingleMethod.COMMAND_DEBUG_SINGLE_METHOD);
supported = filteredActions.toArray(new String[0]);
break;
}
@@ -178,6 +181,15 @@ public void invokeAction(String command, Lookup context) throws IllegalArgumentE
}
}
}
+ if (SingleMethod.COMMAND_RUN_SINGLE_METHOD.equals(command) ||
+ SingleMethod.COMMAND_DEBUG_SINGLE_METHOD.equals(command)) {
+ for (ActionProvider ap : Lookup.getDefault().lookupAll(ActionProvider.class)) {
+ if (new HashSet<>(Arrays.asList(ap.getSupportedActions())).contains(command) && ap.isActionEnabled(command, context)) {
+ ap.invokeAction(command, context);
+ return ;
+ }
+ }
+ }
FileObject scriptFO = script;
Settings settings = project.getLookup().lookup(Settings.class);
Properties props = new Properties();
diff --git a/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/project/ClassPathProviderImpl.java b/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/project/ClassPathProviderImpl.java
index bca41f058dca..dbecca593677 100644
--- a/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/project/ClassPathProviderImpl.java
+++ b/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/project/ClassPathProviderImpl.java
@@ -194,7 +194,7 @@ public ClassPathProviderImpl(JDKProject project, ModuleRepository repository) {
this.repository = repository;
}
- private static final String[] TEST_LIBRARIES = new String[] {"testng", "junit_4"};
+ private static final String[] TEST_LIBRARIES = new String[] {"testng", "junit_4", "junit_5"};
private static URL projectDir2FakeTarget(FileObject projectDir) throws MalformedURLException {
return FileUtil.getArchiveRoot(projectDir.toURI().resolve("fake-target.jar").toURL());
diff --git a/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/project/JDKProject.java b/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/project/JDKProject.java
index 35d639661757..4e98d449e2e9 100644
--- a/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/project/JDKProject.java
+++ b/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/project/JDKProject.java
@@ -222,6 +222,7 @@ public JDKProject(FileObject projectDir, @NullAllowed ModuleRepository moduleRep
new Settings(this),
new BinaryForSourceQueryImpl(this, cpp.getSourceCP()),
CProjectConfigurationProviderImpl.create(this),
+ new UnitTestForSourceQueryImpl(this),
this);
this.lookup = LookupProviderSupport.createCompositeLookup(base, "Projects/" + PROJECT_KEY + "/Lookup");
} catch (Throwable t) {
diff --git a/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/project/UnitTestForSourceQueryImpl.java b/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/project/UnitTestForSourceQueryImpl.java
new file mode 100644
index 000000000000..8bba362c3376
--- /dev/null
+++ b/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/project/UnitTestForSourceQueryImpl.java
@@ -0,0 +1,64 @@
+/*
+ * 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.java.openjdk.project;
+
+import java.net.URL;
+import java.util.Arrays;
+import org.netbeans.api.java.project.JavaProjectConstants;
+import org.netbeans.api.project.ProjectUtils;
+import org.netbeans.api.project.SourceGroup;
+import org.netbeans.modules.java.openjdk.project.JDKProject;
+import org.netbeans.spi.java.queries.MultipleRootsUnitTestForSourceQueryImplementation;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileUtil;
+
+/**
+ *
+ * @author lahvac
+ */
+public class UnitTestForSourceQueryImpl implements MultipleRootsUnitTestForSourceQueryImplementation {
+
+ private final JDKProject prj;
+
+ public UnitTestForSourceQueryImpl(JDKProject prj) {
+ this.prj = prj;
+ }
+
+ @Override
+ public URL[] findUnitTests(FileObject source) {
+ SourceGroup[] groups = ProjectUtils.getSources(prj)
+ .getSourceGroups(SourcesImpl.SOURCES_TYPE_JDK_PROJECT_TESTS);
+ return notInReturn(source, groups);
+ }
+
+ @Override
+ public URL[] findSources(FileObject unitTest) {
+ SourceGroup[] groups = ProjectUtils.getSources(prj)
+ .getSourceGroups(JavaProjectConstants.SOURCES_TYPE_JAVA);
+ return notInReturn(unitTest, groups);
+ }
+
+ private URL[] notInReturn(FileObject file, SourceGroup[] groups) {
+ return Arrays.stream(groups)
+ .map(sg -> sg.getRootFolder())
+ .filter(root -> FileUtil.isParentOf(root, file) || root == file)
+ .map(f -> f.toURL())
+ .toArray(s -> new URL[s]);
+ }
+}
diff --git a/java/java.testrunner.ui/nbproject/project.xml b/java/java.testrunner.ui/nbproject/project.xml
index e9147c5546b8..30b1e91f25ce 100644
--- a/java/java.testrunner.ui/nbproject/project.xml
+++ b/java/java.testrunner.ui/nbproject/project.xml
@@ -197,6 +197,7 @@
org.netbeans.modules.gradle.test
org.netbeans.modules.java.lsp.server
+ org.netbeans.modules.java.openjdk.project
org.netbeans.modules.junit.ant.ui
org.netbeans.modules.junit.ui
org.netbeans.modules.maven.junit.ui
diff --git a/java/testng.ui/nbproject/project.xml b/java/testng.ui/nbproject/project.xml
index 1bbbafb61704..971beaa66b7a 100644
--- a/java/testng.ui/nbproject/project.xml
+++ b/java/testng.ui/nbproject/project.xml
@@ -456,14 +456,24 @@
+
+ org.netbeans.modules.parsing.indexing
+
+
org.netbeans.modules.parsing.lucene
+
+ org.netbeans.modules.parsing.nb
+
org.netbeans.modules.progress.ui
+
+ org.netbeans.modules.projectapi.nb
+
org.netbeans.modules.projectui
@@ -498,12 +508,12 @@
org.openide.text
- org.openide.util.ui
+ org.openide.util.lookup
- org.openide.util.lookup
+ org.openide.util.ui
diff --git a/java/testng.ui/src/org/netbeans/modules/testng/ui/actions/TestClassInfoTask.java b/java/testng.ui/src/org/netbeans/modules/testng/ui/actions/TestClassInfoTask.java
index eddfc91564ca..5a9bb9b78155 100644
--- a/java/testng.ui/src/org/netbeans/modules/testng/ui/actions/TestClassInfoTask.java
+++ b/java/testng.ui/src/org/netbeans/modules/testng/ui/actions/TestClassInfoTask.java
@@ -34,6 +34,8 @@
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.QualifiedNameable;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;
import javax.swing.text.BadLocationException;
@@ -66,6 +68,7 @@ public final class TestClassInfoTask implements CancellableTaskDO NOT USE! Package private due to use in tests
*/
static String ANNOTATION = "org.testng.annotations.Test"; //NOI18N
+ static String TESTNG_ANNOTATION_PACKAGE = "org.testng.annotations"; //NOI18N
TestClassInfoTask(int caretPosition) {
this.caretPosition = caretPosition;
@@ -139,39 +142,52 @@ public static List computeTestMethods(CompilationInfo info, AtomicBo
}
TypeElement typeElement = (TypeElement) info.getTrees().getElement(new TreePath(new TreePath(info.getCompilationUnit()), clazz));
Elements elements = info.getElements();
+ boolean hasClassLevelAnnotation = hasTestNGTestAnnotation(elements, typeElement);
List result = new ArrayList<>();
for (TreePath tp : methods) {
if (cancel.get()) {
return null;
}
Element element = info.getTrees().getElement(tp);
- if (element != null) {
- List extends AnnotationMirror> allAnnotationMirrors = elements.getAllAnnotationMirrors(element);
- for (Iterator extends AnnotationMirror> it = allAnnotationMirrors.iterator(); it.hasNext();) {
- AnnotationMirror annotationMirror = it.next();
- TypeElement annTypeElement = (TypeElement) annotationMirror.getAnnotationType().asElement();
- if (annTypeElement.getQualifiedName().contentEquals(ANNOTATION)) {
- String mn = element.getSimpleName().toString();
- SourcePositions sp = info.getTrees().getSourcePositions();
- int start = (int) sp.getStartPosition(tp.getCompilationUnit(), tp.getLeaf());
- int preferred = info.getTreeUtilities().findNameSpan((MethodTree) tp.getLeaf())[0];
- int end = (int) sp.getEndPosition(tp.getCompilationUnit(), tp.getLeaf());
- Document doc = info.getSnapshot().getSource().getDocument(false);
- try {
- result.add(new TestMethod(typeElement.getQualifiedName().toString(), new SingleMethod(fileObject, mn),
- doc != null ? doc.createPosition(start) : new SimplePosition(start),
- doc != null ? doc.createPosition(preferred) : new SimplePosition(preferred),
- doc != null ? doc.createPosition(end) : new SimplePosition(end)));
- } catch (BadLocationException ex) {
- //ignore
+ if (element != null && element.getKind() == ElementKind.METHOD) {
+ if (hasTestNGTestAnnotation(elements, element) ||
+ (hasClassLevelAnnotation && element.getModifiers().contains(Modifier.PUBLIC) &&
+ !hasTestNGAnnotation(elements, element))) {
+ String mn = element.getSimpleName().toString();
+ SourcePositions sp = info.getTrees().getSourcePositions();
+ int start = (int) sp.getStartPosition(tp.getCompilationUnit(), tp.getLeaf());
+ int preferred = info.getTreeUtilities().findNameSpan((MethodTree) tp.getLeaf())[0];
+ int end = (int) sp.getEndPosition(tp.getCompilationUnit(), tp.getLeaf());
+ Document doc = info.getSnapshot().getSource().getDocument(false);
+ try {
+ result.add(new TestMethod(typeElement.getQualifiedName().toString(), new SingleMethod(fileObject, mn),
+ doc != null ? doc.createPosition(start) : new SimplePosition(start),
+ doc != null ? doc.createPosition(preferred) : new SimplePosition(preferred),
+ doc != null ? doc.createPosition(end) : new SimplePosition(end)));
+ } catch (BadLocationException ex) {
+ //ignore
}
}
}
}
- }
return result;
}
+ private static boolean hasTestNGTestAnnotation(Elements elements, Element element) {
+ return elements.getAllAnnotationMirrors(element)
+ .stream()
+ .map(am -> (TypeElement) am.getAnnotationType().asElement())
+ .anyMatch(annTypeElement -> annTypeElement.getQualifiedName().contentEquals(ANNOTATION));
+ }
+
+ private static boolean hasTestNGAnnotation(Elements elements, Element element) {
+ return elements.getAllAnnotationMirrors(element)
+ .stream()
+ .map(am -> (TypeElement) am.getAnnotationType().asElement())
+ .map(te -> (QualifiedNameable) te.getEnclosingElement())
+ .anyMatch(annTypeElement -> annTypeElement.getQualifiedName().contentEquals(TESTNG_ANNOTATION_PACKAGE));
+ }
+
@ServiceProvider(service=Factory.class)
public static final class ComputeTestMethodsImpl implements Factory {
diff --git a/java/testng.ui/test/unit/src/org/netbeans/modules/testng/ui/actions/RetoucheTestBase.java b/java/testng.ui/test/unit/src/org/netbeans/modules/testng/ui/actions/RetoucheTestBase.java
index e5e9268cc176..11afdedbc480 100644
--- a/java/testng.ui/test/unit/src/org/netbeans/modules/testng/ui/actions/RetoucheTestBase.java
+++ b/java/testng.ui/test/unit/src/org/netbeans/modules/testng/ui/actions/RetoucheTestBase.java
@@ -74,16 +74,6 @@ public ClassPath findClassPath(FileObject file, String type) {
new String[]{},
new Object[]{loader, cpp});
testFO = FileUtil.createFolder(src, "sample/pkg/").createData("Test.java");
- TestUtilities.copyStringToFile(testFO,
- "package sample.pkg;\n" +
- "\n" +
- "public class Test {\n" +
- "\n" +
- " @Deprecated\n" +
- " void method() {\n" +
- " }\n" +
- "\n" +
- "}\n");
}
protected FileObject getTestFO() {
diff --git a/java/testng.ui/test/unit/src/org/netbeans/modules/testng/ui/actions/TestClassInfoTaskTest.java b/java/testng.ui/test/unit/src/org/netbeans/modules/testng/ui/actions/TestClassInfoTaskTest.java
index 4eeb3a8a32eb..060cda54176f 100644
--- a/java/testng.ui/test/unit/src/org/netbeans/modules/testng/ui/actions/TestClassInfoTaskTest.java
+++ b/java/testng.ui/test/unit/src/org/netbeans/modules/testng/ui/actions/TestClassInfoTaskTest.java
@@ -18,8 +18,11 @@
*/
package org.netbeans.modules.testng.ui.actions;
+import java.util.concurrent.atomic.AtomicBoolean;
import org.netbeans.api.java.source.JavaSource;
+import org.netbeans.api.java.source.JavaSource.Phase;
import org.netbeans.api.java.source.TestUtilities;
+import org.testng.annotations.BeforeMethod;
import org.testng.annotations.BeforeSuite;
import org.testng.annotations.Test;
@@ -32,8 +35,20 @@ public class TestClassInfoTaskTest extends RetoucheTestBase {
static {
TestClassInfoTask.ANNOTATION = "java.lang.Deprecated";
+ TestClassInfoTask.TESTNG_ANNOTATION_PACKAGE = "java.lang";
}
+ private static final String DEFAULT_TEST_DATA =
+ "package sample.pkg;\n" +
+ "\n" +
+ "public class Test {\n" +
+ "\n" +
+ " @Deprecated\n" +
+ " void method() {\n" +
+ " }\n" +
+ "\n" +
+ "}\n";
+
public TestClassInfoTaskTest(String testName) {
super(testName);
}
@@ -44,6 +59,7 @@ public void setupClass() throws Exception {
}
public void testCursorInMethod() throws Exception {
+ TestUtilities.copyStringToFile(getTestFO(), DEFAULT_TEST_DATA);
JavaSource src = JavaSource.forFileObject(getTestFO());
TestClassInfoTask task = new TestClassInfoTask(70);
src.runUserActionTask(task, true);
@@ -53,6 +69,7 @@ public void testCursorInMethod() throws Exception {
}
public void testCursorInClass() throws Exception {
+ TestUtilities.copyStringToFile(getTestFO(), DEFAULT_TEST_DATA);
JavaSource src = JavaSource.forFileObject(getTestFO());
TestClassInfoTask task = new TestClassInfoTask(42);
src.runUserActionTask(task, true);
@@ -62,6 +79,7 @@ public void testCursorInClass() throws Exception {
}
public void testCursorInClass2() throws Exception {
+ TestUtilities.copyStringToFile(getTestFO(), DEFAULT_TEST_DATA);
JavaSource src = JavaSource.forFileObject(getTestFO());
TestClassInfoTask task = new TestClassInfoTask(0);
src.runUserActionTask(task, true);
@@ -71,6 +89,7 @@ public void testCursorInClass2() throws Exception {
}
public void testCursorInClass3() throws Exception {
+ TestUtilities.copyStringToFile(getTestFO(), DEFAULT_TEST_DATA);
JavaSource src = JavaSource.forFileObject(getTestFO());
TestClassInfoTask task = new TestClassInfoTask(87);
src.runUserActionTask(task, true);
@@ -95,4 +114,50 @@ public void testDefaultPackage() throws Exception {
assertEquals("", task.getPackageName());
assertEquals("Test", task.getClassName());
}
+
+ public void testClassAnnotated1() throws Exception {
+ String code = "package test;\n" +
+ "@Deprecated\n" +
+ "public class Test {\n" +
+ " public void method1() {\n" +
+ " //test1\n" +
+ " }\n" +
+ " @SuppressWarnings(\"\")\n" +
+ " public void method2() {\n" +
+ " //test2\n" +
+ " }\n" +
+ " void method3() {\n" +
+ " //test3\n" +
+ " }\n" +
+ " public static void method4() {\n" +
+ " //test4\n" +
+ " }\n" +
+ "}\n";
+ TestUtilities.copyStringToFile(getTestFO(), code);
+ JavaSource src = JavaSource.forFileObject(getTestFO());
+ TestClassInfoTask task1 = new TestClassInfoTask(code.indexOf("//test1"));
+ src.runUserActionTask(task1, true);
+ assertEquals("method1", task1.getMethodName());
+ assertEquals("test", task1.getPackageName());
+ assertEquals("Test", task1.getClassName());
+ TestClassInfoTask task2 = new TestClassInfoTask(code.indexOf("//test2"));
+ src.runUserActionTask(task2, true);
+ assertNull(task2.getMethodName());
+ assertEquals("test", task2.getPackageName());
+ assertEquals("Test", task2.getClassName());
+ TestClassInfoTask task3 = new TestClassInfoTask(code.indexOf("//test3"));
+ src.runUserActionTask(task3, true);
+ assertNull(task3.getMethodName());
+ assertEquals("test", task3.getPackageName());
+ assertEquals("Test", task3.getClassName());
+ TestClassInfoTask task4 = new TestClassInfoTask(code.indexOf("//test4"));
+ src.runUserActionTask(task4, true);
+ assertEquals("method4", task4.getMethodName());
+ assertEquals("test", task4.getPackageName());
+ assertEquals("Test", task4.getClassName());
+ src.runUserActionTask(cc -> {
+ cc.toPhase(Phase.ELEMENTS_RESOLVED);
+ assertEquals(2, TestClassInfoTask.computeTestMethods(cc, new AtomicBoolean(), -1).size());
+ }, true);
+ }
}