This is an automated email from the ASF dual-hosted git repository.
dbalek pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/netbeans.git
The following commit(s) were added to refs/heads/master by this push:
new 9ae9262 LSP: Various Test Explorer fixes. (#3224)
9ae9262 is described below
commit 9ae92629835220c79e8395bdd8da26355a4fb5f1
Author: Dusan Balek <[email protected]>
AuthorDate: Mon Oct 11 16:28:16 2021 +0200
LSP: Various Test Explorer fixes. (#3224)
* LSP: TestExplorer support for @Nested tests and various minor fixes.
* TestSession.finishSuite() added - required by the @Nested tests support.
---
.../support/actions/GroovyComputeTestMethods.java | 18 +-
.../gsf/testrunner/ui/TestMethodFinderImpl.java | 58 +++---
.../gsf/testrunner/ui/api/TestMethodFinder.java | 4 +-
ide/gsf.testrunner/apichanges.xml | 12 ++
ide/gsf.testrunner/manifest.mf | 2 +-
.../modules/gsf/testrunner/api/TestSession.java | 26 ++-
java/gradle.test/nbproject/project.xml | 2 +-
.../gradle/test/GradleTestProgressListener.java | 1 +
.../lsp/server/progress/TestProgressHandler.java | 67 +++---
.../java/lsp/server/protocol/TestSuiteInfo.java | 8 +-
.../lsp/server/protocol/WorkspaceServiceImpl.java | 32 +--
.../server/progress/TestProgressHandlerTest.java | 10 +-
.../java/lsp/server/protocol/ServerTest.java | 3 +-
java/java.lsp.server/vscode/src/extension.ts | 15 ++
java/java.lsp.server/vscode/src/protocol.ts | 2 +-
.../vscode/src/test/suite/extension.test.ts | 227 ++++++++++++---------
java/java.lsp.server/vscode/src/testAdapter.ts | 65 ++++--
java/junit.ant/nbproject/project.xml | 12 +-
.../modules/junit/ant/JUnitOutputReader.java | 4 +-
.../junit/ui/actions/TestClassInfoTask.java | 88 +++++---
java/maven.junit/nbproject/project.xml | 2 +-
.../maven/junit/JUnitOutputListenerProvider.java | 1 +
22 files changed, 416 insertions(+), 243 deletions(-)
diff --git
a/groovy/groovy.support/src/org/netbeans/modules/groovy/support/actions/GroovyComputeTestMethods.java
b/groovy/groovy.support/src/org/netbeans/modules/groovy/support/actions/GroovyComputeTestMethods.java
index 3425d19..6e63f6b 100644
---
a/groovy/groovy.support/src/org/netbeans/modules/groovy/support/actions/GroovyComputeTestMethods.java
+++
b/groovy/groovy.support/src/org/netbeans/modules/groovy/support/actions/GroovyComputeTestMethods.java
@@ -19,7 +19,9 @@
package org.netbeans.modules.groovy.support.actions;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.swing.text.Position;
import org.codehaus.groovy.ast.AnnotationNode;
@@ -62,8 +64,7 @@ public class GroovyComputeTestMethods implements
ComputeTestMethods {
return result;
}
for (ClassNode classNode : moduleNode.getClasses()) {
- ClassNode superClass = classNode.getSuperClass();
- if ("spock.lang.Specification".equals(superClass.getName())) {
+ if (isSpecification(classNode.getSuperClass())) {
int classStartLine = classNode.getLineNumber();
int classStartColumn = classNode.getColumnNumber();
int classOffset = classStartLine > 0 && classStartColumn > 0 ?
getOffset(text, classStartLine, classStartColumn) : 0;
@@ -95,6 +96,19 @@ public class GroovyComputeTestMethods implements
ComputeTestMethods {
return result;
}
+ private static boolean isSpecification(ClassNode classNode) {
+ Set<String> visited = new HashSet<>();
+ String name;
+ while (classNode != null && !visited.contains(name =
classNode.getName())) {
+ if ("spock.lang.Specification".equals(name)) {
+ return true;
+ }
+ visited.add(name);
+ classNode = classNode.getSuperClass();
+ }
+ return false;
+ }
+
private static boolean isTestSource(FileObject fo) {
ClassPath cp = ClassPath.getClassPath(fo, ClassPath.SOURCE);
if (cp != null) {
diff --git
a/ide/gsf.testrunner.ui/src/org/netbeans/modules/gsf/testrunner/ui/TestMethodFinderImpl.java
b/ide/gsf.testrunner.ui/src/org/netbeans/modules/gsf/testrunner/ui/TestMethodFinderImpl.java
index 1198c8d..53260a3 100644
---
a/ide/gsf.testrunner.ui/src/org/netbeans/modules/gsf/testrunner/ui/TestMethodFinderImpl.java
+++
b/ide/gsf.testrunner.ui/src/org/netbeans/modules/gsf/testrunner/ui/TestMethodFinderImpl.java
@@ -26,9 +26,13 @@ import java.io.PrintWriter;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.List;
+import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.BiConsumer;
+import java.util.logging.Logger;
import org.netbeans.api.editor.mimelookup.MimeLookup;
import org.netbeans.api.editor.mimelookup.MimeRegistration;
import org.netbeans.modules.gsf.testrunner.ui.api.TestMethodController;
@@ -52,7 +56,7 @@ public final class TestMethodFinderImpl extends
EmbeddingIndexer {
public static final String NAME = "tests"; // NOI18N
public static final int VERSION = 1;
- public static TestMethodFinderImpl INSTANCE = null;
+ public static final TestMethodFinderImpl INSTANCE = new
TestMethodFinderImpl();
private final WeakSet<BiConsumer<FileObject,
Collection<TestMethodController.TestMethod>>> listeners = new WeakSet<>();
@@ -76,6 +80,7 @@ public final class TestMethodFinderImpl extends
EmbeddingIndexer {
public void addListener(BiConsumer<FileObject,
Collection<TestMethodController.TestMethod>> listener) {
synchronized(listeners) {
listeners.putIfAbsent(listener);
+
Logger.getLogger(TestMethodFinderImpl.class.getName()).info("Listener added: "
+ listener);
}
}
@@ -87,29 +92,37 @@ public final class TestMethodFinderImpl extends
EmbeddingIndexer {
output.delete();
}
} else {
+ Map<String, List<TestMethodController.TestMethod>> class2methods =
new LinkedHashMap<>();
+ Map<String, Integer> class2offsets = new HashMap<>();
+ for (TestMethodController.TestMethod method : methods) {
+ String className = method.getTestClassName();
+ if (method.getTestClassPosition() != null) {
+ class2offsets.putIfAbsent(className,
method.getTestClassPosition().getOffset());
+ }
+ class2methods.computeIfAbsent(className, name -> new
ArrayList<>()).add(method);
+ }
output.getParentFile().mkdirs();
- boolean printHeader = true;
try (PrintWriter pw = new PrintWriter(new OutputStreamWriter(new
FileOutputStream(output), "UTF-8"))) {
- for (TestMethodController.TestMethod method : methods) {
- if (printHeader) {
- pw.print("url: "); //NOI18N
- pw.println(url.toString());
- pw.print("class: "); //NOI18N
- pw.print(method.getTestClassName());
- if (method.getTestClassPosition() != null) {
- pw.print(':'); //NOI18N
-
pw.println(method.getTestClassPosition().getOffset());
- } else {
- pw.println();
- }
- printHeader = false;
+ pw.print("url: "); //NOI18N
+ pw.println(url.toString());
+ for (Map.Entry<String, List<TestMethodController.TestMethod>>
entry : class2methods.entrySet()) {
+ pw.print("class: "); //NOI18N
+ pw.print(entry.getKey());
+ Integer offset = class2offsets.get(entry.getKey());
+ if (offset != null) {
+ pw.print(':'); //NOI18N
+ pw.println(offset);
+ } else {
+ pw.println();
+ }
+ for (TestMethodController.TestMethod method :
entry.getValue()) {
+ pw.print("method: "); //NOI18N
+ pw.print(method.method().getMethodName());
+ pw.print(':'); //NOI18N
+ pw.print(method.start().getOffset());
+ pw.print('-'); //NOI18N
+ pw.println(method.end().getOffset());
}
- pw.print("method: "); //NOI18N
- pw.print(method.method().getMethodName());
- pw.print(':'); //NOI18N
- pw.print(method.start().getOffset());
- pw.print('-'); //NOI18N
- pw.println(method.end().getOffset());
}
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
@@ -122,9 +135,6 @@ public final class TestMethodFinderImpl extends
EmbeddingIndexer {
@Override
public EmbeddingIndexer createIndexer(Indexable indexable, Snapshot
snapshot) {
- if (INSTANCE == null) {
- INSTANCE = new TestMethodFinderImpl();
- }
return INSTANCE;
}
diff --git
a/ide/gsf.testrunner.ui/src/org/netbeans/modules/gsf/testrunner/ui/api/TestMethodFinder.java
b/ide/gsf.testrunner.ui/src/org/netbeans/modules/gsf/testrunner/ui/api/TestMethodFinder.java
index 22ae987..0c334c9 100644
---
a/ide/gsf.testrunner.ui/src/org/netbeans/modules/gsf/testrunner/ui/api/TestMethodFinder.java
+++
b/ide/gsf.testrunner.ui/src/org/netbeans/modules/gsf/testrunner/ui/api/TestMethodFinder.java
@@ -55,9 +55,7 @@ public final class TestMethodFinder {
* @since 1.27
*/
public static Map<FileObject, Collection<TestMethodController.TestMethod>>
findTestMethods(Iterable<FileObject> testRoots, BiConsumer<FileObject,
Collection<TestMethodController.TestMethod>> listener) {
- if (TestMethodFinderImpl.INSTANCE != null) {
- TestMethodFinderImpl.INSTANCE.addListener(listener);
- }
+ TestMethodFinderImpl.INSTANCE.addListener(listener);
Map<FileObject, Collection<TestMethodController.TestMethod>>
file2TestMethods = new HashMap<>();
for (FileObject testRoot : testRoots) {
try {
diff --git a/ide/gsf.testrunner/apichanges.xml
b/ide/gsf.testrunner/apichanges.xml
index 1a49bed..34f2252 100644
--- a/ide/gsf.testrunner/apichanges.xml
+++ b/ide/gsf.testrunner/apichanges.xml
@@ -52,6 +52,18 @@
<!-- ACTUAL CHANGES BEGIN HERE: -->
<changes>
+ <change id="TestSession_finishSuite">
+ <api name="CommonTestrunnerAPI"/>
+ <summary>TestSession.finishSuite method added</summary>
+ <version major="2" minor="26"/>
+ <date day="8" month="10" year="2021"/>
+ <author login="dbalek"/>
+ <compatibility addition="yes"/>
+ <description>
+ TestSession.finishSuite() method added.
+ </description>
+ <class package="org.netbeans.modules.gsf.testrunner.api"
name="TestSession"/>
+ </change>
<change id="CommonTestrunnerAPI_Public">
<api name="CommonTestrunnerAPI"/>
<summary>Common Test Runner API made public</summary>
diff --git a/ide/gsf.testrunner/manifest.mf b/ide/gsf.testrunner/manifest.mf
index 03f8517..585b10f 100644
--- a/ide/gsf.testrunner/manifest.mf
+++ b/ide/gsf.testrunner/manifest.mf
@@ -3,5 +3,5 @@ AutoUpdate-Show-In-Client: false
OpenIDE-Module: org.netbeans.modules.gsf.testrunner/2
OpenIDE-Module-Localizing-Bundle:
org/netbeans/modules/gsf/testrunner/Bundle.properties
OpenIDE-Module-Layer: org/netbeans/modules/gsf/testrunner/layer.xml
-OpenIDE-Module-Specification-Version: 2.25
+OpenIDE-Module-Specification-Version: 2.26
diff --git
a/ide/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/api/TestSession.java
b/ide/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/api/TestSession.java
index b850136..a630e7b 100644
---
a/ide/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/api/TestSession.java
+++
b/ide/gsf.testrunner/src/org/netbeans/modules/gsf/testrunner/api/TestSession.java
@@ -22,6 +22,7 @@ import java.lang.ref.WeakReference;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
+import java.util.Stack;
import org.netbeans.api.extexecution.print.LineConvertors.FileLocator;
import org.netbeans.api.project.FileOwnerQuery;
import org.netbeans.api.project.Project;
@@ -62,6 +63,10 @@ public class TestSession {
*/
private final List<TestSuite> testSuites = new ArrayList<TestSuite>();
/**
+ * Current suite indexes.
+ */
+ private final Stack<Integer> suiteIdxs = new Stack<Integer>();
+ /**
* Holds output for testcases. Since a testcase is created only after
* a test finishes, the output of that testcase needs to be associated
* with it after it has been created.
@@ -176,7 +181,22 @@ public class TestSession {
output.clear();
}
}
- testSuites.add(suite);
+ synchronized (this) {
+ suiteIdxs.push(testSuites.size());
+ testSuites.add(suite);
+ }
+ }
+
+ /**
+ * Marks the currently running test suite as finished.
+ *
+ * @param suite the suite to mark as finished
+ * @since 2.26
+ */
+ public synchronized void finishSuite(TestSuite suite) {
+ if (!suiteIdxs.isEmpty() && suite == getCurrentSuite()) {
+ suiteIdxs.pop();
+ }
}
/**
@@ -204,8 +224,8 @@ public class TestSession {
* @return the suite that is currently running or <code>null</code> if
* no suite is running.
*/
- public TestSuite getCurrentSuite() {
- return testSuites.isEmpty() ? null : testSuites.get(testSuites.size()
-1);
+ public synchronized TestSuite getCurrentSuite() {
+ return testSuites.isEmpty() ? null :
testSuites.get(suiteIdxs.isEmpty() ? testSuites.size() -1 : suiteIdxs.peek());
}
/**
diff --git a/java/gradle.test/nbproject/project.xml
b/java/gradle.test/nbproject/project.xml
index 5057501..2c90eb7 100644
--- a/java/gradle.test/nbproject/project.xml
+++ b/java/gradle.test/nbproject/project.xml
@@ -74,7 +74,7 @@
<compile-dependency/>
<run-dependency>
<release-version>2</release-version>
- <specification-version>1.42.1</specification-version>
+ <specification-version>2.26</specification-version>
</run-dependency>
</dependency>
<dependency>
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 11d1614..97a215c 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
@@ -177,6 +177,7 @@ public final class GradleTestProgressListener implements
ProgressListener, Gradl
String suiteName = GradleTestSuite.suiteName(op);
if (suiteName.equals(currentSuite.getName())) {
Report report = session.getReport(result.getEndTime() -
result.getStartTime());
+ session.finishSuite(currentSuite);
CoreManager manager = getManager();
if (manager != null) {
manager.displayReport(session, report, true);
diff --git
a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/progress/TestProgressHandler.java
b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/progress/TestProgressHandler.java
index be7b83d..470293d 100644
---
a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/progress/TestProgressHandler.java
+++
b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/progress/TestProgressHandler.java
@@ -28,6 +28,7 @@ import org.eclipse.lsp4j.debug.OutputEventArguments;
import org.eclipse.lsp4j.debug.services.IDebugProtocolClient;
import org.netbeans.api.extexecution.print.LineConvertors;
import org.netbeans.modules.gsf.testrunner.api.Report;
+import org.netbeans.modules.gsf.testrunner.api.Status;
import org.netbeans.modules.gsf.testrunner.api.TestSession;
import org.netbeans.modules.gsf.testrunner.api.TestSuite;
import org.netbeans.modules.gsf.testrunner.api.Testcase;
@@ -63,7 +64,7 @@ public final class TestProgressHandler implements
TestResultDisplayHandler.Spi<T
public void displayOutput(TestProgressHandler token, String text, boolean
error) {
if (text != null) {
OutputEventArguments output = new OutputEventArguments();
- output.setOutput(text.endsWith("\n") ? text : text + "\n");
+ output.setOutput(text.trim() + "\n");
debugClient.output(output);
}
}
@@ -90,23 +91,7 @@ public final class TestProgressHandler implements
TestResultDisplayHandler.Spi<T
name = name.substring(0, idx);
}
String id = className + ':' + name;
- String status;
- switch (test.getStatus()) {
- case PASSED:
- status = TestSuiteInfo.State.Passed;
- break;
- case ERROR:
- status = TestSuiteInfo.State.Errored;
- break;
- case FAILED:
- status = TestSuiteInfo.State.Failed;
- break;
- case SKIPPED:
- status = TestSuiteInfo.State.Skipped;
- break;
- default:
- throw new IllegalStateException("Unexpected testcase
status: " + test.getStatus());
- }
+ String state = statusToState(test.getStatus());
List<String> stackTrace = test.getTrouble() != null ?
Arrays.asList(test.getTrouble().getStackTrace()) : null;
String location = test.getLocation();
FileObject fo = location != null ?
fileLocations.computeIfAbsent(location, loc -> {
@@ -119,27 +104,16 @@ public final class TestProgressHandler implements
TestResultDisplayHandler.Spi<T
}) : null;
TestSuiteInfo.TestCaseInfo info = testCases.get(id);
if (info != null) {
- updateState(info, status);
+ updateState(info, state);
} else {
- info = new TestSuiteInfo.TestCaseInfo(id, name, fo != null ?
Utils.toUri(fo) : null, null, status, stackTrace);
+ info = new TestSuiteInfo.TestCaseInfo(id, name, fo != null ?
Utils.toUri(fo) : null, null, state, stackTrace);
testCases.put(id, info);
}
}
- String status;
- switch (report.getStatus()) {
- case PASSED:
- case FAILED:
- status = TestSuiteInfo.State.Completed;
- break;
- case ERROR:
- status = TestSuiteInfo.State.Errored;
- break;
- default:
- throw new IllegalStateException("Unexpected testsuite status:
" + report.getStatus());
- }
+ String state = statusToState(report.getStatus());
FileObject fo = fileLocations.size() == 1 ?
fileLocations.values().iterator().next() : null;
lspClient.notifyTestProgress(new TestProgressParams(uri, new
TestSuiteInfo(report.getSuiteClassName(),
- fo != null ? Utils.toUri(fo) : null, null, status, new
ArrayList<>(testCases.values()))));
+ fo != null ? Utils.toUri(fo) : null, null, state, new
ArrayList<>(testCases.values()))));
}
@Override
@@ -155,6 +129,26 @@ public final class TestProgressHandler implements
TestResultDisplayHandler.Spi<T
return 0;
}
+ private String statusToState(Status status) {
+ switch (status) {
+ case PASSED:
+ case PASSEDWITHERRORS:
+ return TestSuiteInfo.State.Passed;
+ case ERROR:
+ return TestSuiteInfo.State.Errored;
+ case FAILED:
+ return TestSuiteInfo.State.Failed;
+ case SKIPPED:
+ case ABORTED:
+ case IGNORED:
+ return TestSuiteInfo.State.Skipped;
+ case PENDING:
+ return TestSuiteInfo.State.Started;
+ default:
+ throw new IllegalStateException("Unexpected testsuite status:
" + status);
+ }
+ }
+
private void updateState(TestSuiteInfo.TestCaseInfo info, String state) {
switch (state) {
case TestSuiteInfo.State.Errored:
@@ -166,7 +160,12 @@ public final class TestProgressHandler implements
TestResultDisplayHandler.Spi<T
}
break;
case TestSuiteInfo.State.Passed:
- if (TestSuiteInfo.State.Skipped.equals(info.getState())) {
+ if (TestSuiteInfo.State.Skipped.equals(info.getState()) ||
TestSuiteInfo.State.Started.equals(info.getState())) {
+ info.setState(state);
+ }
+ break;
+ case TestSuiteInfo.State.Skipped:
+ if (TestSuiteInfo.State.Started.equals(info.getState())) {
info.setState(state);
}
break;
diff --git
a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/TestSuiteInfo.java
b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/TestSuiteInfo.java
index 36ea81b..6258caf 100644
---
a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/TestSuiteInfo.java
+++
b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/TestSuiteInfo.java
@@ -51,7 +51,7 @@ public final class TestSuiteInfo {
/**
* The state of the tests suite. Can be one of the following values:
- * "loaded" | "started" | "completed" | "errored"
+ * "loaded" | "started" | "passed" | "failed" | "skipped" | "errored"
*/
@NonNull
private String state;
@@ -125,7 +125,7 @@ public final class TestSuiteInfo {
/**
* The state of the tests suite. Can be one of the following values:
- * "loaded" | "started" | "completed" | "errored"
+ * "loaded" | "started" | "passed" | "failed" | "skipped" | "errored"
*/
@Pure
@NonNull
@@ -135,7 +135,7 @@ public final class TestSuiteInfo {
/**
* The state of the tests suite. Can be one of the following values:
- * "loaded" | "started" | "completed" | "errored"
+ * "loaded" | "started" | "passed" | "failed" | "skipped" | "errored"
*/
public void setState(@NonNull final String state) {
this.state = Preconditions.checkNotNull(state, "state");
@@ -434,8 +434,6 @@ public final class TestSuiteInfo {
public static final String Started = "started";
- public static final String Completed = "completed";
-
public static final String Passed = "passed";
public static final String Failed = "failed";
diff --git
a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceServiceImpl.java
b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceServiceImpl.java
index 4ab6a64..2942003 100644
---
a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceServiceImpl.java
+++
b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceServiceImpl.java
@@ -43,6 +43,7 @@ import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Supplier;
+import java.util.logging.Logger;
import java.util.stream.Collectors;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
@@ -201,38 +202,39 @@ public final class WorkspaceServiceImpl implements
WorkspaceService, LanguageCli
JavaSource js =
JavaSource.create(ClasspathInfo.create(ClassPath.EMPTY, ClassPath.EMPTY,
ClassPath.EMPTY));
try {
js.runWhenScanFinished(controller -> {
- BiFunction<FileObject,
Collection<TestMethodController.TestMethod>, TestSuiteInfo> f = (fo, methods)
-> {
- List<TestSuiteInfo.TestCaseInfo> tests = new
ArrayList<>(methods.size());
+ BiFunction<FileObject,
Collection<TestMethodController.TestMethod>, Collection<TestSuiteInfo>> f =
(fo, methods) -> {
String url = Utils.toUri(fo);
- String testClassName = null;
- Range testClassRange = null;
+ Map<String, TestSuiteInfo> suite2infos = new
LinkedHashMap<>();
for (TestMethodController.TestMethod
testMethod : methods) {
- if (testClassName == null) {
- testClassName =
testMethod.getTestClassName();
- }
- if (testClassRange == null &&
testMethod.getTestClassPosition() != null) {
- Position pos =
Utils.createPosition(fo, testMethod.getTestClassPosition().getOffset());
- testClassRange = new Range(pos, pos);
- }
+ TestSuiteInfo suite =
suite2infos.computeIfAbsent(testMethod.getTestClassName(), name -> {
+ Position pos =
testMethod.getTestClassPosition() != null ? Utils.createPosition(fo,
testMethod.getTestClassPosition().getOffset()) : null;
+ return new TestSuiteInfo(name, url,
pos != null ? new Range(pos, pos) : null, TestSuiteInfo.State.Loaded, new
ArrayList<>());
+ });
String id = testMethod.getTestClassName()
+ ':' + testMethod.method().getMethodName();
Position startPos = testMethod.start() !=
null ? Utils.createPosition(fo, testMethod.start().getOffset()) : null;
Position endPos = testMethod.end() != null
? Utils.createPosition(fo, testMethod.end().getOffset()) : startPos;
Range range = startPos != null ? new
Range(startPos, endPos) : null;
- tests.add(new
TestSuiteInfo.TestCaseInfo(id, testMethod.method().getMethodName(), url, range,
TestSuiteInfo.State.Loaded, null));
+ suite.getTests().add(new
TestSuiteInfo.TestCaseInfo(id, testMethod.method().getMethodName(), url, range,
TestSuiteInfo.State.Loaded, null));
}
- return new TestSuiteInfo(testClassName, url,
testClassRange, TestSuiteInfo.State.Loaded, tests);
+ return suite2infos.values();
};
testMethodsListener.compareAndSet(null, (fo,
methods) -> {
+
Logger.getLogger(WorkspaceServiceImpl.class.getName()).info("FileObject
reindexed: " + fo.getPath());
try {
- client.notifyTestProgress(new
TestProgressParams(Utils.toUri(fo), f.apply(fo, methods)));
+ for (TestSuiteInfo testSuiteInfo :
f.apply(fo, methods)) {
+ client.notifyTestProgress(new
TestProgressParams(Utils.toUri(fo), testSuiteInfo));
+ }
} catch (Exception e) {
+
Logger.getLogger(WorkspaceServiceImpl.class.getName()).severe(e.getMessage());
+ Exceptions.printStackTrace(e);
testMethodsListener.set(null);
}
});
+
Logger.getLogger(WorkspaceServiceImpl.class.getName()).info("Attaching
listener: " + testMethodsListener.get());
Map<FileObject,
Collection<TestMethodController.TestMethod>> testMethods =
TestMethodFinder.findTestMethods(testRoots, testMethodsListener.get());
Collection<TestSuiteInfo> suites = new
ArrayList<>(testMethods.size());
for (Entry<FileObject,
Collection<TestMethodController.TestMethod>> entry : testMethods.entrySet()) {
- suites.add(f.apply(entry.getKey(),
entry.getValue()));
+ suites.addAll(f.apply(entry.getKey(),
entry.getValue()));
}
future.complete(suites);
}, true);
diff --git
a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/progress/TestProgressHandlerTest.java
b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/progress/TestProgressHandlerTest.java
index c325b59..a80d125 100644
---
a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/progress/TestProgressHandlerTest.java
+++
b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/progress/TestProgressHandlerTest.java
@@ -121,17 +121,17 @@ public class TestProgressHandlerTest extends NbTestCase {
assertEquals(fo.toURI().toString(), msgs.get(1).getUri());
suite = msgs.get(1).getSuite();
assertEquals("TestSuiteName", suite.getName());
- assertEquals(TestSuiteInfo.State.Completed, suite.getState());
+ assertEquals(TestSuiteInfo.State.Failed, suite.getState());
assertEquals(2, suite.getTests().size());
TestSuiteInfo.TestCaseInfo testCase = suite.getTests().get(0);
- assertEquals("TestSuiteName:test1", testCase.getId());
- assertEquals("test1", testCase.getName());
+ assertEquals("TestSuiteName:TestSuiteName.test1", testCase.getId());
+ assertEquals("TestSuiteName.test1", testCase.getName());
assertEquals(fo.toURI().toString(), testCase.getFile());
assertEquals(TestSuiteInfo.State.Passed, testCase.getState());
assertNull(testCase.getStackTrace());
testCase = suite.getTests().get(1);
- assertEquals("TestSuiteName:test2", testCase.getId());
- assertEquals("test2", testCase.getName());
+ assertEquals("TestSuiteName:TestSuiteName.test2", testCase.getId());
+ assertEquals("TestSuiteName.test2", testCase.getName());
assertEquals(fo.toURI().toString(), testCase.getFile());
assertEquals(TestSuiteInfo.State.Failed, testCase.getState());
assertNotNull(testCase.getStackTrace());
diff --git
a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java
b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java
index e891ddc..9e906d7 100644
---
a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java
+++
b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java
@@ -3489,7 +3489,8 @@ public class ServerTest extends NbTestCase {
" @Override\n" +
" public String toString() {\n" +
" StringBuilder sb = new StringBuilder();\n" +
- " sb.append(\"Test{f1=\").append(f1);\n" +
+ " sb.append(\"Test{\");\n" +
+ " sb.append(\"f1=\").append(f1);\n" +
" sb.append('}');\n" +
" return sb.toString();\n" +
" }\n",
diff --git a/java/java.lsp.server/vscode/src/extension.ts
b/java/java.lsp.server/vscode/src/extension.ts
index 871a722..4fb71bb 100644
--- a/java/java.lsp.server/vscode/src/extension.ts
+++ b/java/java.lsp.server/vscode/src/extension.ts
@@ -174,6 +174,8 @@ export function activate(context: ExtensionContext):
VSNetBeansAPI {
});
//register debugger:
+ let debugTrackerFactory =new NetBeansDebugAdapterTrackerFactory();
+
context.subscriptions.push(vscode.debug.registerDebugAdapterTrackerFactory('java8+',
debugTrackerFactory));
let configInitialProvider = new NetBeansConfigurationInitialProvider();
context.subscriptions.push(vscode.debug.registerDebugConfigurationProvider('java8+',
configInitialProvider, vscode.DebugConfigurationProviderTriggerKind.Initial));
let configDynamicProvider = new
NetBeansConfigurationDynamicProvider(context);
@@ -712,6 +714,19 @@ export function deactivate(): Thenable<void> {
return stopClient(client);
}
+class NetBeansDebugAdapterTrackerFactory implements
vscode.DebugAdapterTrackerFactory {
+
+ createDebugAdapterTracker(_session: vscode.DebugSession):
vscode.ProviderResult<vscode.DebugAdapterTracker> {
+ return {
+ onDidSendMessage(message: any): void {
+ if (testAdapter && message.type === 'event' && message.event
=== 'output') {
+ testAdapter.testOutput(message.body.output);
+ }
+ }
+ }
+ }
+}
+
class NetBeansDebugAdapterDescriptionFactory implements
vscode.DebugAdapterDescriptorFactory {
createDebugAdapterDescriptor(_session: vscode.DebugSession, _executable:
vscode.DebugAdapterExecutable | undefined):
vscode.ProviderResult<vscode.DebugAdapterDescriptor> {
diff --git a/java/java.lsp.server/vscode/src/protocol.ts
b/java/java.lsp.server/vscode/src/protocol.ts
index c4bcaac..64b3da2 100644
--- a/java/java.lsp.server/vscode/src/protocol.ts
+++ b/java/java.lsp.server/vscode/src/protocol.ts
@@ -83,7 +83,7 @@ export interface TestSuite {
name: string;
file?: string;
range?: Range;
- state: 'loaded' | 'started' | 'completed' | 'errored';
+ state: 'loaded' | 'started' | 'passed' | 'failed' | 'skipped' | 'errored';
tests?: TestCase[];
}
diff --git a/java/java.lsp.server/vscode/src/test/suite/extension.test.ts
b/java/java.lsp.server/vscode/src/test/suite/extension.test.ts
index e757b5b..562dacc 100644
--- a/java/java.lsp.server/vscode/src/test/suite/extension.test.ts
+++ b/java/java.lsp.server/vscode/src/test/suite/extension.test.ts
@@ -71,32 +71,7 @@ suite('Extension Test Suite', () => {
async function demo(where: number) {
let folder: string = assertWorkspace();
- await fs.promises.writeFile(path.join(folder, 'pom.xml'), `
-<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <groupId>org.netbeans.demo.vscode.t1</groupId>
- <artifactId>basicapp</artifactId>
- <version>1.0</version>
- <properties>
- <maven.compiler.source>1.8</maven.compiler.source>
- <maven.compiler.target>1.8</maven.compiler.target>
- </properties>
-</project>
- `);
-
- let pkg = path.join(folder, 'src', 'main', 'java', 'pkg');
- let mainJava = path.join(pkg, 'Main.java');
-
- await fs.promises.mkdir(pkg, { recursive: true });
-
- await fs.promises.writeFile(mainJava, `
-package pkg;
-class Main {
- public static void main(String... args) {
- System.out.println("Hello World!");
- }
-}
- `);
+ await prepareProject(folder);
vscode.workspace.saveAll();
@@ -131,42 +106,14 @@ class Main {
async function mavenTerminateWithoutDebugger() {
let folder: string = assertWorkspace();
- await fs.promises.writeFile(path.join(folder, 'pom.xml'), `
- <project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <groupId>org.netbeans.demo.vscode.t1</groupId>
- <artifactId>basicapp</artifactId>
- <version>1.0</version>
- <properties>
- <maven.compiler.source>1.8</maven.compiler.source>
- <maven.compiler.target>1.8</maven.compiler.target>
- </properties>
- </project>
- `);
-
- let pkg = path.join(folder, 'src', 'main', 'java', 'pkg');
- let mainJava = path.join(pkg, 'Main.java');
-
- await fs.promises.mkdir(pkg, { recursive: true });
-
- await fs.promises.writeFile(mainJava, `
- package pkg;
- class Main {
- public static void main(String... args) throws Exception {
- System.out.println("Endless wait...");
- while (true) {
- Thread.sleep(1000);
- }
- }
- }
- `);
+ await prepareProject(folder);
+
vscode.workspace.saveAll();
- let u : Uri = vscode.Uri.file(mainJava);
+ let u : Uri = vscode.Uri.file(path.join(folder, 'src', 'main', 'java',
'pkg', 'Main.java'));
let doc : TextDocument = await vscode.workspace.openTextDocument(u);
let e : TextEditor = await vscode.window.showTextDocument(doc);
try {
- let terminated = false;
let r = new Promise((resolve, reject) => {
function waitUserApplication(cnt : number, running: boolean,
cb : () => void) {
ps.lookup({
@@ -210,34 +157,7 @@ class Main {
async function getProjectInfo() {
let folder: string = assertWorkspace();
- await fs.promises.writeFile(path.join(folder, 'pom.xml'), `
-<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <groupId>org.netbeans.demo.vscode.t1</groupId>
- <artifactId>basicapp</artifactId>
- <version>1.0</version>
- <properties>
- <maven.compiler.source>1.8</maven.compiler.source>
- <maven.compiler.target>1.8</maven.compiler.target>
- </properties>
-</project>
- `);
-
- let pkg = path.join(folder, 'src', 'main', 'java', 'pkg');
- let resources = path.join(folder, 'src', 'main', 'resources');
- let mainJava = path.join(pkg, 'Main.java');
-
- await fs.promises.mkdir(pkg, { recursive: true });
- await fs.promises.mkdir(resources, { recursive: true });
-
- await fs.promises.writeFile(mainJava, `
-package pkg;
-class Main {
- public static void main(String... args) {
- System.out.println("Hello World!");
- }
-}
- `);
+ await prepareProject(folder);
vscode.workspace.saveAll();
@@ -245,30 +165,33 @@ class Main {
console.log("Test: get project java source roots");
let res: any = await
vscode.commands.executeCommand("java.get.project.source.roots",
Uri.file(folder).toString());
console.log(`Test: get project java source roots finished with
${res}`);
- assert.ok(res, "No java source root rertuned");
- assert.strictEqual(res.length, 1, `Invalid number of java roots
returned`);
- assert.strictEqual(res[0], path.join('file:', folder, 'src',
'main', 'java') + path.sep, `Invalid java source root returned`);
+ assert.ok(res, "No java source root returned");
+ assert.strictEqual(res.length, 2, `Invalid number of java roots
returned`);
+ assert.strictEqual(res[0], path.join('file:', folder, 'src',
'main', 'java') + path.sep, `Invalid java main source root returned`);
+ assert.strictEqual(res[1], path.join('file:', folder, 'src',
'test', 'java') + path.sep, `Invalid java test source root returned`);
console.log("Test: get project resource roots");
res = await
vscode.commands.executeCommand("java.get.project.source.roots",
Uri.file(folder).toString(), 'resources');
console.log(`Test: get project resource roots finished with
${res}`);
assert.ok(res, "No resource root returned");
assert.strictEqual(res.length, 1, `Invalid number of resource
roots returned`);
- assert.strictEqual(res[0], path.join('file:', resources) +
path.sep, `Invalid resource root returned`);
+ assert.strictEqual(res[0], path.join('file:', folder, 'src',
'main', 'resources') + path.sep, `Invalid resource root returned`);
console.log("Test: get project compile classpath");
res = await
vscode.commands.executeCommand("java.get.project.classpath",
Uri.file(folder).toString());
console.log(`Test: get project compile classpath finished with
${res}`);
assert.ok(res, "No compile classpath returned");
- assert.strictEqual(res.length, 1, `Invalid number of compile
classpath roots returned`);
- assert.strictEqual(res[0], path.join('file:', folder, 'target',
'classes') + path.sep, `Invalid compile classpath root returned`);
+ assert.strictEqual(res.length, 9, `Invalid number of compile
classpath roots returned`);
+ assert.ok(res.find((item: any) => item === path.join('file:',
folder, 'target', 'classes') + path.sep, `Invalid compile classpath root
returned`));
console.log("Test: get project source classpath");
res = await
vscode.commands.executeCommand("java.get.project.classpath",
Uri.file(folder).toString(), 'SOURCE');
console.log(`Test: get project source classpath finished with
${res}`);
assert.ok(res, "No source classpath returned");
- assert.strictEqual(res.length, 1, `Invalid number of source
classpath roots returned`);
- assert.strictEqual(res[0], path.join('file:', folder, 'src',
'main', 'java') + path.sep, `Invalid source classpath root returned`);
+ assert.strictEqual(res.length, 3, `Invalid number of source
classpath roots returned`);
+ assert.ok(res.find((item: any) => item === path.join('file:',
folder, 'src', 'main', 'java') + path.sep, `Invalid source classpath root
returned`));
+ assert.ok(res.find((item: any) => item === path.join('file:',
folder, 'src', 'main', 'resources') + path.sep, `Invalid source classpath root
returned`));
+ assert.ok(res.find((item: any) => item === path.join('file:',
folder, 'src', 'test', 'java') + path.sep, `Invalid source classpath root
returned`));
console.log("Test: get project boot classpath");
res = await
vscode.commands.executeCommand("java.get.project.classpath",
Uri.file(folder).toString(), 'BOOT');
@@ -302,6 +225,37 @@ class Main {
test("Get project sources, classpath, and packages", async() =>
getProjectInfo());
+ async function testExplorerTests() {
+ let folder: string = assertWorkspace();
+
+ await prepareProject(folder);
+
+ vscode.workspace.saveAll();
+
+ try {
+ console.log("Test: load workspace tests");
+ let tests: any = await
vscode.commands.executeCommand("java.load.workspace.tests",
Uri.file(folder).toString());
+ console.log(`Test: load workspace tests finished with ${tests}`);
+ assert.ok(tests, "No tests returned for workspace");
+ assert.strictEqual(tests.length, 2, `Invalid number of test suites
returned`);
+ assert.strictEqual(tests[0].name, 'pkg.MainTest', `Invalid test
suite name returned`);
+ assert.strictEqual(tests[0].tests.length, 1, `Invalid number of
tests in suite returned`);
+ assert.strictEqual(tests[0].tests[0].name, 'testGetName', `Invalid
test name returned`);
+ assert.strictEqual(tests[1].name, 'pkg.MainTest$NestedTest',
`Invalid test suite name returned`);
+ assert.strictEqual(tests[1].tests.length, 1, `Invalid number of
tests in suite returned`);
+ assert.strictEqual(tests[1].tests[0].name, 'testTrue', `Invalid
test name returned`);
+
+ console.log("Test: run all workspace tests");
+ const workspaceFolder = (vscode.workspace.workspaceFolders!)[0];
+ await vscode.commands.executeCommand('java.run.test',
workspaceFolder.uri.toString());
+ console.log(`Test: run all workspace tests finished`);
+ } catch (error) {
+ dumpJava();
+ throw error;
+ }
+ }
+
+ test("Test Explorer tests", async() => testExplorerTests());
});
function assertWorkspace(): string {
@@ -313,6 +267,93 @@ function assertWorkspace(): string {
return folder;
}
+async function prepareProject(folder: string) {
+ await fs.promises.writeFile(path.join(folder, 'pom.xml'), `
+<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
+<modelVersion>4.0.0</modelVersion>
+<groupId>org.netbeans.demo.vscode.t1</groupId>
+<artifactId>basicapp</artifactId>
+<version>1.0</version>
+<properties>
+ <maven.compiler.source>1.8</maven.compiler.source>
+ <maven.compiler.target>1.8</maven.compiler.target>
+</properties>
+<build>
+<plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.22.0</version>
+ </plugin>
+</plugins>
+</build>
+<dependencies>
+<dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter-api</artifactId>
+ <version>5.3.1</version>
+ <scope>test</scope>
+</dependency>
+<dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter-params</artifactId>
+ <version>5.3.1</version>
+ <scope>test</scope>
+</dependency>
+<dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter-engine</artifactId>
+ <version>5.3.1</version>
+ <scope>test</scope>
+</dependency>
+</dependencies>
+</project>
+ `);
+
+ let pkg = path.join(folder, 'src', 'main', 'java', 'pkg');
+ let testPkg = path.join(folder, 'src', 'test', 'java', 'pkg');
+ let resources = path.join(folder, 'src', 'main', 'resources');
+ let mainJava = path.join(pkg, 'Main.java');
+ let mainTestJava = path.join(testPkg, 'MainTest.java');
+
+ await fs.promises.mkdir(pkg, { recursive: true });
+ await fs.promises.mkdir(resources, { recursive: true });
+ await fs.promises.mkdir(testPkg, { recursive: true });
+
+ await fs.promises.writeFile(mainJava, `
+package pkg;
+public class Main {
+ public static void main(String... args) throws Exception {
+ System.out.println("Endless wait...");
+ while (true) {
+ Thread.sleep(1000);
+ }
+ }
+ public String getName() {
+ return "John";
+ }
+}
+ `);
+
+ await fs.promises.writeFile(mainTestJava, `
+package pkg;
+import static org.junit.jupiter.api.Assertions.*;
+class MainTest {
+ @org.junit.jupiter.api.Test
+ public void testGetName() {
+ assertEquals("John", new Main().getName());
+ }
+ @org.junit.jupiter.api.Nested
+ class NestedTest {
+ @org.junit.jupiter.api.Test
+ public void testTrue() {
+ assertTrue(true);
+ }
+ }
+}
+ `);
+}
+
async function dumpJava() {
const cmd = 'jps';
const args = [ '-v' ];
diff --git a/java/java.lsp.server/vscode/src/testAdapter.ts
b/java/java.lsp.server/vscode/src/testAdapter.ts
index 26daaac..3ba428a 100644
--- a/java/java.lsp.server/vscode/src/testAdapter.ts
+++ b/java/java.lsp.server/vscode/src/testAdapter.ts
@@ -20,7 +20,7 @@
import { commands, debug, tests, workspace, CancellationToken, TestController,
TestItem, TestRunProfileKind, TestRunRequest, Uri, TestRun, TestMessage,
Location, Position } from "vscode";
import * as path from 'path';
-import { asRange, TestSuite } from "./protocol";
+import { asRange, TestCase, TestSuite } from "./protocol";
import { LanguageClient } from "vscode-languageclient";
export class NbTestAdapter {
@@ -114,6 +114,12 @@ export class NbTestAdapter {
this.disposables = [];
}
+ testOutput(output: string): void {
+ if (this.currentRun && output) {
+ this.currentRun.appendOutput(output.replace(/\n/g, '\r\n'));
+ }
+ }
+
testProgress(suite: TestSuite): void {
const currentSuite = this.testController.items.get(suite.name);
switch (suite.state) {
@@ -125,8 +131,10 @@ export class NbTestAdapter {
this.set(currentSuite, 'started');
}
break;
- case 'completed':
+ case 'passed':
+ case "failed":
case 'errored':
+ case 'skipped':
if (suite.tests) {
this.updateTests(suite, true);
if (currentSuite) {
@@ -136,8 +144,11 @@ export class NbTestAdapter {
let currentTest =
currentSuite.children.get(test.id);
if (!currentTest) {
currentSuite.children.forEach(item => {
- if (!currentTest &&
test.id.startsWith(item.id)) {
- currentTest =
item.children.get(test.id);
+ if (!currentTest) {
+ const subName =
this.subTestName(item, test);
+ if (subName) {
+ currentTest =
item.children.get(test.id);
+ }
}
});
}
@@ -174,6 +185,8 @@ export class NbTestAdapter {
if (suiteMessages.length > 0) {
this.set(currentSuite, 'errored', suiteMessages,
true);
currentSuite.children.forEach(item =>
this.set(item, 'skipped'));
+ } else {
+ this.set(currentSuite, suite.state, undefined,
true);
}
}
}
@@ -209,23 +222,22 @@ export class NbTestAdapter {
children.push(currentTest);
} else {
if (testExecution) {
- const parents: TestItem[] = [];
+ const parents: Map<TestItem, string> = new Map();
currentSuite?.children.forEach(item => {
- if (test.id.startsWith(item.id)) {
- parents.push(item);
+ const subName = this.subTestName(item, test);
+ if (subName) {
+ parents.set(item, subName);
}
});
- if (parents.length === 1) {
- let arr = parentTests.get(parents[0]);
- if (!arr) {
- parentTests.set(parents[0], arr = []);
- children.push(parents[0]);
- }
- let label = test.name;
- if (label.startsWith(parents[0].label)) {
- label =
label.slice(parents[0].label.length).trim();
- }
- arr.push(this.testController.createTestItem(test.id,
label));
+ if (parents.size === 1) {
+ parents.forEach((label, parentTest) => {
+ let arr = parentTests.get(parentTest);
+ if (!arr) {
+ parentTests.set(parentTest, arr = []);
+ children.push(parentTest);
+ }
+
arr.push(this.testController.createTestItem(test.id, label));
+ });
}
} else {
currentTest = this.testController.createTestItem(test.id,
test.name, testUri);
@@ -246,4 +258,21 @@ export class NbTestAdapter {
currentSuite.children.replace(children);
}
}
+
+ subTestName(item: TestItem, test: TestCase): string | undefined {
+ if (test.id.startsWith(item.id)) {
+ let label = test.name;
+ if (label.startsWith(item.label)) {
+ label = label.slice(item.label.length).trim();
+ }
+ return label;
+ } else {
+ const regexp = new RegExp(item.id.replace(/#\S*/g, '\\S*'));
+ if (regexp.test(test.id)) {
+ let idx = test.id.indexOf(':');
+ return idx < 0 ? test.id : test.id.slice(idx + 1);
+ }
+ }
+ return undefined;
+ }
}
diff --git a/java/junit.ant/nbproject/project.xml
b/java/junit.ant/nbproject/project.xml
index eeb69a3..11ab478 100644
--- a/java/junit.ant/nbproject/project.xml
+++ b/java/junit.ant/nbproject/project.xml
@@ -58,7 +58,7 @@
<compile-dependency/>
<run-dependency>
<release-version>2</release-version>
- <specification-version>2.0</specification-version>
+ <specification-version>2.26</specification-version>
</run-dependency>
</dependency>
<dependency>
@@ -148,7 +148,7 @@
</run-dependency>
</dependency>
<dependency>
- <code-name-base>org.openide.util.ui</code-name-base>
+ <code-name-base>org.openide.util</code-name-base>
<build-prerequisite/>
<compile-dependency/>
<run-dependency>
@@ -156,19 +156,19 @@
</run-dependency>
</dependency>
<dependency>
- <code-name-base>org.openide.util</code-name-base>
+ <code-name-base>org.openide.util.lookup</code-name-base>
<build-prerequisite/>
<compile-dependency/>
<run-dependency>
- <specification-version>9.3</specification-version>
+ <specification-version>8.25</specification-version>
</run-dependency>
</dependency>
<dependency>
- <code-name-base>org.openide.util.lookup</code-name-base>
+ <code-name-base>org.openide.util.ui</code-name-base>
<build-prerequisite/>
<compile-dependency/>
<run-dependency>
- <specification-version>8.25</specification-version>
+ <specification-version>9.3</specification-version>
</run-dependency>
</dependency>
</module-dependencies>
diff --git
a/java/junit.ant/src/org/netbeans/modules/junit/ant/JUnitOutputReader.java
b/java/junit.ant/src/org/netbeans/modules/junit/ant/JUnitOutputReader.java
index 21d1b21..0e866e0 100644
--- a/java/junit.ant/src/org/netbeans/modules/junit/ant/JUnitOutputReader.java
+++ b/java/junit.ant/src/org/netbeans/modules/junit/ant/JUnitOutputReader.java
@@ -692,7 +692,8 @@ final class JUnitOutputReader {
int addFail = failures;
int addError = errors;
int addPass = total - failures - errors;
- for(Testcase tc: testSession.getCurrentSuite().getTestcases()){
+ TestSuite suite = testSession.getCurrentSuite();
+ for(Testcase tc: suite.getTestcases()){
switch(tc.getStatus()){
case ERROR: addError--;break;
case FAILED: addFail--;break;
@@ -717,6 +718,7 @@ final class JUnitOutputReader {
lastSuiteTime = time;
state = State.SUITE_FINISHED;
+ testSession.finishSuite(suite);
}
private void testCaseStarted(String name){
diff --git
a/java/junit.ui/src/org/netbeans/modules/junit/ui/actions/TestClassInfoTask.java
b/java/junit.ui/src/org/netbeans/modules/junit/ui/actions/TestClassInfoTask.java
index 85578a5..36534eb 100644
---
a/java/junit.ui/src/org/netbeans/modules/junit/ui/actions/TestClassInfoTask.java
+++
b/java/junit.ui/src/org/netbeans/modules/junit/ui/actions/TestClassInfoTask.java
@@ -24,6 +24,7 @@ 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 com.sun.source.util.Trees;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.ArrayList;
@@ -50,6 +51,7 @@ 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.api.java.source.Task;
+import org.netbeans.api.java.source.TreeUtilities;
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;
@@ -64,6 +66,7 @@ public final class TestClassInfoTask implements
Task<CompilationController> {
private SingleMethod singleMethod;
private static final String JUNIT4_ANNOTATION = "org.junit.Test"; //NOI18N
+ private static final String JUNIT5_NESTED_ANNOTATION =
"org.junit.jupiter.api.Nested"; //NOI18N
private static final String JUNIT5_ANNOTATION =
"org.junit.platform.commons.annotation.Testable"; //NOI18N
private static final String TESTCASE = "junit.framework.TestCase"; //NOI18N
@@ -83,39 +86,46 @@ public final class TestClassInfoTask implements
Task<CompilationController> {
if (!isTestSource(fileObject)) {
return Collections.emptyList();
}
- ClassTree clazz;
- List<TreePath> methods;
+ List<TestMethod> result = new ArrayList<>();
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();
+ ClassTree 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();
- }
+ List<TreePath> methods = clazz.getMembers().stream().filter(m ->
m.getKind() == Kind.METHOD).map(m -> new TreePath(pathToClass,
m)).collect(Collectors.toList());
+ collect(info, pathToClass, methods, true, cancel, result);
+ return result;
}
- int clazzPreferred = info.getTreeUtilities().findNameSpan(clazz)[0];
- TypeElement typeElement = (TypeElement) info.getTrees().getElement(new
TreePath(new TreePath(info.getCompilationUnit()), clazz));
+ TreePath tp = info.getTreeUtilities().pathFor(caretPosIfAny);
+ while (tp != null && tp.getLeaf().getKind() != Kind.METHOD) {
+ tp = tp.getParentPath();
+ }
+ if (tp != null) {
+ collect(info, tp.getParentPath(), Collections.singletonList(tp),
false, cancel, result);
+ return result;
+ }
+ return Collections.emptyList();
+ }
+
+ SingleMethod getSingleMethod() {
+ return singleMethod;
+ }
+
+ private static void collect(CompilationInfo info, TreePath clazz,
List<TreePath> methods, boolean searchNested, AtomicBoolean cancel,
List<TestMethod> result) {
+ Trees trees = info.getTrees();
Elements elements = info.getElements();
+ TreeUtilities treeUtilities = info.getTreeUtilities();
+ int clazzPreferred = treeUtilities.findNameSpan((ClassTree)
clazz.getLeaf())[0];
+ TypeElement typeElement = (TypeElement) trees.getElement(clazz);
TypeElement testcase = elements.getTypeElement(TESTCASE);
boolean junit3 = (testcase != null && typeElement != null) ?
info.getTypes().isSubtype(typeElement.asType(), testcase.asType()) : false;
- List<TestMethod> result = new ArrayList<>();
for (TreePath tp : methods) {
if (cancel.get()) {
- return null;
+ return;
}
- Element element = info.getTrees().getElement(tp);
+ Element element = trees.getElement(tp);
if (element != null) {
String mn = element.getSimpleName().toString();
boolean testMethod = false;
@@ -128,15 +138,15 @@ public final class TestClassInfoTask implements
Task<CompilationController> {
}
}
if (testMethod) {
- SourcePositions sp = info.getTrees().getSourcePositions();
+ SourcePositions sp = trees.getSourcePositions();
int start = (int)
sp.getStartPosition(tp.getCompilationUnit(), tp.getLeaf());
- int preferred =
info.getTreeUtilities().findNameSpan((MethodTree) tp.getLeaf())[0];
+ int preferred = treeUtilities.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(),
+ result.add(new
TestMethod(elements.getBinaryName(typeElement).toString(),
doc != null ?
doc.createPosition(clazzPreferred) : new SimplePosition(clazzPreferred),
- new SingleMethod(fileObject, mn),
+ new SingleMethod(info.getFileObject(), 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)));
@@ -146,11 +156,20 @@ public final class TestClassInfoTask implements
Task<CompilationController> {
}
}
}
- return result;
- }
-
- SingleMethod getSingleMethod() {
- return singleMethod;
+ if (searchNested && !cancel.get()) {
+ ((ClassTree)clazz.getLeaf()).getMembers().stream().filter(m ->
m.getKind() == Kind.CLASS).map(n -> new TreePath(clazz, n)).forEach(nested -> {
+ if (!cancel.get()) {
+ Element nestedElement = trees.getElement(nested);
+ if (nestedElement != null && !junit3) {
+ List<? extends AnnotationMirror> allAnnotationMirrors
= elements.getAllAnnotationMirrors(nestedElement);
+ if (isJunit5Nested(allAnnotationMirrors)) {
+ List<TreePath> nestedMethods = ((ClassTree)
nested.getLeaf()).getMembers().stream().filter(m -> m.getKind() ==
Kind.METHOD).map(m -> new TreePath(nested, m)).collect(Collectors.toList());
+ collect(info, nested, nestedMethods, true, cancel,
result);
+ }
+ }
+ }
+ });
+ }
}
private static boolean isTestSource(FileObject fo) {
@@ -175,6 +194,17 @@ public final class TestClassInfoTask implements
Task<CompilationController> {
return false;
}
+ private static boolean isJunit5Nested(List<? extends AnnotationMirror>
allAnnotationMirrors) {
+ for (Iterator<? extends AnnotationMirror> it =
allAnnotationMirrors.iterator(); it.hasNext();) {
+ AnnotationMirror annotationMirror = it.next();
+ TypeElement typeElement = (TypeElement)
annotationMirror.getAnnotationType().asElement();
+ if
(typeElement.getQualifiedName().contentEquals(JUNIT5_NESTED_ANNOTATION)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private static boolean isJunit5Testable(List<? extends AnnotationMirror>
allAnnotationMirrors) {
Queue<AnnotationMirror> pendingMirrorsToCheck = new
ArrayDeque<>(allAnnotationMirrors);
Set<AnnotationMirror> alreadyAddedMirrorsToCheck = new
HashSet<>(allAnnotationMirrors);
diff --git a/java/maven.junit/nbproject/project.xml
b/java/maven.junit/nbproject/project.xml
index e9fb585..9a35f1a 100644
--- a/java/maven.junit/nbproject/project.xml
+++ b/java/maven.junit/nbproject/project.xml
@@ -40,7 +40,7 @@
<compile-dependency/>
<run-dependency>
<release-version>2</release-version>
- <specification-version>2.0</specification-version>
+ <specification-version>2.26</specification-version>
</run-dependency>
</dependency>
<dependency>
diff --git
a/java/maven.junit/src/org/netbeans/modules/maven/junit/JUnitOutputListenerProvider.java
b/java/maven.junit/src/org/netbeans/modules/maven/junit/JUnitOutputListenerProvider.java
index e923bd6..4cda2cc 100644
---
a/java/maven.junit/src/org/netbeans/modules/maven/junit/JUnitOutputListenerProvider.java
+++
b/java/maven.junit/src/org/netbeans/modules/maven/junit/JUnitOutputListenerProvider.java
@@ -734,6 +734,7 @@ public class JUnitOutputListenerProvider implements
OutputProcessor {
} else { // update report status as a minimum
session.getReport(timeinmilis).setCompleted(true);
}
+ session.finishSuite(suite);
if (output.isFile()) {
if (junitManager != null) {
junitManager.displayOutput(session,
FileUtils.fileRead(output), false);
---------------------------------------------------------------------
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