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 16a48da LSP: Find tests on initial scan. (#3093)
16a48da is described below
commit 16a48da097a251638483fbc33699bea0f73d8da2
Author: Dusan Balek <[email protected]>
AuthorDate: Thu Aug 26 09:39:27 2021 +0200
LSP: Find tests on initial scan. (#3093)
---
.../groovy/editor/api/parser/GroovyParser.java | 5 +-
.../editor/compiler/ParsingCompilerCustomizer.java | 9 +-
ide/gsf.testrunner.ui/apichanges.xml | 12 ++
ide/gsf.testrunner.ui/manifest.mf | 2 -
ide/gsf.testrunner.ui/nbproject/project.properties | 1 +
ide/gsf.testrunner.ui/nbproject/project.xml | 2 +-
.../gsf/testrunner/ui/TestMethodFinderImpl.java | 154 +++++++++++++++++++++
.../gsf/testrunner/ui/api/TestMethodFinder.java | 118 ++++++++++++++++
.../parsing/impl/indexing/RepositoryUpdater.java | 19 ++-
java/java.lsp.server/nbproject/project.xml | 2 +-
.../server/protocol/TextDocumentServiceImpl.java | 39 +-----
.../lsp/server/protocol/WorkspaceServiceImpl.java | 110 +++++++--------
12 files changed, 370 insertions(+), 103 deletions(-)
diff --git
a/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/api/parser/GroovyParser.java
b/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/api/parser/GroovyParser.java
index fee5c7f..40860f8 100644
---
a/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/api/parser/GroovyParser.java
+++
b/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/api/parser/GroovyParser.java
@@ -829,7 +829,10 @@ public class GroovyParser extends Parser {
}
void setIndexingTask(Task t) {
- this.parserTask = parserTask;
+ this.parserTask = t;
+ if (customizerCtx != null) {
+ customizerCtx.setConsumerTask(t);
+ }
}
@Override
diff --git
a/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/compiler/ParsingCompilerCustomizer.java
b/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/compiler/ParsingCompilerCustomizer.java
index 046272f..0e3d405 100644
---
a/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/compiler/ParsingCompilerCustomizer.java
+++
b/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/compiler/ParsingCompilerCustomizer.java
@@ -61,7 +61,7 @@ public interface ParsingCompilerCustomizer {
*/
public final class Context {
private final Snapshot snapshot;
- private final Task consumerTask;
+ private Task consumerTask;
/**
* Constructs the context.
@@ -90,5 +90,12 @@ public interface ParsingCompilerCustomizer {
public Task getConsumerTask() {
return consumerTask;
}
+
+ /**
+ * Sets the task that is about to consume the parser's results.
+ */
+ public void setConsumerTask(Task consumerTask) {
+ this.consumerTask = consumerTask;
+ }
}
}
diff --git a/ide/gsf.testrunner.ui/apichanges.xml
b/ide/gsf.testrunner.ui/apichanges.xml
index 2d3d18c..19ba911 100644
--- a/ide/gsf.testrunner.ui/apichanges.xml
+++ b/ide/gsf.testrunner.ui/apichanges.xml
@@ -52,6 +52,18 @@
<!-- ACTUAL CHANGES BEGIN HERE: -->
<changes>
+ <change id="TestMethodsFinder">
+ <api name="CommonTestrunnerUIAPI"/>
+ <summary>Added FindTestMethods API</summary>
+ <version major="1" minor="27"/>
+ <date day="25" month="8" year="2021"/>
+ <author login="dbalek"/>
+ <compatibility addition="yes"/>
+ <description>
+ Added API to provide a list of TestMethods found in sources under
particutlar test roots.
+ </description>
+ <class package="org.netbeans.modules.gsf.testrunner.ui.api"
name="TestMethodFinder"/>
+ </change>
<change id="ComputeTestMethodsAndTestMethodGetTestClassPosition">
<api name="CommonTestrunnerUIAPI"/>
<summary>Added ComputeTestMethods SPI and getTestClassPosition() to
TestMethod</summary>
diff --git a/ide/gsf.testrunner.ui/manifest.mf
b/ide/gsf.testrunner.ui/manifest.mf
index 741896d..6df6ce7 100644
--- a/ide/gsf.testrunner.ui/manifest.mf
+++ b/ide/gsf.testrunner.ui/manifest.mf
@@ -2,5 +2,3 @@ Manifest-Version: 1.0
OpenIDE-Module: org.netbeans.modules.gsf.testrunner.ui
OpenIDE-Module-Layer: org/netbeans/modules/gsf/testrunner/ui/layer.xml
OpenIDE-Module-Localizing-Bundle:
org/netbeans/modules/gsf/testrunner/ui/Bundle.properties
-OpenIDE-Module-Specification-Version: 1.26
-
diff --git a/ide/gsf.testrunner.ui/nbproject/project.properties
b/ide/gsf.testrunner.ui/nbproject/project.properties
index 9c1cd1c..d664921 100644
--- a/ide/gsf.testrunner.ui/nbproject/project.properties
+++ b/ide/gsf.testrunner.ui/nbproject/project.properties
@@ -18,3 +18,4 @@ is.eager=true
javac.source=1.8
javac.compilerargs=-Xlint -Xlint:-serial
javadoc.apichanges=${basedir}/apichanges.xml
+spec.version.base=1.27
diff --git a/ide/gsf.testrunner.ui/nbproject/project.xml
b/ide/gsf.testrunner.ui/nbproject/project.xml
index e7ccc9f..63ffee1 100644
--- a/ide/gsf.testrunner.ui/nbproject/project.xml
+++ b/ide/gsf.testrunner.ui/nbproject/project.xml
@@ -136,7 +136,7 @@
<build-prerequisite/>
<compile-dependency/>
<run-dependency>
- <specification-version>9.0</specification-version>
+ <implementation-version/>
</run-dependency>
</dependency>
<dependency>
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
new file mode 100644
index 0000000..6588969
--- /dev/null
+++
b/ide/gsf.testrunner.ui/src/org/netbeans/modules/gsf/testrunner/ui/TestMethodFinderImpl.java
@@ -0,0 +1,154 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.gsf.testrunner.ui;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.BiConsumer;
+import org.netbeans.api.editor.mimelookup.MimeLookup;
+import org.netbeans.api.editor.mimelookup.MimeRegistration;
+import org.netbeans.modules.gsf.testrunner.ui.api.TestMethodController;
+import org.netbeans.modules.gsf.testrunner.ui.spi.ComputeTestMethods;
+import org.netbeans.modules.parsing.api.Snapshot;
+import org.netbeans.modules.parsing.spi.Parser;
+import org.netbeans.modules.parsing.spi.indexing.Context;
+import org.netbeans.modules.parsing.spi.indexing.EmbeddingIndexer;
+import org.netbeans.modules.parsing.spi.indexing.EmbeddingIndexerFactory;
+import org.netbeans.modules.parsing.spi.indexing.Indexable;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileUtil;
+import org.openide.util.Exceptions;
+import org.openide.util.WeakSet;
+
+/**
+ *
+ * @author Dusan Balek
+ */
+public final class TestMethodFinderImpl extends EmbeddingIndexer {
+
+ public static final String NAME = "tests"; // NOI18N
+ public static final int VERSION = 1;
+ public static TestMethodFinderImpl INSTANCE = null;
+
+ private final WeakSet<BiConsumer<FileObject,
Collection<TestMethodController.TestMethod>>> listeners = new WeakSet<>();
+
+ @Override
+ protected void index(Indexable indexable, Parser.Result parserResult,
Context context) {
+ List<TestMethodController.TestMethod> testMethods = new ArrayList<>();
+ for (ComputeTestMethods ctm :
MimeLookup.getLookup(indexable.getMimeType()).lookupAll(ComputeTestMethods.class))
{
+ testMethods.addAll(ctm.computeTestMethods(parserResult, new
AtomicBoolean()));
+ }
+ FileObject fo = parserResult.getSnapshot().getSource().getFileObject();
+ store(context.getIndexFolder(), indexable.getURL(),
indexable.getRelativePath(), testMethods);
+ if (!context.isAllFilesIndexing()) {
+ synchronized (listeners) {
+ for (BiConsumer<FileObject,
Collection<TestMethodController.TestMethod>> listener : listeners) {
+ listener.accept(fo, testMethods);
+ }
+ }
+ }
+ }
+
+ public void addListener(BiConsumer<FileObject,
Collection<TestMethodController.TestMethod>> listener) {
+ synchronized(listeners) {
+ listeners.putIfAbsent(listener);
+ }
+ }
+
+ private void store(FileObject indexFolder, URL url, String resourceName,
List<TestMethodController.TestMethod> methods) {
+ File cacheRoot = FileUtil.toFile(indexFolder);
+ File output = new File(cacheRoot, resourceName + ".tests"); //NOI18N
+ if (methods.isEmpty()) {
+ if (output.exists()) {
+ output.delete();
+ }
+ } else {
+ 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("method: "); //NOI18N
+ pw.print(method.method().getMethodName());
+ pw.print(':'); //NOI18N
+ pw.println(method.start().getOffset());
+ }
+ } catch (IOException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ }
+ }
+
+ @MimeRegistration(mimeType="", service=EmbeddingIndexerFactory.class)
//NOI18N
+ public static class Factory extends EmbeddingIndexerFactory {
+
+ @Override
+ public EmbeddingIndexer createIndexer(Indexable indexable, Snapshot
snapshot) {
+ if (INSTANCE == null) {
+ INSTANCE = new TestMethodFinderImpl();
+ }
+ return INSTANCE;
+ }
+
+ @Override
+ public void filesDeleted(Iterable<? extends Indexable> deleted,
Context context) {
+ File cacheRoot = FileUtil.toFile(context.getIndexFolder());
+ for (Indexable indexable : deleted) {
+ File output = new File(cacheRoot, indexable.getRelativePath()
+ ".tests"); //NOI18N
+ if (output.exists()) {
+ output.delete();
+ }
+ }
+ }
+
+ @Override
+ public void filesDirty(Iterable<? extends Indexable> dirty, Context
context) {
+ }
+
+ @Override
+ public String getIndexerName() {
+ return NAME;
+ }
+
+ @Override
+ public int getIndexVersion() {
+ return VERSION;
+ }
+ }
+}
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
new file mode 100644
index 0000000..b1dc558
--- /dev/null
+++
b/ide/gsf.testrunner.ui/src/org/netbeans/modules/gsf/testrunner/ui/api/TestMethodFinder.java
@@ -0,0 +1,118 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.gsf.testrunner.ui.api;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URI;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.BiConsumer;
+import javax.swing.text.Position;
+import org.netbeans.modules.gsf.testrunner.ui.TestMethodFinderImpl;
+import org.netbeans.modules.parsing.impl.indexing.CacheFolder;
+import org.netbeans.spi.project.SingleMethod;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileUtil;
+import org.openide.filesystems.URLMapper;
+import org.openide.util.Exceptions;
+
+/**
+ * API to provide a list of {@link TestMethod}s found in sources under
particular test roots.
+ *
+ * @author Dusan Balek
+ * @since 1.27
+ */
+public final class TestMethodFinder {
+
+ /**
+ * Provides a list of {@link TestMethod}s found in sources under
particular test roots.
+ *
+ * @param testRoots roots to search test methods for
+ * @param listener a listener to inform about later changes. The listener
is held weakly.
+ * @return map of test source files to tests methods found
+ * @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);
+ }
+ Map<FileObject, Collection<TestMethodController.TestMethod>>
file2TestMethods = new HashMap<>();
+ for (FileObject testRoot : testRoots) {
+ try {
+ FileObject cacheRoot = getCacheRoot(testRoot.toURL());
+ if (cacheRoot != null) {
+ Enumeration<? extends FileObject> children =
cacheRoot.getChildren(true);
+ while (children.hasMoreElements()) {
+ FileObject child = children.nextElement();
+ if (child.hasExt("tests")) { //NOI18N
+ loadTestMethods(child, file2TestMethods);
+ }
+ }
+ }
+ } catch (IOException ex) {}
+ }
+ return file2TestMethods;
+ }
+
+ private static void loadTestMethods(FileObject input, Map<FileObject,
Collection<TestMethodController.TestMethod>> file2TestMethods) {
+ try (BufferedReader br = new BufferedReader(new
InputStreamReader(input.getInputStream(), "UTF-8"))) {
+ FileObject fo = null;
+ String className = null;
+ Position classPosition = null;
+ Collection<TestMethodController.TestMethod> testMethods = null;
+ String line;
+ while ((line = br.readLine()) != null) {
+ if (line.startsWith("url: ")) { //NOI18N
+ String url = line.substring(5);
+ fo = URLMapper.findFileObject(URI.create(url).toURL());
+ if (fo == null) {
+ return;
+ }
+ testMethods = file2TestMethods.computeIfAbsent(fo, fObj ->
{
+ return new ArrayList<>();
+ });
+ } else if (line.startsWith("class: ")) { //NOI18N
+ String info = line.substring(7);
+ int idx = info.lastIndexOf(':');
+ className = (idx < 0 ? info : info.substring(0,
idx)).trim();
+ classPosition = idx < 0 ? null : () ->
Integer.parseInt(info.substring(idx + 1));
+ } else if (line.startsWith("method: ") && testMethods != null
&& className != null) { //NOI18N
+ String info = line.substring(8);
+ int idx = info.lastIndexOf(':');
+ String name = (idx < 0 ? info : info.substring(0,
idx)).trim();
+ Position methodPosition = idx < 0 ? null : () ->
Integer.parseInt(info.substring(idx + 1));
+ testMethods.add(new
TestMethodController.TestMethod(className, classPosition, new SingleMethod(fo,
name), methodPosition, null, null));
+ }
+ }
+ } catch (IOException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ }
+
+ private static FileObject getCacheRoot(URL root) throws IOException {
+ final FileObject dataFolder = CacheFolder.getDataFolder(root, true);
+ return dataFolder != null ? FileUtil.createFolder(dataFolder,
TestMethodFinderImpl.NAME + "/" + TestMethodFinderImpl.VERSION) : null; //NOI18N
+ }
+}
diff --git
a/ide/parsing.indexing/src/org/netbeans/modules/parsing/impl/indexing/RepositoryUpdater.java
b/ide/parsing.indexing/src/org/netbeans/modules/parsing/impl/indexing/RepositoryUpdater.java
index a30f189..134442d 100644
---
a/ide/parsing.indexing/src/org/netbeans/modules/parsing/impl/indexing/RepositoryUpdater.java
+++
b/ide/parsing.indexing/src/org/netbeans/modules/parsing/impl/indexing/RepositoryUpdater.java
@@ -3124,7 +3124,7 @@ public final class RepositoryUpdater implements
PathRegistryListener, PropertyCh
return false;
}
- Collection<? extends
IndexerCache.IndexerInfo<EmbeddingIndexerFactory>> infos =
eifInfosMap.get(dirty.getMimeType());
+ Collection<? extends
IndexerCache.IndexerInfo<EmbeddingIndexerFactory>> infos =
getIndexerInfos(eifInfosMap, dirty.getMimeType());
if (infos != null && infos.size() > 0) {
final URL url = dirty.getURL();
if (url == null) {
@@ -3145,7 +3145,7 @@ public final class RepositoryUpdater implements
PathRegistryListener, PropertyCh
@Override
public void run(ResultIterator resultIterator)
throws Exception {
final String mimeType =
resultIterator.getSnapshot().getMimeType();
- final Collection<? extends
IndexerCache.IndexerInfo<EmbeddingIndexerFactory>> infos =
eifInfosMap.get(mimeType);
+ final Collection<? extends
IndexerCache.IndexerInfo<EmbeddingIndexerFactory>> infos =
getIndexerInfos(eifInfosMap, mimeType);
if (infos != null && infos.size() > 0) {
boolean finished = false;
@@ -3578,6 +3578,21 @@ public final class RepositoryUpdater implements
PathRegistryListener, PropertyCh
return result;
}
+ private static final String ALL_MIME_TYPES = ""; //NOI18N
+
+ private static Collection<? extends
IndexerCache.IndexerInfo<EmbeddingIndexerFactory>> getIndexerInfos(
+ final Map<String,
Collection<IndexerCache.IndexerInfo<EmbeddingIndexerFactory>>> eifInfosMap,
+ final String mimeType) {
+ final
Collection<IndexerCache.IndexerInfo<EmbeddingIndexerFactory>> infos = new
ArrayList<>();
+ if (eifInfosMap.containsKey(mimeType)) {
+ infos.addAll(eifInfosMap.get(mimeType));
+ }
+ if (eifInfosMap.containsKey(ALL_MIME_TYPES)) {
+ infos.addAll(eifInfosMap.get(ALL_MIME_TYPES));
+ }
+ return infos;
+ }
+
protected final boolean storeChanges(
@NullAllowed final String indexerName,
@NonNull final Context ctx,
diff --git a/java/java.lsp.server/nbproject/project.xml
b/java/java.lsp.server/nbproject/project.xml
index 99f64a7..9e4f7a3 100644
--- a/java/java.lsp.server/nbproject/project.xml
+++ b/java/java.lsp.server/nbproject/project.xml
@@ -214,7 +214,7 @@
<build-prerequisite/>
<compile-dependency/>
<run-dependency>
- <specification-version>1.25</specification-version>
+ <specification-version>1.27</specification-version>
</run-dependency>
</dependency>
<dependency>
diff --git
a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/TextDocumentServiceImpl.java
b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/TextDocumentServiceImpl.java
index c950560..3e91b48 100644
---
a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/TextDocumentServiceImpl.java
+++
b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/TextDocumentServiceImpl.java
@@ -42,14 +42,12 @@ import java.util.Collections;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
@@ -158,8 +156,6 @@ import org.netbeans.api.project.Sources;
import org.netbeans.lib.editor.util.swing.DocumentUtilities;
import org.netbeans.modules.editor.java.GoToSupport;
import org.netbeans.modules.editor.java.GoToSupport.GoToTarget;
-import
org.netbeans.modules.gsf.testrunner.ui.api.TestMethodController.TestMethod;
-import org.netbeans.modules.gsf.testrunner.ui.spi.ComputeTestMethods;
import org.netbeans.modules.java.editor.base.fold.JavaElementFoldVisitor;
import
org.netbeans.modules.java.editor.base.fold.JavaElementFoldVisitor.FoldCreator;
import
org.netbeans.modules.java.editor.base.semantic.MarkOccurrencesHighlighterBase;
@@ -175,7 +171,6 @@ import org.netbeans.modules.java.lsp.server.Utils;
import org.netbeans.modules.java.lsp.server.debugging.utils.ErrorUtilities;
import org.netbeans.modules.parsing.api.ParserManager;
import org.netbeans.modules.parsing.api.ResultIterator;
-import org.netbeans.modules.java.lsp.server.files.OpenedDocuments;
import org.netbeans.modules.parsing.api.Source;
import org.netbeans.modules.parsing.api.UserTask;
import
org.netbeans.modules.parsing.impl.indexing.implspi.ActiveDocumentProvider.IndexingAware;
@@ -904,8 +899,6 @@ public class TextDocumentServiceImpl implements
TextDocumentService, LanguageCli
}
- private ConcurrentHashMap<String, Boolean> upToDateTests = new
ConcurrentHashMap<>();
-
@NbBundle.Messages({"# {0} - method name", "LBL_Run=Run {0}",
"# {0} - method name", "LBL_Debug=Debug {0}",
"# {0} - method name", "# {1} - configuration name",
"LBL_RunWith=Run {0} with {1}",
@@ -923,38 +916,10 @@ public class TextDocumentServiceImpl implements
TextDocumentService, LanguageCli
}
CompletableFuture<List<? extends CodeLens>> result = new
CompletableFuture<>();
try {
- ParserManager.parse(Collections.singleton(source), new UserTask() {
+ ParserManager.parseWhenScanFinished(Collections.singleton(source),
new UserTask() {
@Override
public void run(ResultIterator resultIterator) throws
Exception {
Parser.Result parserResult =
resultIterator.getParserResult();
- //look for test methods:
- if (!upToDateTests.getOrDefault(uri, Boolean.FALSE)) {
- List<TestMethod> testMethods = new ArrayList<>();
- for (ComputeTestMethods ctm :
MimeLookup.getLookup(parserResult.getSnapshot().getMimePath()).lookupAll(ComputeTestMethods.class))
{
-
testMethods.addAll(ctm.computeTestMethods(parserResult, new AtomicBoolean()));
- }
- if (!testMethods.isEmpty()) {
- String testClassName = null;
- Integer testClassLine = null;
- List<TestSuiteInfo.TestCaseInfo> tests = new
ArrayList<>(testMethods.size());
- for (TestMethod testMethod : testMethods) {
- if (testClassName == null) {
- testClassName =
testMethod.getTestClassName();
- }
- if (testClassLine == null) {
- testClassLine =
testMethod.getTestClassPosition() != null
- ?
Utils.createPosition(parserResult.getSnapshot().getSource().getFileObject(),
testMethod.getTestClassPosition().getOffset()).getLine()
- : null;
- }
- String id = testMethod.getTestClassName() +
':' + testMethod.method().getMethodName();
- String fullName =
testMethod.getTestClassName() + '.' + testMethod.method().getMethodName();
- int testLine =
Utils.createPosition(parserResult.getSnapshot().getSource().getFileObject(),
testMethod.start().getOffset()).getLine();
- tests.add(new TestSuiteInfo.TestCaseInfo(id,
testMethod.method().getMethodName(), fullName, uri, testLine,
TestSuiteInfo.State.Loaded, null));
- }
- client.notifyTestProgress(new
TestProgressParams(uri, new TestSuiteInfo(testClassName, uri, testClassLine,
TestSuiteInfo.State.Loaded, tests)));
- upToDateTests.put(uri, Boolean.TRUE);
- }
- }
//look for main methods:
List<CodeLens> lens = new ArrayList<>();
CompilationController cc =
CompilationController.get(parserResult);
@@ -1331,7 +1296,6 @@ public class TextDocumentServiceImpl implements
TextDocumentService, LanguageCli
@Override
public void didChange(DidChangeTextDocumentParams params) {
String uri = params.getTextDocument().getUri();
- upToDateTests.put(uri, Boolean.FALSE);
Document doc = server.getOpenedDocuments().getDocument(uri);
if (doc != null) {
NbDocument.runAtomic((StyledDocument) doc, () -> {
@@ -1355,7 +1319,6 @@ public class TextDocumentServiceImpl implements
TextDocumentService, LanguageCli
public void didClose(DidCloseTextDocumentParams params) {
try {
String uri = params.getTextDocument().getUri();
- upToDateTests.remove(uri);
// the order here is important ! As the file may cease to exist,
it's
// important that the doucment is already gone form the client.
server.getOpenedDocuments().notifyClosed(uri);
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 e778c19..c018c71 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
@@ -30,7 +30,6 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
-import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
@@ -40,6 +39,9 @@ import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import javax.lang.model.element.Element;
@@ -61,9 +63,10 @@ import org.netbeans.api.annotations.common.NonNull;
import org.netbeans.api.annotations.common.NullAllowed;
import org.netbeans.api.debugger.ActionsManager;
import org.netbeans.api.debugger.DebuggerManager;
-import org.netbeans.api.editor.mimelookup.MimeLookup;
+import org.netbeans.api.java.classpath.ClassPath;
import org.netbeans.api.java.project.JavaProjectConstants;
import org.netbeans.api.java.queries.SourceForBinaryQuery;
+import org.netbeans.api.java.queries.UnitTestForSourceQuery;
import org.netbeans.api.java.source.ClassIndex;
import org.netbeans.api.java.source.ClasspathInfo;
import org.netbeans.api.java.source.CompilationInfo;
@@ -77,7 +80,7 @@ import org.netbeans.api.project.ProjectUtils;
import org.netbeans.api.project.SourceGroup;
import org.netbeans.api.project.ui.OpenProjects;
import org.netbeans.modules.gsf.testrunner.ui.api.TestMethodController;
-import org.netbeans.modules.gsf.testrunner.ui.spi.ComputeTestMethods;
+import org.netbeans.modules.gsf.testrunner.ui.api.TestMethodFinder;
import org.netbeans.modules.java.lsp.server.LspServerState;
import org.netbeans.modules.java.lsp.server.Utils;
import
org.netbeans.modules.java.lsp.server.debugging.attach.AttachConfigurations;
@@ -85,13 +88,7 @@ import
org.netbeans.modules.java.lsp.server.debugging.attach.AttachNativeConfigu
import org.netbeans.modules.java.source.ui.JavaSymbolProvider;
import org.netbeans.modules.java.source.ui.JavaTypeProvider;
import org.netbeans.modules.java.source.usages.ClassIndexImpl;
-import org.netbeans.modules.parsing.api.ParserManager;
-import org.netbeans.modules.parsing.api.ResultIterator;
-import org.netbeans.modules.parsing.api.Source;
-import org.netbeans.modules.parsing.api.UserTask;
import org.netbeans.modules.parsing.lucene.support.Queries;
-import org.netbeans.modules.parsing.spi.ParseException;
-import org.netbeans.modules.parsing.spi.Parser;
import org.netbeans.spi.jumpto.type.SearchType;
import org.netbeans.spi.project.ActionProgress;
import org.netbeans.spi.project.ActionProvider;
@@ -199,26 +196,50 @@ public final class WorkspaceServiceImpl implements
WorkspaceService, LanguageCli
if (file == null) {
return
CompletableFuture.completedFuture(Collections.emptyList());
}
- return
server.asyncOpenFileOwner(file).thenCompose(this::getTestRoots).thenApply(testRoots
-> {
- List<TestMethodController.TestMethod> testMethods = new
ArrayList<>();
- findTestMethods(testRoots, testMethods);
- if (testMethods.isEmpty()) {
- return Collections.emptyList();
- }
- Map<FileObject, TestSuiteInfo> file2TestSuites = new
HashMap<>();
- for (TestMethodController.TestMethod testMethod :
testMethods) {
- TestSuiteInfo suite =
file2TestSuites.computeIfAbsent(testMethod.method().getFile(), fo -> {
- String foUri = Utils.toUri(fo);
- int off = testMethod.getTestClassPosition() !=
null ? testMethod.getTestClassPosition().getOffset() : -1;
- Integer line = off < 0 ? null :
Utils.createPosition(testMethod.method().getFile(), off).getLine();
- return new
TestSuiteInfo(testMethod.getTestClassName(), foUri, line,
TestSuiteInfo.State.Loaded, new ArrayList<>());
- });
- String id = testMethod.getTestClassName() + ':' +
testMethod.method().getMethodName();
- String fullName = testMethod.getTestClassName() + '.'
+ testMethod.method().getMethodName();
- int line =
Utils.createPosition(testMethod.method().getFile(),
testMethod.start().getOffset()).getLine();
- suite.getTests().add(new
TestSuiteInfo.TestCaseInfo(id, testMethod.method().getMethodName(), fullName,
suite.getFile(), line, TestSuiteInfo.State.Loaded, null));
+ return
server.asyncOpenFileOwner(file).thenCompose(this::getTestRoots).thenCompose(testRoots
-> {
+ CompletableFuture<Object> future = new
CompletableFuture<>();
+ 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());
+ String url = Utils.toUri(fo);
+ String testClassName = null;
+ Integer testClassLine = null;
+ for (TestMethodController.TestMethod
testMethod : methods) {
+ if (testClassName == null) {
+ testClassName =
testMethod.getTestClassName();
+ }
+ if (testClassLine == null) {
+ testClassLine =
testMethod.getTestClassPosition() != null
+ ? Utils.createPosition(fo,
testMethod.getTestClassPosition().getOffset()).getLine()
+ : null;
+ }
+ String id = testMethod.getTestClassName()
+ ':' + testMethod.method().getMethodName();
+ String fullName =
testMethod.getTestClassName() + '.' + testMethod.method().getMethodName();
+ int testLine = Utils.createPosition(fo,
testMethod.start().getOffset()).getLine();
+ tests.add(new
TestSuiteInfo.TestCaseInfo(id, testMethod.method().getMethodName(), fullName,
url, testLine, TestSuiteInfo.State.Loaded, null));
+ }
+ return new TestSuiteInfo(testClassName, url,
testClassLine, TestSuiteInfo.State.Loaded, tests);
+ };
+ testMethodsListener.compareAndSet(null, (fo,
methods) -> {
+ try {
+ client.notifyTestProgress(new
TestProgressParams(Utils.toUri(fo), f.apply(fo, methods)));
+ } catch (Exception e) {
+ testMethodsListener.set(null);
+ }
+ });
+ 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()));
+ }
+ future.complete(suites);
+ }, true);
+ } catch (IOException ex) {
+ future.completeExceptionally(ex);
}
- return file2TestSuites.values();
+ return future;
});
}
case Server.JAVA_SUPER_IMPLEMENTATION:
@@ -302,7 +323,9 @@ public final class WorkspaceServiceImpl implements
WorkspaceService, LanguageCli
}
throw new UnsupportedOperationException("Command not supported: " +
params.getCommand());
}
-
+
+ private final AtomicReference<BiConsumer<FileObject,
Collection<TestMethodController.TestMethod>>> testMethodsListener = new
AtomicReference<>();
+
private static Map<String, Object> attributesMap(JsonObject json) {
Map<String, Object> map = new LinkedHashMap<>();
for (Entry<String, JsonElement> entry : json.entrySet()) {
@@ -382,34 +405,7 @@ public final class WorkspaceServiceImpl implements
WorkspaceService, LanguageCli
}
private boolean isTestGroup(SourceGroup sg) {
- return sg.getName().contains("TestSourceRoot") ||
sg.getName().contains("test.");
- }
-
- private void findTestMethods(Set<FileObject> testRoots,
List<TestMethodController.TestMethod> testMethods) {
- for (FileObject testRoot : testRoots) {
- List<Source> sources = new ArrayList<>();
- Enumeration<? extends FileObject> children =
testRoot.getChildren(true);
- while(children.hasMoreElements()) {
- FileObject fo = children.nextElement();
- boolean groovy =
this.client.getNbCodeCapabilities().wantsGroovySupport();
- if (fo.hasExt("java") || (groovy && fo.hasExt("groovy"))) {
-
sources.add(((TextDocumentServiceImpl)server.getTextDocumentService()).getSource(Utils.toUri(fo)));
- }
- }
- if (!sources.isEmpty()) {
- try {
- ParserManager.parseWhenScanFinished(sources, new
UserTask() {
- @Override
- public void run(ResultIterator resultIterator) throws
Exception {
- Parser.Result parserResult =
resultIterator.getParserResult();
- for (ComputeTestMethods ctm :
MimeLookup.getLookup(parserResult.getSnapshot().getMimePath()).lookupAll(ComputeTestMethods.class))
{
-
testMethods.addAll(ctm.computeTestMethods(parserResult, new AtomicBoolean()));
- }
- }
- }).get();
- } catch (Exception ex) {}
- }
- }
+ return UnitTestForSourceQuery.findSources(sg.getRootFolder()).length >
0;
}
@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