You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@netbeans.apache.org by th...@apache.org on 2025/08/29 13:36:20 UTC
(netbeans) 03/04: Gradle JUnit: Support nested and top-level non-public tests
This is an automated email from the ASF dual-hosted git repository.
thurka pushed a commit to branch vsnetbeans_2701
in repository https://gitbox.apache.org/repos/asf/netbeans.git
commit 96c7410c4a9225edd3b7de2d6028a893bd061021
Author: Matthias Bläsing <mb...@doppel-helix.eu>
AuthorDate: Tue Jul 22 21:15:54 2025 +0200
Gradle JUnit: Support nested and top-level non-public tests
---
java/gradle.test/nbproject/project.properties | 2 +-
java/gradle.test/nbproject/project.xml | 36 +++++----
.../gradle/test/GradleTestProgressListener.java | 92 +++++++++++++++++-----
.../gradle/test/ui/nodes/GradleTestMethodNode.java | 48 ++++++++---
4 files changed, 132 insertions(+), 46 deletions(-)
diff --git a/java/gradle.test/nbproject/project.properties b/java/gradle.test/nbproject/project.properties
index f39ff4a0268..6ef89b565a6 100644
--- a/java/gradle.test/nbproject/project.properties
+++ b/java/gradle.test/nbproject/project.properties
@@ -16,6 +16,6 @@
# under the License.
is.eager=true
-javac.source=1.8
+javac.release=17
javac.compilerargs=-Xlint -Xlint:-serial
nbm.module.author=Laszlo Kishalmi
diff --git a/java/gradle.test/nbproject/project.xml b/java/gradle.test/nbproject/project.xml
index efe3ef690eb..b796e54b21b 100644
--- a/java/gradle.test/nbproject/project.xml
+++ b/java/gradle.test/nbproject/project.xml
@@ -26,46 +26,46 @@
<code-name-base>org.netbeans.modules.gradle.test</code-name-base>
<module-dependencies>
<dependency>
- <code-name-base>org.netbeans.modules.libs.gradle</code-name-base>
+ <code-name-base>org.netbeans.api.java.classpath</code-name-base>
+ <build-prerequisite/>
<compile-dependency/>
<run-dependency>
- <release-version>8</release-version>
- <specification-version>8.0.1</specification-version>
+ <release-version>1</release-version>
+ <specification-version>1.41.1</specification-version>
</run-dependency>
</dependency>
<dependency>
- <code-name-base>org.netbeans.modules.gradle</code-name-base>
+ <code-name-base>org.netbeans.libs.javacapi</code-name-base>
<build-prerequisite/>
<compile-dependency/>
<run-dependency>
- <release-version>2</release-version>
- <specification-version>2.0</specification-version>
+ <specification-version>8.53</specification-version>
</run-dependency>
</dependency>
<dependency>
- <code-name-base>org.netbeans.modules.gradle.java</code-name-base>
+ <code-name-base>org.netbeans.modules.extexecution</code-name-base>
<build-prerequisite/>
<compile-dependency/>
<run-dependency>
- <specification-version>1.17</specification-version>
+ <release-version>2</release-version>
+ <specification-version>1.45</specification-version>
</run-dependency>
</dependency>
<dependency>
- <code-name-base>org.netbeans.api.java.classpath</code-name-base>
+ <code-name-base>org.netbeans.modules.gradle</code-name-base>
<build-prerequisite/>
<compile-dependency/>
<run-dependency>
- <release-version>1</release-version>
- <specification-version>1.41.1</specification-version>
+ <release-version>2</release-version>
+ <specification-version>2.0</specification-version>
</run-dependency>
</dependency>
<dependency>
- <code-name-base>org.netbeans.modules.extexecution</code-name-base>
+ <code-name-base>org.netbeans.modules.gradle.java</code-name-base>
<build-prerequisite/>
<compile-dependency/>
<run-dependency>
- <release-version>2</release-version>
- <specification-version>1.45</specification-version>
+ <specification-version>1.17</specification-version>
</run-dependency>
</dependency>
<dependency>
@@ -118,6 +118,14 @@
<specification-version>1.3.1</specification-version>
</run-dependency>
</dependency>
+ <dependency>
+ <code-name-base>org.netbeans.modules.libs.gradle</code-name-base>
+ <compile-dependency/>
+ <run-dependency>
+ <release-version>8</release-version>
+ <specification-version>8.0.1</specification-version>
+ </run-dependency>
+ </dependency>
<dependency>
<code-name-base>org.netbeans.modules.projectapi</code-name-base>
<build-prerequisite/>
diff --git a/java/gradle.test/src/org/netbeans/modules/gradle/test/GradleTestProgressListener.java b/java/gradle.test/src/org/netbeans/modules/gradle/test/GradleTestProgressListener.java
index a45f9d20176..cacf2c8d43e 100644
--- a/java/gradle.test/src/org/netbeans/modules/gradle/test/GradleTestProgressListener.java
+++ b/java/gradle.test/src/org/netbeans/modules/gradle/test/GradleTestProgressListener.java
@@ -19,16 +19,17 @@
package org.netbeans.modules.gradle.test;
+import java.nio.file.Path;
import java.util.Arrays;
-import org.netbeans.modules.gradle.api.NbGradleProject;
import java.util.Collection;
-import org.netbeans.modules.gradle.spi.GradleProgressListenerProvider;
import java.util.EnumSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import javax.lang.model.element.ElementKind;
import org.gradle.tooling.Failure;
import org.gradle.tooling.events.OperationDescriptor;
import org.gradle.tooling.events.OperationType;
@@ -46,8 +47,15 @@ import org.gradle.tooling.events.test.TestProgressEvent;
import org.gradle.tooling.events.test.TestSkippedResult;
import org.gradle.tooling.events.test.TestStartEvent;
import org.gradle.tooling.events.test.TestSuccessResult;
+import org.netbeans.api.java.source.ClasspathInfo;
+import org.netbeans.api.java.source.ElementHandle;
+import org.netbeans.api.java.source.SourceUtils;
import org.netbeans.api.project.Project;
import org.netbeans.api.project.ProjectUtils;
+import org.netbeans.modules.gradle.api.NbGradleProject;
+import org.netbeans.modules.gradle.java.api.GradleJavaProject;
+import org.netbeans.modules.gradle.java.api.GradleJavaSourceSet.SourceType;
+import org.netbeans.modules.gradle.spi.GradleProgressListenerProvider;
import org.netbeans.modules.gsf.testrunner.api.CommonUtils;
import org.netbeans.modules.gsf.testrunner.api.CoreManager;
import org.netbeans.modules.gsf.testrunner.api.Report;
@@ -57,6 +65,8 @@ import org.netbeans.modules.gsf.testrunner.api.TestSuite;
import org.netbeans.modules.gsf.testrunner.api.Testcase;
import org.netbeans.modules.gsf.testrunner.api.Trouble;
import org.netbeans.spi.project.ProjectServiceProvider;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileUtil;
import org.openide.util.Lookup;
/**
@@ -68,8 +78,8 @@ public final class GradleTestProgressListener implements ProgressListener, Gradl
private final Project project;
private final Map<String, TestSession> sessions = new ConcurrentHashMap<>();
-
- private Map<TestSession, Map<String, Testcase>> runningTests = new ConcurrentHashMap<>();
+ private final Map<TestSession, Map<String, TestSuite>> runningSuites = new ConcurrentHashMap<>();
+ private final Map<TestSession, Map<String, Testcase>> runningTests = new ConcurrentHashMap<>();
public GradleTestProgressListener(Project project) {
this.project = project;
@@ -190,13 +200,21 @@ public final class GradleTestProgressListener implements ProgressListener, Gradl
TestSession session = sessions.get(getSessionKey(evt.getDescriptor()));
assert session != null;
TestOperationResult result = evt.getResult();
- TestSuite currentSuite = session.getCurrentSuite();
String suiteName = GradleTestSuite.suiteName(op);
- if (suiteName.equals(currentSuite.getName())) {
+ // In the NetBeans wording a testsuite is the class grouping multiple
+ // methods (testcase). In the gradle wording a suite can be nested, for
+ // example the hieararchy can be:
+ // - Gradle Test Executor <Number> started
+ // - Test class <Class> started
+ // => We flatten the list (suites are registered base on executed
+ // cases (see caseStart)
+ TestSuite testSuite = runningSuites.get(session).remove(suiteName);
+ if (testSuite != null) {
Report report = session.getReport(result.getEndTime() - result.getStartTime());
- session.finishSuite(currentSuite);
+ session.finishSuite(testSuite);
CoreManager manager = getManager();
if (manager != null) {
+ manager.displaySuiteRunning(session, testSuite);
manager.displayReport(session, report, true);
}
}
@@ -206,19 +224,21 @@ public final class GradleTestProgressListener implements ProgressListener, Gradl
TestSession session = sessions.get(getSessionKey(evt.getDescriptor()));
assert session != null;
assert op.getParent() != null;
- TestSuite currentSuite = session.getCurrentSuite();
- TestSuite newSuite = new GradleTestSuite(getSuiteOpDesc((JvmTestOperationDescriptor) op.getParent(), op.getClassName()));
- if ((currentSuite == null) || !currentSuite.equals(newSuite)) {
- session.addSuite(newSuite);
- CoreManager manager = getManager();
- if (manager != null) {
- manager.displaySuiteRunning(session, newSuite);
- }
+ String suiteName = GradleTestSuite.suiteName(op.getParent());
+ Map<String, TestSuite> sessionSuites = runningSuites.computeIfAbsent(session, s -> new ConcurrentHashMap<>());
+ TestSuite ts = sessionSuites.computeIfAbsent(suiteName, s -> {
+ TestSuite suite = new GradleTestSuite(getSuiteOpDesc((JvmTestOperationDescriptor) op.getParent(), op.getClassName()));
+ session.addSuite(suite);
+ return suite;
+ });
+ CoreManager manager = getManager();
+ if (manager != null && sessionSuites.size() == 1) {
+ manager.displaySuiteRunning(session, ts);
}
Testcase tc = new GradleTestcase(op, session);
- synchronized (this) {
+ synchronized (this) {
runningTests.get(session).put(getTestOpKey(op), tc);
- session.addTestCase(tc);
+ session.addTestCase(tc);
}
}
@@ -233,7 +253,7 @@ public final class GradleTestProgressListener implements ProgressListener, Gradl
TestOperationResult result = evt.getResult();
long time = result.getEndTime() - result.getStartTime();
tc.setTimeMillis(time);
- tc.setLocation(searchLocation(op.getClassName(), op.getMethodName(), null));
+ tc.setLocation(searchLocation(tc, op.getClassName(), op.getMethodName(), null));
if (result instanceof TestSuccessResult) {
tc.setStatus(Status.PASSED);
}
@@ -261,7 +281,7 @@ public final class GradleTestProgressListener implements ProgressListener, Gradl
stackTrace = desc.split("\\n");
trouble.setStackTrace(stackTrace);
}
- tc.setLocation(searchLocation(op.getClassName(), op.getMethodName(), stackTrace));
+ tc.setLocation(searchLocation(tc, op.getClassName(), op.getMethodName(), stackTrace));
tc.setTrouble(trouble);
}
@@ -322,7 +342,39 @@ public final class GradleTestProgressListener implements ProgressListener, Gradl
}
- private String searchLocation(String className, String methodName, String[] stackTrace) {
+ private String searchLocation(Testcase tc, String className, String methodName, String[] stackTrace) {
+ Map<ClasspathInfo, Path> classpathInfo = Map.of();
+ NbGradleProject nbGradleProject = tc.getSession()
+ .getProject()
+ .getLookup()
+ .lookup(NbGradleProject.class);
+ GradleJavaProject gradleJavaProject = nbGradleProject != null ? nbGradleProject.projectLookup(GradleJavaProject.class) : null;
+ if (gradleJavaProject != null) {
+ classpathInfo = gradleJavaProject
+ .getSourceSets()
+ .values()
+ .stream()
+ .flatMap(gradleJavaSourceSet -> gradleJavaSourceSet.getSourceDirs(SourceType.JAVA).stream())
+ .collect(
+ Collectors.toMap(
+ f -> ClasspathInfo.create(f),
+ f -> f.toPath()
+ )
+ );
+ }
+
+ String relativePath = null;
+ for (Map.Entry<ClasspathInfo, Path> ci : classpathInfo.entrySet()) {
+ FileObject fo = SourceUtils.getFile(ElementHandle.createTypeElementHandle(ElementKind.CLASS, className), ci.getKey());
+ if (fo != null) {
+ relativePath = ci.getValue().relativize(FileUtil.toFile(fo).toPath()).toString();
+ break;
+ }
+ }
+ if (relativePath != null) {
+ return relativePath;
+ }
+
StringBuilder ret = new StringBuilder(className.length() + methodName.length() + 10);
String fileName = null;
String line = null;
diff --git a/java/gradle.test/src/org/netbeans/modules/gradle/test/ui/nodes/GradleTestMethodNode.java b/java/gradle.test/src/org/netbeans/modules/gradle/test/ui/nodes/GradleTestMethodNode.java
index 4e11099aff0..13733d9445c 100644
--- a/java/gradle.test/src/org/netbeans/modules/gradle/test/ui/nodes/GradleTestMethodNode.java
+++ b/java/gradle.test/src/org/netbeans/modules/gradle/test/ui/nodes/GradleTestMethodNode.java
@@ -19,10 +19,6 @@
package org.netbeans.modules.gradle.test.ui.nodes;
-import org.netbeans.modules.gradle.api.execute.RunUtils;
-import org.netbeans.modules.gradle.java.api.output.Location;
-import org.netbeans.modules.gradle.test.ui.nodes.Bundle;
-import org.netbeans.modules.gradle.test.GradleTestcase;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -30,16 +26,21 @@ import javax.swing.Action;
import org.gradle.tooling.events.test.JvmTestOperationDescriptor;
import org.netbeans.api.extexecution.print.LineConvertors;
import org.netbeans.api.project.Project;
+import org.netbeans.modules.gradle.java.api.output.Location;
+import org.netbeans.modules.gradle.test.GradleTestcase;
import org.netbeans.modules.gsf.testrunner.api.Testcase;
import org.netbeans.modules.junit.ui.api.JUnitTestMethodNode;
import org.netbeans.spi.project.ActionProvider;
-import static org.netbeans.spi.project.SingleMethod.COMMAND_DEBUG_SINGLE_METHOD;
-import static org.netbeans.spi.project.SingleMethod.COMMAND_RUN_SINGLE_METHOD;
+import org.netbeans.spi.project.NestedClass;
+import org.netbeans.spi.project.SingleMethod;
import org.openide.filesystems.FileObject;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.openide.util.lookup.Lookups;
+import static org.netbeans.spi.project.SingleMethod.COMMAND_DEBUG_SINGLE_METHOD;
+import static org.netbeans.spi.project.SingleMethod.COMMAND_RUN_SINGLE_METHOD;
+
/**
*
* @author Laszlo Kishalmi
@@ -66,14 +67,39 @@ public final class GradleTestMethodNode extends JUnitTestMethodNode implements L
actions.add(getPreferredAction());
}
ActionProvider actionProvider = getProject().getLookup().lookup(ActionProvider.class);
- if ((actionProvider != null) && (testcase instanceof GradleTestcase)) {
+ if ((actionProvider != null) && testcase instanceof GradleTestcase gradleTestcase) {
List<String> supportedActions = Arrays.asList(actionProvider.getSupportedActions());
boolean runSupported = supportedActions.contains(COMMAND_RUN_SINGLE_METHOD);
boolean debugSupported = supportedActions.contains(COMMAND_DEBUG_SINGLE_METHOD);
- JvmTestOperationDescriptor op = ((GradleTestcase) testcase).getOperation();
- String tcName = op.getClassName() + '.' + op.getMethodName();
- Lookup nodeContext = Lookups.singleton(RunUtils.simpleReplaceTokenProvider("selectedMethod", tcName));
+ FileObject testFO = findFileObject(getTestLocation());
+ JvmTestOperationDescriptor op = gradleTestcase.getOperation();
+ // reporting adds signature to method name, this needs to be stripped away
+ String mName = op.getMethodName();
+ if(mName != null) {
+ mName = mName.replaceFirst("[^\\p{javaJavaIdentifierPart}].*", "");
+ }
+ String tcName = op.getClassName();
+
+ SingleMethod methodSpec;
+ if (tcName != null && tcName.contains("$")) {
+ String[] nestedSplit = tcName.split("\\$", 2);
+ String[] topLevelSplit = nestedSplit[0].split("\\.");
+ methodSpec = new SingleMethod(mName, new NestedClass(nestedSplit[1].replace("$", "."), topLevelSplit[topLevelSplit.length - 1], testFO));
+ } else {
+ if (tcName != null) {
+ String[] topLevelSplit = tcName.split("\\.");
+ if (!testFO.getName().equals(topLevelSplit[topLevelSplit.length - 1])) {
+ methodSpec = new SingleMethod(mName, new NestedClass("", topLevelSplit[topLevelSplit.length - 1], testFO));
+ } else {
+ methodSpec = new SingleMethod(testFO, mName);
+ }
+ } else {
+ methodSpec = new SingleMethod(testFO, mName);
+ }
+ }
+
+ Lookup nodeContext = Lookups.fixed(methodSpec);
if (runSupported) {
actions.add(new ReRunTestAction(actionProvider, nodeContext, COMMAND_RUN_SINGLE_METHOD, Bundle.LBL_RerunTest()));
@@ -83,7 +109,7 @@ public final class GradleTestMethodNode extends JUnitTestMethodNode implements L
actions.add(new ReRunTestAction(actionProvider, nodeContext, COMMAND_DEBUG_SINGLE_METHOD, Bundle.LBL_DebugTest()));
}
}
- return actions.toArray(new Action[0]);
+ return actions.toArray(Action[]::new);
}
@Override
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@netbeans.apache.org
For additional commands, e-mail: commits-help@netbeans.apache.org
For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists