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 <[email protected]>
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: [email protected]
For additional commands, e-mail: [email protected]

For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists

Reply via email to