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
