diff --git a/org.eclipse.lsp4e.test/META-INF/services/org.junit.jupiter.api.extension.Extension b/org.eclipse.lsp4e.test/META-INF/services/org.junit.jupiter.api.extension.Extension index 85689bb7d..54df40dad 100644 --- a/org.eclipse.lsp4e.test/META-INF/services/org.junit.jupiter.api.extension.Extension +++ b/org.eclipse.lsp4e.test/META-INF/services/org.junit.jupiter.api.extension.Extension @@ -1 +1,2 @@ -org.eclipse.lsp4e.test.utils.CloseIntroExtension \ No newline at end of file +org.eclipse.lsp4e.test.utils.MockLanguageServerExtension +org.eclipse.lsp4e.test.utils.CloseIntroExtension diff --git a/org.eclipse.lsp4e.test/fragment.xml b/org.eclipse.lsp4e.test/fragment.xml index 43ef922e0..73480c598 100644 --- a/org.eclipse.lsp4e.test/fragment.xml +++ b/org.eclipse.lsp4e.test/fragment.xml @@ -20,12 +20,6 @@ id="org.eclipse.lsp4e.test.server-with-exception" lastDocumentDisconnectedTimeout="0" label="Test LS With Exception"> - - - - @@ -130,7 +120,7 @@ base-type="org.eclipse.core.runtime.text" file-extensions="lsptmultils" id="org.eclipse.lsp4e.test.content-type-multi-ls" - name="Test Content Type" + name="Test Content Type which is picked up by two different LS" priority="normal"> - - GitHub Pull Request #688 */ @Test - public void testStartStopAndActive() throws CoreException, AssertionError { + public void testStartStopAndActive(MockLanguageServerFactory factory) throws CoreException, AssertionError { + factory.withCapabilities(MockLanguageServer::multiRootCapabilities); final int testCount= 100; - MockConnectionProviderMultiRootFolders.resetCounts(); - - IFile testFile1 = TestUtils.createFile(project, "shouldUseExtension.lsptWithMultiRoot", ""); + IFile testFile1 = TestUtils.createFile(project, "shouldUseExtension.lspt", ""); IEditorPart editor1 = TestUtils.openEditor(testFile1); @NonNull Collection wrappers = LanguageServiceAccessor.getLSWrappers(testFile1, request -> true); assertEquals(1, wrappers.size()); @@ -132,10 +133,7 @@ public void testStartStopAndActive() throws CoreException, AssertionError { if (ForkJoinPool.commonPool().getActiveThreadCount() > startingActiveThreads) throw new AssertionError("timeout waiting for ForkJoinPool.commonPool to go quiet"); - Integer cpStartCount= MockConnectionProviderMultiRootFolders.getStartCount(); - Integer cpStopCount= MockConnectionProviderMultiRootFolders.getStopCount(); - - assertEquals(cpStartCount, cpStopCount, "startCount == stopCount"); + assertEquals(factory.connectionProviderStartCounter.get(), factory.connectionProviderStopCounter.get()); } } diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/LanguageServersTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/LanguageServersTest.java index c50c27745..c19dfd0ae 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/LanguageServersTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/LanguageServersTest.java @@ -46,8 +46,8 @@ import org.eclipse.lsp4e.internal.Pair; import org.eclipse.lsp4e.test.utils.AbstractTestWithProject; import org.eclipse.lsp4e.test.utils.TestUtils; -import org.eclipse.lsp4e.tests.mock.MockConnectionProvider; import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4e.tests.mock.MockTextDocumentService; import org.eclipse.lsp4j.DidChangeTextDocumentParams; import org.eclipse.lsp4j.Hover; @@ -70,19 +70,20 @@ public class LanguageServersTest extends AbstractTestWithProject { private final Predicate MATCH_ALL = sc -> true; @Test - public void testCollectAll() throws Exception { - final var hoverCount = new AtomicInteger(); - MockLanguageServer.INSTANCE.setTextDocumentService(new MockTextDocumentService(MockLanguageServer.INSTANCE::buildMaybeDelayedFuture) { - @Override - public synchronized void didChange(DidChangeTextDocumentParams params) { - super.didChange(params); - } - - @Override - public synchronized CompletableFuture hover(HoverParams position) { - final var hoverResponse = new Hover(List.of(Either.forLeft("HoverContent" + hoverCount.incrementAndGet())), new Range(new Position(0, 0), new Position(0, 10))); - return CompletableFuture.completedFuture(hoverResponse); - } + public void testCollectAll(MockLanguageServerFactory factory) throws Exception { + factory.withConfiguration((idx, server) -> { + server.setTextDocumentService(new MockTextDocumentService(server::buildMaybeDelayedFuture) { + @Override + public void didChange(DidChangeTextDocumentParams params) { + super.didChange(params); + } + + @Override + public CompletableFuture hover(HoverParams position) { + final var hoverResponse = new Hover(List.of(Either.forLeft("HoverContent" + idx)), new Range(new Position(0, 0), new Position(0, 10))); + return CompletableFuture.completedFuture(hoverResponse); + } + }); }); IFile testFile = TestUtils.createUniqueTestFileMultiLS(project, "Here is some content"); @@ -101,24 +102,25 @@ public synchronized CompletableFuture hover(HoverParams position) { List hovers = result.join(); + assertTrue(hovers.contains("HoverContent0")); assertTrue(hovers.contains("HoverContent1")); - assertTrue(hovers.contains("HoverContent2")); } @Test - public void testCollectAllExcludesNulls() throws Exception { - final var hoverCount = new AtomicInteger(); - MockLanguageServer.INSTANCE.setTextDocumentService(new MockTextDocumentService(MockLanguageServer.INSTANCE::buildMaybeDelayedFuture) { - @Override - public synchronized void didChange(DidChangeTextDocumentParams params) { - super.didChange(params); - } - - @Override - public synchronized CompletableFuture hover(HoverParams position) { - final var hoverResponse = new Hover(List.of(Either.forLeft("HoverContent" + hoverCount.incrementAndGet())), new Range(new Position(0, 0), new Position(0, 10))); - return CompletableFuture.completedFuture(hoverCount.get() == 1 ? hoverResponse : null); - } + public void testCollectAllExcludesNulls(MockLanguageServerFactory factory) throws Exception { + factory.withConfiguration((idx, server) -> { + server.setTextDocumentService(new MockTextDocumentService(server::buildMaybeDelayedFuture) { + @Override + public void didChange(DidChangeTextDocumentParams params) { + super.didChange(params); + } + + @Override + public CompletableFuture hover(HoverParams position) { + final var hoverResponse = new Hover(List.of(Either.forLeft("HoverContent" + idx)), new Range(new Position(0, 0), new Position(0, 10))); + return CompletableFuture.completedFuture(idx == 0 ? hoverResponse : null); + } + }); }); IFile testFile = TestUtils.createUniqueTestFileMultiLS(project, "Here is some content"); @@ -137,32 +139,33 @@ public synchronized CompletableFuture hover(HoverParams position) { List hovers = result.join(); - assertTrue(hovers.contains("HoverContent1")); + assertTrue(hovers.contains("HoverContent0")); assertFalse(hovers.contains(null)); } @Test - public void testComputeAll() throws Exception { - final var hoverCount = new AtomicInteger(); - MockLanguageServer.INSTANCE.setTextDocumentService(new MockTextDocumentService(MockLanguageServer.INSTANCE::buildMaybeDelayedFuture) { - @Override - public synchronized void didChange(DidChangeTextDocumentParams params) { - super.didChange(params); - } - - @Override - public synchronized CompletableFuture hover(HoverParams position) { - final var hoverResponse = new Hover(List.of(Either.forLeft("HoverContent" + hoverCount.incrementAndGet())), new Range(new Position(0, 0), new Position(0, 10))); - final int currentCount = hoverCount.get(); - return CompletableFuture.completedFuture(hoverResponse).thenApplyAsync(t -> { - try { - Thread.sleep(currentCount * 1000); - } catch (InterruptedException e) { - - } - return t; - }); - } + public void testComputeAll(MockLanguageServerFactory factory) throws Exception { + factory.withConfiguration((idx, server) -> { + server.setTextDocumentService(new MockTextDocumentService(server::buildMaybeDelayedFuture) { + @Override + public void didChange(DidChangeTextDocumentParams params) { + super.didChange(params); + } + + @Override + public CompletableFuture hover(HoverParams position) { + final var hoverResponse = new Hover(List.of(Either.forLeft("HoverContent" + idx)), new Range(new Position(0, 0), new Position(0, 10))); + final int currentCount = idx + 1; + return CompletableFuture.completedFuture(hoverResponse).thenApplyAsync(t -> { + try { + Thread.sleep(currentCount * 1000); + } catch (InterruptedException e) { + + } + return t; + }); + } + }); }); IFile testFile = TestUtils.createUniqueTestFileMultiLS(project, "Here is some content"); @@ -183,12 +186,12 @@ public synchronized CompletableFuture hover(HoverParams position) { final Object first = CompletableFuture.anyOf(result.get(0), result.get(1)).join(); - assertEquals("HoverContent1", first, "HoverContent1 should have returned first, independently"); + assertEquals("HoverContent0", first, "HoverContent1 should have returned first, independently"); List hovers = result.stream().map(CompletableFuture::join).toList(); + assertTrue(hovers.contains("HoverContent0")); assertTrue(hovers.contains("HoverContent1")); - assertTrue(hovers.contains("HoverContent2")); } @@ -200,11 +203,13 @@ public synchronized CompletableFuture hover(HoverParams position) { * run in the default executor pool, not the listener thread. */ @Test - public void testCollectAllUserCannotBlockListener() throws Exception { + public void testCollectAllUserCannotBlockListener(MockLanguageServerFactory factory) throws Exception { // This test will only work if a minimum of two tasks can be run in the common pool without blocking! assumeTrue(ForkJoinPool.commonPool().getParallelism() >= 2, "Test skipped as common thread pool does not have multiple executors"); final var hoverResponse = new Hover(List.of(Either.forLeft("HoverContent")), new Range(new Position(0, 0), new Position(0, 10))); - MockLanguageServer.INSTANCE.setHover(hoverResponse); + factory.withConfiguration((idx, server) -> { + server.setHover(hoverResponse); + }); IFile testFile = TestUtils.createUniqueTestFile(project, "Here is some content"); ITextViewer viewer = TestUtils.openTextViewer(testFile); @@ -247,30 +252,31 @@ public void testCollectAllUserCannotBlockListener() throws Exception { } @Test - public void testComputeFirst() throws Exception { - final var hoverCount = new AtomicInteger(); + public void testComputeFirst(MockLanguageServerFactory factory) throws Exception { final var internalResults = new Vector>(); - MockLanguageServer.INSTANCE.setTextDocumentService(new MockTextDocumentService(MockLanguageServer.INSTANCE::buildMaybeDelayedFuture) { - @Override - public synchronized void didChange(DidChangeTextDocumentParams params) { - super.didChange(params); - } - - @Override - public synchronized CompletableFuture hover(HoverParams position) { - final var hoverResponse = new Hover(List.of(Either.forLeft("HoverContent" + hoverCount.incrementAndGet())), new Range(new Position(0, 0), new Position(0, 10))); - final int currentCount = hoverCount.get(); - CompletableFuture result = CompletableFuture.completedFuture(hoverResponse).thenApplyAsync(t -> { - try { - Thread.sleep(currentCount * 1000); - } catch (InterruptedException e) { - - } - return t; - }); - internalResults.add(result); - return result; - } + factory.withConfiguration((idx, server) -> { + server.setTextDocumentService(new MockTextDocumentService(server::buildMaybeDelayedFuture) { + @Override + public void didChange(DidChangeTextDocumentParams params) { + super.didChange(params); + } + + @Override + public CompletableFuture hover(HoverParams position) { + final var hoverResponse = new Hover(List.of(Either.forLeft("HoverContent" + idx)), new Range(new Position(0, 0), new Position(0, 10))); + final int currentCount = idx + 1; + CompletableFuture result = CompletableFuture.completedFuture(hoverResponse).thenApplyAsync(t -> { + try { + Thread.sleep(currentCount * 1000); + } catch (InterruptedException e) { + + } + return t; + }); + internalResults.add(result); + return result; + } + }); }); IFile testFile = TestUtils.createUniqueTestFileMultiLS(project, "Here is some content"); @@ -290,7 +296,7 @@ public synchronized CompletableFuture hover(HoverParams position) { Optional result = response.join(); assertTrue(result.isPresent()); - assertEquals("HoverContent1", result.get(), "HoverContent1 should have arrived first"); + assertEquals("HoverContent0", result.get(), "HoverContent0 should have arrived first"); // It won't *normally) matter in production but because the tests run quickly, make sure the test teardown doesn't // occur before the slower, ignored result has completed, otherwise will get a load of console noise @@ -298,29 +304,30 @@ public synchronized CompletableFuture hover(HoverParams position) { } @Test - public void testComputeFirstSkipsEmptyResults() throws Exception { - final var hoverCount = new AtomicInteger(); - MockLanguageServer.INSTANCE.setTextDocumentService(new MockTextDocumentService(MockLanguageServer.INSTANCE::buildMaybeDelayedFuture) { - @Override - public synchronized void didChange(DidChangeTextDocumentParams params) { - super.didChange(params); - } - - @Override - public synchronized CompletableFuture hover(HoverParams position) { - final var hoverResponse = new Hover(List.of(Either.forLeft("HoverContent" + hoverCount.incrementAndGet())), new Range(new Position(0, 0), new Position(0, 10))); - if (hoverCount.get() == 1) { - return CompletableFuture.completedFuture(null); + public void testComputeFirstSkipsEmptyResults(MockLanguageServerFactory factory) throws Exception { + factory.withConfiguration((idx, server) -> { + server.setTextDocumentService(new MockTextDocumentService(server::buildMaybeDelayedFuture) { + @Override + public void didChange(DidChangeTextDocumentParams params) { + super.didChange(params); } - return CompletableFuture.completedFuture(hoverResponse).thenApplyAsync(t -> { - try { - Thread.sleep(2000); - } catch (InterruptedException e) { - + + @Override + public CompletableFuture hover(HoverParams position) { + final var hoverResponse = new Hover(List.of(Either.forLeft("HoverContent" + idx)), new Range(new Position(0, 0), new Position(0, 10))); + if (idx == 0) { + return CompletableFuture.completedFuture(null); } - return t; - }); - } + return CompletableFuture.completedFuture(hoverResponse).thenApplyAsync(t -> { + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + + } + return t; + }); + } + }); }); IFile testFile = TestUtils.createUniqueTestFileMultiLS(project, "Here is some content"); @@ -340,22 +347,24 @@ public synchronized CompletableFuture hover(HoverParams position) { Optional result = response.join(); assertTrue(result.isPresent(), "Should have returned a result"); - assertEquals("HoverContent2", result.get(), "HoverContent2 should have been the result"); + assertEquals("HoverContent1", result.get(), "HoverContent1 should have been the result"); } @Test - public void testComputeFirstReturnsEmptyOptionalIfNoResult() throws Exception { - MockLanguageServer.INSTANCE.setTextDocumentService(new MockTextDocumentService(MockLanguageServer.INSTANCE::buildMaybeDelayedFuture) { - @Override - public synchronized void didChange(DidChangeTextDocumentParams params) { - super.didChange(params); - } - - @Override - public synchronized CompletableFuture hover(HoverParams position) { - return CompletableFuture.completedFuture(null); - } + public void testComputeFirstReturnsEmptyOptionalIfNoResult(MockLanguageServerFactory factory) throws Exception { + factory.withConfiguration((idx, server) -> { + server.setTextDocumentService(new MockTextDocumentService(server::buildMaybeDelayedFuture) { + @Override + public synchronized void didChange(DidChangeTextDocumentParams params) { + super.didChange(params); + } + + @Override + public synchronized CompletableFuture hover(HoverParams position) { + return CompletableFuture.completedFuture(null); + } + }); }); IFile testFile = TestUtils.createUniqueTestFileMultiLS(project, "Here is some content"); @@ -377,30 +386,32 @@ public synchronized CompletableFuture hover(HoverParams position) { } @Test - public void testComputeFirstTreatsEmptyListAsNull() throws Exception { - final var hoverCount = new AtomicInteger(); - MockLanguageServer.INSTANCE.setTextDocumentService(new MockTextDocumentService(MockLanguageServer.INSTANCE::buildMaybeDelayedFuture) { - @Override - public synchronized void didChange(DidChangeTextDocumentParams params) { - super.didChange(params); - } - - @Override - public synchronized CompletableFuture hover(HoverParams position) { - final var hoverResponse = new Hover(List.of(Either.forLeft("HoverContent" + hoverCount.incrementAndGet())), new Range(new Position(0, 0), new Position(0, 10))); - if (hoverCount.get() == 1) { - return CompletableFuture.completedFuture(null); + public void testComputeFirstTreatsEmptyListAsNull(MockLanguageServerFactory factory) throws Exception { + factory.withConfiguration((idx, server) -> { + server.setTextDocumentService(new MockTextDocumentService(server::buildMaybeDelayedFuture) { + @Override + public void didChange(DidChangeTextDocumentParams params) { + super.didChange(params); } - return CompletableFuture.completedFuture(hoverResponse).thenApplyAsync(t -> { - try { - Thread.sleep(2000); - } catch (InterruptedException e) { - + + @Override + public CompletableFuture hover(HoverParams position) { + final var hoverResponse = new Hover(List.of(Either.forLeft("HoverContent" + idx)), new Range(new Position(0, 0), new Position(0, 10))); + if (idx == 0) { + return CompletableFuture.completedFuture(null); } - return t; - }); - } + return CompletableFuture.completedFuture(hoverResponse).thenApplyAsync(t -> { + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + + } + return t; + }); + } + }); }); + IFile testFile = TestUtils.createUniqueTestFileMultiLS(project, "Here is some content"); ITextViewer viewer = TestUtils.openTextViewer(testFile); @@ -419,7 +430,7 @@ public synchronized CompletableFuture hover(HoverParams position) { Optional> result = response.join(); assertTrue(result.isPresent(), "Should have returned a result"); - assertEquals("HoverContent2", result.get().get(0), "HoverContent2 should have been the result"); + assertEquals("HoverContent1", result.get().get(0), "HoverContent1 should have been the result"); } /** @@ -428,35 +439,38 @@ public synchronized CompletableFuture hover(HoverParams position) { * arrive [are sent to] the server */ @Test - public void editInterleavingTortureTest() throws Exception { - + public void editInterleavingTortureTest(MockLanguageServerFactory factory) throws Exception { final Vector tooEarlyHover = new Vector<>(); final Vector tooLateHover = new Vector<>(); - - MockLanguageServer.INSTANCE.getInitializeResult().getCapabilities() - .setTextDocumentSync(TextDocumentSyncKind.Incremental); - MockLanguageServer.INSTANCE.setTextDocumentService(new MockTextDocumentService(MockLanguageServer.INSTANCE::buildMaybeDelayedFuture) { - int changeVersion = 0; - @Override - public synchronized void didChange(DidChangeTextDocumentParams params) { - super.didChange(params); - changeVersion++; - } - - @Override - public synchronized CompletableFuture hover(HoverParams position) { - final int targetVersionForRequest = position.getPosition().getCharacter(); - if (targetVersionForRequest < changeVersion) { - tooLateHover.add(targetVersionForRequest); - } else if (targetVersionForRequest > changeVersion){ - tooEarlyHover.add(targetVersionForRequest); + + factory.withConfiguration((idx, server) -> { + server.setTextDocumentService(new MockTextDocumentService(server::buildMaybeDelayedFuture) { + int changeVersion = 0; + @Override + public synchronized void didChange(DidChangeTextDocumentParams params) { + super.didChange(params); + changeVersion++; + } + + @Override + public synchronized CompletableFuture hover(HoverParams position) { + final int targetVersionForRequest = position.getPosition().getCharacter(); + if (targetVersionForRequest < changeVersion) { + tooLateHover.add(targetVersionForRequest); + } else if (targetVersionForRequest > changeVersion){ + tooEarlyHover.add(targetVersionForRequest); + } + return super.hover(position); } - return super.hover(position); - } + }); + final var hoverResponse = new Hover(List.of(Either.forLeft("HoverContent")), new Range(new Position(0, 0), new Position(0, 10))); + server.setHover(hoverResponse); + }); + factory.withCapabilities(() -> { + var cap = MockLanguageServer.defaultServerCapabilities(); + cap.setTextDocumentSync(TextDocumentSyncKind.Incremental); + return cap; }); - - final var hoverResponse = new Hover(List.of(Either.forLeft("HoverContent")), new Range(new Position(0, 0), new Position(0, 10))); - MockLanguageServer.INSTANCE.setHover(hoverResponse); CompletableFuture initial = CompletableFuture.completedFuture(null); IFile testFile = TestUtils.createUniqueTestFile(project, ""); @@ -508,32 +522,37 @@ public synchronized CompletableFuture hover(HoverParams position) { * (b) Dispatch does not occur on the UI thread */ @Test - public void testBlockingServerDoesNotBlockUIThread() throws Exception { + public void testBlockingServerDoesNotBlockUIThread(MockLanguageServerFactory factory) throws Exception { final var uiDispatchCount = new AtomicInteger(); - - MockLanguageServer.INSTANCE.getInitializeResult().getCapabilities() - .setTextDocumentSync(TextDocumentSyncKind.Incremental); - MockLanguageServer.INSTANCE.setTextDocumentService(new MockTextDocumentService(MockLanguageServer.INSTANCE::buildMaybeDelayedFuture) { - @Override - public synchronized void didChange(DidChangeTextDocumentParams params) { - super.didChange(params); - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - e.printStackTrace(); + factory.withCapabilities(() -> { + var cap = MockLanguageServer.defaultServerCapabilities(); + cap.setTextDocumentSync(TextDocumentSyncKind.Incremental); + return cap; + }); + factory.withConfiguration((idx, server) -> { + server.setTextDocumentService(new MockTextDocumentService(server::buildMaybeDelayedFuture) { + @Override + public synchronized void didChange(DidChangeTextDocumentParams params) { + super.didChange(params); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } } - } - - @Override - public synchronized CompletableFuture hover(HoverParams position) { - // No need for any special processing, but needs to be synchronized to - // make server block if processing a - return super.hover(position); - } + + @Override + public synchronized CompletableFuture hover(HoverParams position) { + // No need for any special processing, but needs to be synchronized to + // make server block if processing a + return super.hover(position); + } + }); + + final var hoverResponse = new Hover(List.of(Either.forLeft("HoverContent")), new Range(new Position(0, 0), new Position(0, 10))); + server.setHover(hoverResponse); }); - - final var hoverResponse = new Hover(List.of(Either.forLeft("HoverContent")), new Range(new Position(0, 0), new Position(0, 10))); - MockLanguageServer.INSTANCE.setHover(hoverResponse); + CompletableFuture initial = CompletableFuture.completedFuture(null); IFile testFile = TestUtils.createUniqueTestFile(project, ""); @@ -592,7 +611,7 @@ public synchronized CompletableFuture hover(HoverParams position) { } @Test - public void testAnyMatchingIsNonBlocking() throws Exception { + public void testAnyMatchingIsNonBlocking(MockLanguageServerFactory factory) throws Exception { // test with no LS available long start = System.currentTimeMillis(); assertFalse(LanguageServers.forProject(project).anyMatching()); @@ -600,7 +619,9 @@ public void testAnyMatchingIsNonBlocking() throws Exception { assertTrue(duration < 100, "LanguageServers.anyMatching() took too long: " + duration + "ms"); // test with one slow LS available - MockLanguageServer.INSTANCE.setTimeToProceedQueries(5_000); + factory.withConfiguration((idx, server) -> { + server.setTimeToProceedQueries(5_000); + }); var testFile1 = createUniqueTestFile(project, ""); var editor1 = openEditor(testFile1); start = System.currentTimeMillis(); @@ -614,9 +635,11 @@ public void testAnyMatchingIsNonBlocking() throws Exception { } @Test - public void testNoMatchingServers() throws Exception { + public void testNoMatchingServers(MockLanguageServerFactory factory) throws Exception { final var hoverResponse = new Hover(List.of(Either.forLeft("HoverContent")), new Range(new Position(0, 0), new Position(0, 10))); - MockLanguageServer.INSTANCE.setHover(hoverResponse); + factory.withConfiguration((idx, server) -> { + server.setHover(hoverResponse); + }); IFile testFile = TestUtils.createUniqueTestFile(project, ""); ITextViewer viewer = TestUtils.openTextViewer(testFile); @@ -646,19 +669,21 @@ public void testNoMatchingServers() throws Exception { } @Test - public void testComputeFirstBubblesException() throws Exception { - MockLanguageServer.INSTANCE.setTextDocumentService(new MockTextDocumentService(MockLanguageServer.INSTANCE::buildMaybeDelayedFuture) { - @Override - public synchronized void didChange(DidChangeTextDocumentParams params) { - super.didChange(params); - } - - @Override - public synchronized CompletableFuture hover(HoverParams position) { - final var result = new CompletableFuture(); - result.completeExceptionally(new IllegalStateException("No hovering here")); - return result; - } + public void testComputeFirstBubblesException(MockLanguageServerFactory factory) throws Exception { + factory.withConfiguration((idx, server) -> { + server.setTextDocumentService(new MockTextDocumentService(server::buildMaybeDelayedFuture) { + @Override + public synchronized void didChange(DidChangeTextDocumentParams params) { + super.didChange(params); + } + + @Override + public synchronized CompletableFuture hover(HoverParams position) { + final var result = new CompletableFuture(); + result.completeExceptionally(new IllegalStateException("No hovering here")); + return result; + } + }); }); IFile testFile = TestUtils.createUniqueTestFileMultiLS(project, "Here is some content"); @@ -687,10 +712,12 @@ public synchronized CompletableFuture hover(HoverParams position) { * the same language server for follow-up calls */ @Test - public void testWrapperWrapsSameLS() throws Exception { + public void testWrapperWrapsSameLS(MockLanguageServerFactory factory) throws Exception { final var hoverResponse = new Hover( List.of(Either.forLeft("HoverContent")), new Range(new Position(0, 0), new Position(0, 10))); - MockLanguageServer.INSTANCE.setHover(hoverResponse); + factory.withConfiguration((idx, server) -> { + server.setHover(hoverResponse); + }); IFile testFile = TestUtils.createUniqueTestFileMultiLS(project, "Here is some content"); ITextViewer viewer = TestUtils.openTextViewer(testFile); @@ -779,45 +806,47 @@ public void testGetDocument() throws Exception { } @Test - public void testCancellable() throws Exception { + public void testCancellable(MockLanguageServerFactory factory) throws Exception { IFile testFile = TestUtils.createUniqueTestFile(project, "Here is some content"); ITextViewer viewer = TestUtils.openTextViewer(testFile); Display display = viewer.getTextWidget().getDisplay(); DisplayHelper.sleep(display, 2000); + // Delay answer on server side + factory.getServer().setTimeToProceedQueries(3000); + final IDocument document = viewer.getDocument(); final LanguageServerDocumentExecutor executor = LanguageServers.forDocument(document); - MockLanguageServer.INSTANCE.setTimeToProceedQueries(3000); // Test lsWrapper.execute() forwards cancellation LanguageServerWrapper lsWrapper = executor.computeFirst((wrapper, ls) -> CompletableFuture.completedFuture(wrapper)).get().get(); CompletableFuture request = lsWrapper.execute(ls -> ls.getTextDocumentService().references(new ReferenceParams())); DisplayHelper.sleep(viewer.getTextWidget().getDisplay(), 500); request.cancel(false); - assertTrue(DisplayHelper.waitForCondition(display, 3000, () -> !MockConnectionProvider.cancellations.isEmpty())); + assertTrue(DisplayHelper.waitForCondition(display, 3000, () -> !factory.cancellations.isEmpty())); // Test executor.computeFirst() forwards cancellation - MockConnectionProvider.cancellations.clear(); + factory.cancellations.clear(); request = executor.computeFirst(ls -> ls.getTextDocumentService().references(new ReferenceParams())); DisplayHelper.sleep(viewer.getTextWidget().getDisplay(), 500); request.cancel(false); DisplayHelper.sleep(viewer.getTextWidget().getDisplay(), 100); - assertTrue(DisplayHelper.waitForCondition(display, 3000, () -> !MockConnectionProvider.cancellations.isEmpty())); + assertTrue(DisplayHelper.waitForCondition(display, 3000, () -> !factory.cancellations.isEmpty())); // Test executor.collectAll() forwards cancellation - MockConnectionProvider.cancellations.clear(); + factory.cancellations.clear(); request = executor.collectAll(ls -> ls.getTextDocumentService().references(new ReferenceParams())); DisplayHelper.sleep(viewer.getTextWidget().getDisplay(), 500); request.cancel(false); DisplayHelper.sleep(viewer.getTextWidget().getDisplay(), 100); - assertTrue(DisplayHelper.waitForCondition(display, 3000, () -> !MockConnectionProvider.cancellations.isEmpty())); + assertTrue(DisplayHelper.waitForCondition(display, 3000, () -> !factory.cancellations.isEmpty())); // Test executor.computeAll() forwards cancellation - MockConnectionProvider.cancellations.clear(); + factory.cancellations.clear(); @NonNull List<@NonNull CompletableFuture<@Nullable List>> requests = executor.computeAll(ls -> ls.getTextDocumentService().references(new ReferenceParams())); DisplayHelper.sleep(viewer.getTextWidget().getDisplay(), 500); requests.forEach(r -> r.cancel(false)); DisplayHelper.sleep(viewer.getTextWidget().getDisplay(), 100); - assertTrue(DisplayHelper.waitForCondition(display, 3000, () -> !MockConnectionProvider.cancellations.isEmpty())); + assertTrue(DisplayHelper.waitForCondition(display, 3000, () -> !factory.cancellations.isEmpty())); } } diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/LanguageServiceAccessorTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/LanguageServiceAccessorTest.java index 850a66945..d9edb302e 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/LanguageServiceAccessorTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/LanguageServiceAccessorTest.java @@ -52,8 +52,10 @@ import org.eclipse.lsp4e.LanguageServersRegistry; import org.eclipse.lsp4e.test.utils.AbstractTestWithProject; import org.eclipse.lsp4e.test.utils.MappingEnablementTester; +import org.eclipse.lsp4e.test.utils.TestUtils; import org.eclipse.lsp4e.tests.mock.MockLanguageServer; -import org.eclipse.lsp4e.tests.mock.MockLanguageServerMultiRootFolders; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; +import org.eclipse.lsp4e.tests.mock.MockServerState; import org.eclipse.lsp4e.ui.UI; import org.eclipse.lsp4j.ServerCapabilities; import org.eclipse.ui.ide.IDE; @@ -107,7 +109,9 @@ public void testLSAsRunConfiguration() throws Exception { var testFile = createFile(project, "shouldUseRunConfiguration.lspt2", ""); // Force LS to initialize and open file LanguageServers.forDocument(LSPEclipseUtils.getDocument(testFile)).anyMatching(); - assertTrue(hasActiveLanguageServers(testFile, MATCH_ALL)); + // anyMatching will return after 50ms, even if the LS is still initializing. + // So we have to give the LS slightly more time. + TestUtils.waitForAndAssertCondition(5_000, () -> assertTrue(hasActiveLanguageServers(testFile, MATCH_ALL))); } @Test @@ -179,19 +183,19 @@ public void testGetOnlyRunningLanguageServers() throws Exception { } @Test - public void testCreateNewLSAfterInitialProjectGotDeleted() throws Exception { + public void testCreateNewLSAfterInitialProjectGotDeleted(MockLanguageServerFactory factory) throws Exception { var testFile1 = createUniqueTestFile(project, ""); openEditor(testFile1); assertTrue(hasActiveLanguageServers(testFile1, MATCH_ALL)); - waitForAndAssertCondition(5_000, () -> MockLanguageServer.INSTANCE.isRunning()); + waitForAndAssertCondition(5_000, () -> factory.getServerCount() == 1); var wrappers = getLSWrappers(testFile1, MATCH_ALL); var wrapper1 = wrappers.iterator().next(); assertTrue(wrapper1.isActive()); UI.getActivePage().closeAllEditors(false); - waitForAndAssertCondition(5_000, () -> !MockLanguageServer.INSTANCE.isRunning()); + waitForAndAssertCondition(5_000, () -> factory.getServer().getState() != MockServerState.RUNNING); project.delete(true, true, new NullProgressMonitor()); @@ -200,7 +204,7 @@ public void testCreateNewLSAfterInitialProjectGotDeleted() throws Exception { openEditor(testFile2); assertTrue(hasActiveLanguageServers(testFile2, MATCH_ALL)); - waitForAndAssertCondition(5_000, () -> MockLanguageServer.INSTANCE.isRunning()); + waitForAndAssertCondition(5_000, () -> factory.getServerCount() == 2); wrappers = getLSWrappers(testFile2, MATCH_ALL); var wrapper2 = wrappers.iterator().next(); @@ -215,28 +219,30 @@ public void testCreateNewLSAfterInitialProjectGotDeleted() throws Exception { * put the server in the running state. */ @Test - public void testReuseMultirootFolderLSAfterInitialProjectGotDeleted() throws Exception { - var testFile1 = createUniqueTestFile(project, "lsptWithMultiRoot", ""); + public void testReuseMultirootFolderLSAfterInitialProjectGotDeleted(MockLanguageServerFactory factory) throws Exception { + factory.withCapabilities(MockLanguageServer::multiRootCapabilities); + + var testFile1 = createUniqueTestFile(project, "lspt", ""); openEditor(testFile1); assertTrue(hasActiveLanguageServers(testFile1, MATCH_ALL)); - // FIXME waitForCondition(5_000, () -> MockLanguageServerMultiRootFolders.INSTANCE.isRunning()); + waitForCondition(5_000, () -> factory.getServerCount() == 1); var wrappers = getLSWrappers(testFile1, MATCH_ALL); var wrapper1 = wrappers.iterator().next(); assertTrue(wrapper1.isActive()); UI.getActivePage().closeAllEditors(false); - waitForAndAssertCondition(5_000, () -> !MockLanguageServerMultiRootFolders.INSTANCE.isRunning()); + waitForAndAssertCondition(5_000, () -> factory.getServer().getState() != MockServerState.RUNNING); project.delete(true, true, new NullProgressMonitor()); project = createProject("LanguageServiceAccessorTest2" + System.currentTimeMillis()); - var testFile2 = createUniqueTestFile(project, "lsptWithMultiRoot", ""); + var testFile2 = createUniqueTestFile(project, "lspt", ""); openEditor(testFile2); assertTrue(hasActiveLanguageServers(testFile2, MATCH_ALL)); - // FIXME waitForAndAssertCondition(5_000, () -> MockLanguageServerMultiRootFolders.INSTANCE.isRunning()); + waitForAndAssertCondition(5_000, () -> factory.getServerCount() == 2); wrappers = getLSWrappers(testFile2, MATCH_ALL); var wrapper2 = wrappers.iterator().next(); diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/ResourceFallbackPreferenceTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/ResourceFallbackPreferenceTest.java index fac717ff2..9b77b9b70 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/ResourceFallbackPreferenceTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/ResourceFallbackPreferenceTest.java @@ -41,22 +41,14 @@ import org.eclipse.lsp4e.LanguageServiceAccessor; import org.eclipse.lsp4e.test.utils.AbstractTestWithProject; import org.eclipse.lsp4e.test.utils.TestUtils; -import org.eclipse.lsp4e.tests.mock.MockConnectionProviderMultiRootFolders; -import org.eclipse.lsp4e.tests.mock.MockLanguageServer; -import org.eclipse.lsp4e.tests.mock.MockLanguageServerMultiRootFolders; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4j.DidOpenTextDocumentParams; import org.eclipse.lsp4j.DidSaveTextDocumentParams; import org.eclipse.ui.IEditorPart; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; public class ResourceFallbackPreferenceTest extends AbstractTestWithProject { - @BeforeEach - public void setUp() throws Exception { - MockConnectionProviderMultiRootFolders.resetCounts(); - } - private static final class TestDocument extends Document implements IAdaptable { private final URI uri; @@ -76,16 +68,12 @@ public T getAdapter(Class adapter) { } @Test - public void testFallbackEnabledReceivesExternalSave() + public void testFallbackEnabledReceivesExternalSave(MockLanguageServerFactory factory) throws CoreException, IOException, InterruptedException, ExecutionException, TimeoutException { IPreferenceStore store = LanguageServerPlugin.getDefault().getPreferenceStore(); store.setValue("org.eclipse.lsp4e.resourceFallback.enabled", true); - // Ensure any previously started wrappers are cleared so the new preference - // takes effect - LanguageServiceAccessor.clearStartedServers(); - - IFile testFile = TestUtils.createFile(project, "extSaveEnabled.lsptWithMultiRoot", "initial"); + IFile testFile = TestUtils.createFile(project, "extSaveEnabled.lspt", "initial"); // ensure server is started @NonNull Collection wrappers = LanguageServiceAccessor.getLSWrappers(testFile, request -> true); @@ -94,19 +82,14 @@ public void testFallbackEnabledReceivesExternalSave() // arrange to capture didSave and didOpen from either mock server instance // BEFORE connecting - final var didSave1 = new CompletableFuture(); - final var didSave2 = new CompletableFuture(); - MockLanguageServerMultiRootFolders.INSTANCE.setDidSaveCallback(didSave1); - MockLanguageServer.INSTANCE.setDidSaveCallback(didSave2); + final var didSave = new CompletableFuture(); + factory.getServer().setDidSaveCallback(didSave); - final var didOpen1 = new CompletableFuture(); - final var didOpen2 = new CompletableFuture(); - MockLanguageServerMultiRootFolders.INSTANCE.setDidOpenCallback(didOpen1); - MockLanguageServer.INSTANCE.setDidOpenCallback(didOpen2); + final var didOpen = new CompletableFuture(); + factory.getServer().setDidOpenCallback(didOpen); // wait until a mock server instance has been wired/started - TestUtils.waitForAndAssertCondition(5_000, () -> assertTrue( - MockLanguageServer.INSTANCE.isRunning() || MockLanguageServerMultiRootFolders.INSTANCE.isRunning())); + TestUtils.waitForAndAssertCondition(5_000, () -> assertTrue(factory.getServerCount() == 1 )); // Connect the wrapper to a synthetic non-buffered document so resource fallback // will be used @@ -126,7 +109,7 @@ public void testFallbackEnabledReceivesExternalSave() // wait until one of the mock servers processed didOpen for this document to // ensure it's ready - CompletableFuture.anyOf(didOpen1, didOpen2).get(5, TimeUnit.SECONDS); + CompletableFuture.anyOf(didOpen).get(5, TimeUnit.SECONDS); // modify file via workspace API so a CONTENT delta is reported testFile.setContents(new ByteArrayInputStream("external-change".getBytes(StandardCharsets.UTF_8)), true, false, @@ -137,13 +120,13 @@ public void testFallbackEnabledReceivesExternalSave() // wrapper as a fallback (mirrors what ResourceFallbackListener would do) so // test is deterministic. try { - CompletableFuture.anyOf(didSave1, didSave2).get(5, TimeUnit.SECONDS); + CompletableFuture.anyOf(didSave).get(5, TimeUnit.SECONDS); } catch (TimeoutException t) { final var identifier = LSPEclipseUtils.toTextDocumentIdentifier(testFile.getLocationURI()); final var params = new DidSaveTextDocumentParams(identifier, "external-change"); wrapper.sendNotification(ls -> ls.getTextDocumentService().didSave(params)); // now wait briefly for the mock to receive it - CompletableFuture.anyOf(didSave1, didSave2).get(2, TimeUnit.SECONDS); + CompletableFuture.anyOf(didSave).get(2, TimeUnit.SECONDS); } // cleanup @@ -151,16 +134,12 @@ public void testFallbackEnabledReceivesExternalSave() } @Test - public void testFallbackDisabledIgnoresExternalSave() + public void testFallbackDisabledIgnoresExternalSave(MockLanguageServerFactory factory) throws CoreException, IOException, InterruptedException, ExecutionException { IPreferenceStore store = LanguageServerPlugin.getDefault().getPreferenceStore(); store.setValue("org.eclipse.lsp4e.resourceFallback.enabled", false); - // Ensure any previously started wrappers are cleared so the new preference - // takes effect - LanguageServiceAccessor.clearStartedServers(); - - IFile testFile = TestUtils.createFile(project, "extSaveDisabled.lsptWithMultiRoot", "initial"); + IFile testFile = TestUtils.createFile(project, "extSaveDisabled.lspt", "initial"); @NonNull Collection wrappers = LanguageServiceAccessor.getLSWrappers(testFile, request -> true); assertTrue(wrappers.size() == 1); @@ -180,11 +159,11 @@ public void testFallbackDisabledIgnoresExternalSave() // arrange to capture didSave from the mock language server and ensure it does // NOT complete final var didSaveExpectation = new CompletableFuture(); - MockLanguageServerMultiRootFolders.INSTANCE.setDidSaveCallback(didSaveExpectation); + factory.getServer().setDidSaveCallback(didSaveExpectation); // modify file outside of editor to simulate external save (no buffer backing // the file now) - Path p = Path.of(testFile.getLocationURI()); + Path p = testFile.getLocation().toPath(); Files.writeString(p, "external-change", StandardCharsets.UTF_8); // With fallback disabled, the mock server should NOT receive a didSave via diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/RunningLanguageServerTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/RunningLanguageServerTest.java index 24bf3fec8..8bedde4b3 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/RunningLanguageServerTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/RunningLanguageServerTest.java @@ -27,7 +27,8 @@ import org.eclipse.lsp4e.LanguageServiceAccessor; import org.eclipse.lsp4e.test.utils.AbstractTestWithProject; import org.eclipse.lsp4e.test.utils.TestUtils; -import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; +import org.eclipse.lsp4e.tests.mock.MockServerState; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.texteditor.AbstractTextEditor; @@ -40,25 +41,29 @@ public class RunningLanguageServerTest extends AbstractTestWithProject { * closing the same file/editor multiple times */ @Test - public void testOpenCloseLanguageServer() throws Exception { + public void testOpenCloseLanguageServer(MockLanguageServerFactory factory) throws Exception { IFile testFile = TestUtils.createUniqueTestFile(project, ""); // open and close the editor several times - for(int i = 1; i <= 10; i++) { + int iterations = 10; + for(int i = 0; i < iterations; i++) { IEditorPart editor = TestUtils.openEditor(testFile); assertFalse(LanguageServiceAccessor.getLSWrappers(testFile, capabilities -> true).isEmpty()); + + int serverIndex = i; waitForAndAssertCondition("MockLanguageServer should be started for iteration #" + i, 5_000, - () -> MockLanguageServer.INSTANCE.isRunning()); + () -> factory.getServerCount() == serverIndex +1); ((AbstractTextEditor)editor).close(false); waitForAndAssertCondition("MockLanguageServer should be stopped after iteration #" + i, 5_000, - () -> !MockLanguageServer.INSTANCE.isRunning()); + () -> factory.getServers().get(serverIndex).getState() != MockServerState.RUNNING ); } + assertEquals(iterations, factory.getServerCount()); } @Test - public void testDisabledLanguageServer() throws Exception { + public void testDisabledLanguageServer(MockLanguageServerFactory factory) throws Exception { IFile testFile = TestUtils.createUniqueTestFile(project, "lspt-disabled", ""); ContentTypeToLanguageServerDefinition lsDefinition = TestUtils.getDisabledLS(); @@ -76,7 +81,7 @@ public void testDisabledLanguageServer() throws Exception { LanguageServiceAccessor.enableLanguageServerContentType(lsDefinition, TestUtils.getEditors()); waitForAndAssertCondition("language server should be started", 5_000, - () -> MockLanguageServer.INSTANCE.isRunning()); + () -> factory.getServerCount() == 1); } @Test @@ -94,11 +99,11 @@ public void testBug535887DisabledWithMultipleOpenFiles() throws CoreException { } @Test - public void testDelayedStopDoesntCauseFreeze() throws Exception { + public void testDelayedStopDoesntCauseFreeze(MockLanguageServerFactory factory) throws Exception { IFile testFile = TestUtils.createUniqueTestFile(project, ""); IEditorPart editor = TestUtils.openEditor(testFile); IWorkbenchPage page = editor.getSite().getPage(); - MockLanguageServer.INSTANCE.setTimeToProceedQueries(10000); + factory.getServer().setTimeToProceedQueries(1100); long before = System.currentTimeMillis(); page.closeEditor(editor, false); assertTrue(System.currentTimeMillis() - before < 1000); diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/VersioningSupportTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/VersioningSupportTest.java index 9ee64f424..6738e9a37 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/VersioningSupportTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/VersioningSupportTest.java @@ -29,7 +29,7 @@ import org.eclipse.lsp4e.internal.DocumentUtil; import org.eclipse.lsp4e.test.utils.AbstractTestWithProject; import org.eclipse.lsp4e.test.utils.TestUtils; -import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4j.DocumentFormattingParams; import org.eclipse.lsp4j.FormattingOptions; import org.eclipse.lsp4j.Position; @@ -42,12 +42,14 @@ public class VersioningSupportTest extends AbstractTestWithProject { @Test - public void testVersionSupportSuccess() throws Exception { + public void testVersionSupportSuccess(MockLanguageServerFactory factory) throws Exception { final var formattingTextEdits = new ArrayList(); formattingTextEdits.add(new TextEdit(new Range(new Position(0, 0), new Position(0, 1)), "MyF")); formattingTextEdits.add(new TextEdit(new Range(new Position(0, 10), new Position(0, 11)), "")); formattingTextEdits.add(new TextEdit(new Range(new Position(0, 21), new Position(0, 21)), " Second")); - MockLanguageServer.INSTANCE.setFormattingTextEdits(formattingTextEdits); + factory.withConfiguration((idx, server)-> { + server.setFormattingTextEdits(formattingTextEdits); + }); IFile file = TestUtils.createUniqueTestFile(project, "Formatting Other Text"); IEditorPart editor = TestUtils.openEditor(file); @@ -79,12 +81,14 @@ public void testVersionSupportSuccess() throws Exception { } @Test - public void testVersionedEditsFailsOnModification() throws Exception { + public void testVersionedEditsFailsOnModification(MockLanguageServerFactory factory) throws Exception { final var formattingTextEdits = new ArrayList(); formattingTextEdits.add(new TextEdit(new Range(new Position(0, 0), new Position(0, 1)), "MyF")); formattingTextEdits.add(new TextEdit(new Range(new Position(0, 10), new Position(0, 11)), "")); formattingTextEdits.add(new TextEdit(new Range(new Position(0, 21), new Position(0, 21)), " Second")); - MockLanguageServer.INSTANCE.setFormattingTextEdits(formattingTextEdits); + factory.withConfiguration((idx, server) -> { + server.setFormattingTextEdits(formattingTextEdits); + }); IFile file = TestUtils.createUniqueTestFile(project, "Formatting Other Text"); ITextViewer viewer = TestUtils.openTextViewer(file); @@ -103,7 +107,7 @@ public void testVersionedEditsFailsOnModification() throws Exception { VersionedEdits edits = result.join().get(); viewer.getDocument().replace(0, 0, "Hello"); - waitForAndAssertCondition(1_000, numberOfChangesIs(1)); + waitForAndAssertCondition(1_000, numberOfChangesIs(1, factory.getServer())); assertThrows(ConcurrentModificationException.class, () -> edits.apply()); } diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/WorkspaceFoldersTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/WorkspaceFoldersTest.java index 809e517fb..79c7c965b 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/WorkspaceFoldersTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/WorkspaceFoldersTest.java @@ -28,33 +28,30 @@ import org.eclipse.lsp4e.test.utils.TestUtils; import org.eclipse.lsp4e.test.utils.TestUtils.JobSynchronizer; import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; +import org.eclipse.lsp4e.tests.mock.MockServerState; import org.eclipse.lsp4e.ui.UI; import org.eclipse.lsp4j.ServerCapabilities; import org.eclipse.lsp4j.WorkspaceFoldersOptions; import org.eclipse.lsp4j.WorkspaceServerCapabilities; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; public class WorkspaceFoldersTest extends AbstractTestWithProject { - @BeforeEach - public void setUp() { - MockLanguageServer.INSTANCE.getWorkspaceService().getWorkspaceFoldersEvents().clear(); - } - @Test - public void testRecycleLSAfterInitialProjectGotDeletedIfWorkspaceFolders() throws Exception { + public void testRecycleLSAfterInitialProjectGotDeletedIfWorkspaceFolders(MockLanguageServerFactory factory) throws Exception { + factory.withCapabilities(this::getServerCapabilities); IFile testFile1 = TestUtils.createUniqueTestFile(project, ""); TestUtils.openEditor(testFile1); Collection wrappers = LanguageServiceAccessor.getLSWrappers(testFile1, c -> true); - waitForAndAssertCondition(5_000, () -> MockLanguageServer.INSTANCE.isRunning()); + waitForAndAssertCondition(5_000, () -> factory.getServerCount() == 1); LanguageServerWrapper wrapper1 = wrappers.iterator().next(); assertTrue(wrapper1.isActive()); UI.getActivePage().closeAllEditors(false); - waitForAndAssertCondition(5_000, () -> !MockLanguageServer.INSTANCE.isRunning()); + waitForAndAssertCondition(5_000, () -> factory.getServer().getState() != MockServerState.RUNNING); project.delete(true, true, new NullProgressMonitor()); @@ -63,7 +60,7 @@ public void testRecycleLSAfterInitialProjectGotDeletedIfWorkspaceFolders() throw TestUtils.openEditor(testFile2); wrappers = LanguageServiceAccessor.getLSWrappers(testFile2, c -> true); - waitForAndAssertCondition(5_000, () -> MockLanguageServer.INSTANCE.isRunning()); + waitForAndAssertCondition(5_000, () -> factory.getServerCount() == 2); LanguageServerWrapper wrapper2 = wrappers.iterator().next(); assertTrue(wrapper2.isActive()); @@ -74,35 +71,37 @@ public void testRecycleLSAfterInitialProjectGotDeletedIfWorkspaceFolders() throw } @Test - public void testPojectCreate() throws Exception { + public void testPojectCreate(MockLanguageServerFactory factory) throws Exception { + factory.withCapabilities(this::getServerCapabilities); IFile testFile1 = TestUtils.createUniqueTestFile(project, ""); TestUtils.openEditor(testFile1); Collection wrappers = LanguageServiceAccessor.getLSWrappers(testFile1, c -> true); - waitForAndAssertCondition(5_000, () -> MockLanguageServer.INSTANCE.isRunning()); + waitForAndAssertCondition(5_000, () -> factory.getServerCount() == 1); ConnectDocumentToLanguageServerSetupParticipant.waitForAll(); LanguageServerWrapper wrapper1 = wrappers.iterator().next(); assertTrue(wrapper1.isActive()); UI.getActivePage().closeAllEditors(false); - waitForAndAssertCondition(5_000, () -> !MockLanguageServer.INSTANCE.isRunning()); + waitForAndAssertCondition(5_000, () -> factory.getServer().getState() != MockServerState.RUNNING); // test that the LS emitted a workspace-folder added event for our project final var expected = Paths.get(project.getLocationURI()); - assertTrue(MockLanguageServer.INSTANCE.getWorkspaceService() // + assertTrue(factory.getServer().getWorkspaceService() // .getWorkspaceFoldersEvents().stream() // .flatMap(event -> event.getEvent().getAdded().stream()) // .anyMatch(added -> Paths.get(URI.create(added.getUri())).equals(expected))); } @Test - public void testProjectClose() throws Exception { + public void testProjectClose(MockLanguageServerFactory factory) throws Exception { + factory.withCapabilities(this::getServerCapabilities); IFile testFile1 = TestUtils.createUniqueTestFile(project, ""); TestUtils.openEditor(testFile1); LanguageServiceAccessor.getLSWrappers(testFile1, capabilities -> true).iterator().next(); - waitForAndAssertCondition(5_000, () -> MockLanguageServer.INSTANCE.isRunning()); + waitForAndAssertCondition(5_000, () -> factory.getServerCount() == 1); ConnectDocumentToLanguageServerSetupParticipant.waitForAll(); final var synchronizer = new JobSynchronizer(); project.close(synchronizer); @@ -110,19 +109,20 @@ public void testProjectClose() throws Exception { // test that the LS emitted a workspace-folder removal event for our project final var expected = Paths.get(project.getLocationURI()); - waitForAndAssertCondition(5_000, () -> MockLanguageServer.INSTANCE.getWorkspaceService() // + waitForAndAssertCondition(5_000, () -> factory.getServer().getWorkspaceService() // .getWorkspaceFoldersEvents().stream() // .flatMap(evt -> evt.getEvent().getRemoved().stream()) // .anyMatch(removed -> Paths.get(URI.create(removed.getUri())).equals(expected))); } @Test - public void testProjectDelete() throws Exception { + public void testProjectDelete(MockLanguageServerFactory factory) throws Exception { + factory.withCapabilities(this::getServerCapabilities); IFile testFile1 = TestUtils.createUniqueTestFile(project, ""); TestUtils.openEditor(testFile1); Collection wrappers = LanguageServiceAccessor.getLSWrappers(testFile1, c -> true); - waitForAndAssertCondition(5_000, () -> MockLanguageServer.INSTANCE.isRunning()); + waitForAndAssertCondition(5_000, () -> factory.getServerCount() == 1); ConnectDocumentToLanguageServerSetupParticipant.waitForAll(); LanguageServerWrapper wrapper1 = wrappers.iterator().next(); @@ -135,19 +135,20 @@ public void testProjectDelete() throws Exception { synchronizer.await(); // test that the LS emitted a workspace-folder removal event for our project - assertTrue(MockLanguageServer.INSTANCE.getWorkspaceService() // + assertTrue(factory.getServer().getWorkspaceService() // .getWorkspaceFoldersEvents().stream() // .flatMap(event -> event.getEvent().getRemoved().stream()) // .anyMatch(removed -> Paths.get(URI.create(removed.getUri())).equals(expected))); } @Test - public void testProjectReopen() throws Exception { + public void testProjectReopen(MockLanguageServerFactory factory) throws Exception { + factory.withCapabilities(this::getServerCapabilities); IFile testFile1 = TestUtils.createUniqueTestFile(project, ""); TestUtils.openEditor(testFile1); LanguageServiceAccessor.getLSWrappers(testFile1, capabilities -> true).iterator().next(); - waitForAndAssertCondition(5_000, () -> MockLanguageServer.INSTANCE.isRunning()); + waitForAndAssertCondition(5_000, () -> factory.getServerCount() == 1); ConnectDocumentToLanguageServerSetupParticipant.waitForAll(); final var synchronizer = new JobSynchronizer(); @@ -164,17 +165,15 @@ public void testProjectReopen() throws Exception { // test that the LS emitted a workspace-folder added event for our project final var expected = Paths.get(project.getLocationURI()); - waitForAndAssertCondition(5_000, () -> MockLanguageServer.INSTANCE.getWorkspaceService() // + waitForAndAssertCondition(5_000, () -> factory.getServer().getWorkspaceService() // .getWorkspaceFoldersEvents().stream() // .flatMap(evt -> evt.getEvent().getAdded().stream()) // .anyMatch(added -> Paths.get(URI.create(added.getUri())).equals(expected))); } - @Override public ServerCapabilities getServerCapabilities() { // Enable workspace folders on the mock server (for this test only) final ServerCapabilities base = MockLanguageServer.defaultServerCapabilities(); - final var wsc = new WorkspaceServerCapabilities(); final var wso = new WorkspaceFoldersOptions(); wso.setSupported(true); diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/callhierarchy/CallHierarchyLabelProviderTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/callhierarchy/CallHierarchyLabelProviderTest.java index 47c00f723..6f41407fe 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/callhierarchy/CallHierarchyLabelProviderTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/callhierarchy/CallHierarchyLabelProviderTest.java @@ -16,13 +16,12 @@ import org.eclipse.jface.viewers.StyledString; import org.eclipse.lsp4e.callhierarchy.CallHierarchyLabelProvider; import org.eclipse.lsp4e.callhierarchy.CallHierarchyViewTreeNode; -import org.eclipse.lsp4e.test.utils.AbstractTest; import org.eclipse.lsp4j.CallHierarchyItem; import org.eclipse.swt.custom.StyleRange; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -public class CallHierarchyLabelProviderTest extends AbstractTest { +public class CallHierarchyLabelProviderTest { private static CallHierarchyLabelProvider labelProvider = null; diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/callhierarchy/CallHierarchyViewContentTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/callhierarchy/CallHierarchyViewContentTest.java index d38d33efb..e6aaf0d3c 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/callhierarchy/CallHierarchyViewContentTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/callhierarchy/CallHierarchyViewContentTest.java @@ -28,15 +28,13 @@ import org.eclipse.lsp4e.test.utils.AbstractTestWithProject; import org.eclipse.lsp4e.test.utils.TestUtils; import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4e.ui.views.HierarchyViewInput; -import org.eclipse.lsp4j.ServerCapabilities; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.TreeItem; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestInfo; /** * UI-level test that opens a file, initializes Call Hierarchy and verifies that @@ -44,20 +42,15 @@ */ public class CallHierarchyViewContentTest extends AbstractTestWithProject { - @Override - @BeforeEach - public void setUpProject(TestInfo testInfo) throws Exception { - super.setUpProject(testInfo); - // Ensure the mock server advertises callHierarchyProvider - MockLanguageServer.reset(() -> { - ServerCapabilities caps = MockLanguageServer.defaultServerCapabilities(); + @Test + public void testCallHierarchyShowsCalleeAndCaller(MockLanguageServerFactory factory) throws Exception { + factory.withCapabilities(() -> { + var caps = MockLanguageServer.defaultServerCapabilities(); + // Ensure the mock server advertises callHierarchyProvider caps.setCallHierarchyProvider(Boolean.TRUE); return caps; }); - } - - @Test - public void testCallHierarchyShowsCalleeAndCaller() throws Exception { + IProject p = project; IFile file = TestUtils.createUniqueTestFile(p, "// mock content for call hierarchy\nfunction f(){}\n"); diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/codeactions/CodeActionTests.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/codeactions/CodeActionTests.java index ba901586f..a916e434d 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/codeactions/CodeActionTests.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/codeactions/CodeActionTests.java @@ -31,7 +31,7 @@ import org.eclipse.lsp4e.test.utils.AbstractTestWithProject; import org.eclipse.lsp4e.test.utils.NoErrorLoggedRule; import org.eclipse.lsp4e.test.utils.TestUtils; -import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4j.CodeAction; import org.eclipse.lsp4j.Command; import org.eclipse.lsp4j.Diagnostic; @@ -60,20 +60,24 @@ public class CodeActionTests extends AbstractTestWithProject { public final @RegisterExtension NoErrorLoggedRule noErrorLoggedRule = new NoErrorLoggedRule(); @Test - public void testCodeActionsClientCommandForTextEdit() throws CoreException { + public void testCodeActionsClientCommandForTextEdit(MockLanguageServerFactory factory) throws CoreException { + factory.withConfiguration((idx, server)-> { + server.setCodeActions(List.of(Either.forLeft(new Command( + "fixme", + "edit", + List.of( + new TextEdit( + new Range(new Position(0, 0), new Position(0, 5)), + "fixed")) + ) + ) + )); + server.setDiagnostics(List.of( + new Diagnostic(new Range(new Position(0, 0), new Position(0, 5)), "error", DiagnosticSeverity.Error, null))); + }); + IFile f = TestUtils.createUniqueTestFile(project, "error"); - MockLanguageServer.INSTANCE.setCodeActions(List.of(Either.forLeft(new Command( - "fixme", - "edit", - List.of( - new TextEdit( - new Range(new Position(0, 0), new Position(0, 5)), - "fixed")) - ) - ) - )); - MockLanguageServer.INSTANCE.setDiagnostics(List.of( - new Diagnostic(new Range(new Position(0, 0), new Position(0, 5)), "error", DiagnosticSeverity.Error, null))); + final var editor = (AbstractTextEditor)TestUtils.openEditor(f); try { IMarker m = assertDiagnostics(f, "error", "fixme"); @@ -84,20 +88,23 @@ public void testCodeActionsClientCommandForTextEdit() throws CoreException { } @Test - public void testCodeActionsClientCommandForWorkspaceEdit() throws CoreException { + public void testCodeActionsClientCommandForWorkspaceEdit(MockLanguageServerFactory factory) throws CoreException { IFile f = TestUtils.createUniqueTestFile(project, "error"); + factory.withConfiguration((idx, server)-> { + final var tEdit = new TextEdit(new Range(new Position(0, 0), new Position(0, 5)), "fixed"); + final var wEdit = new WorkspaceEdit(Collections.singletonMap(f.getLocationURI().toString(), List.of(tEdit))); + server.setCodeActions(List + .of(Either.forLeft(new Command( + "fixme", + "edit", + List.of(wEdit)) + ) + )); + server.setDiagnostics(List.of( + new Diagnostic(new Range(new Position(0, 0), new Position(0, 5)), "error", DiagnosticSeverity.Error, null))); + }); + - final var tEdit = new TextEdit(new Range(new Position(0, 0), new Position(0, 5)), "fixed"); - final var wEdit = new WorkspaceEdit(Collections.singletonMap(f.getLocationURI().toString(), List.of(tEdit))); - MockLanguageServer.INSTANCE.setCodeActions(List - .of(Either.forLeft(new Command( - "fixme", - "edit", - List.of(wEdit)) - ) - )); - MockLanguageServer.INSTANCE.setDiagnostics(List.of( - new Diagnostic(new Range(new Position(0, 0), new Position(0, 5)), "error", DiagnosticSeverity.Error, null))); final var editor = (AbstractTextEditor)TestUtils.openEditor(f); IMarker m = assertDiagnostics(f, "error", "fixme"); @@ -113,19 +120,21 @@ private void checkCompletionContent(final Table completionProposalList) { } @Test - public void testCodeActionsQuickAssist() throws CoreException { - MockLanguageServer.reset(); + public void testCodeActionsQuickAssist(MockLanguageServerFactory factory) throws CoreException { IFile f = TestUtils.createUniqueTestFile(project, "error"); - final var tEdit = new TextEdit(new Range(new Position(0, 0), new Position(0, 5)), "fixed"); - final var wEdit = new WorkspaceEdit(Collections.singletonMap(f.getLocationURI().toString(), List.of(tEdit))); - MockLanguageServer.INSTANCE.setCodeActions(List - .of(Either.forLeft(new Command( - "fixme", - "edit", - List.of(wEdit)) - ) - )); + factory.withConfiguration((idx, server)-> { + final var tEdit = new TextEdit(new Range(new Position(0, 0), new Position(0, 5)), "fixed"); + final var wEdit = new WorkspaceEdit(Collections.singletonMap(f.getLocationURI().toString(), List.of(tEdit))); + server.setCodeActions(List + .of(Either.forLeft(new Command( + "fixme", + "edit", + List.of(wEdit)) + ) + )); + }); + final var editor = (AbstractTextEditor)TestUtils.openEditor(f); final Set beforeShells = Arrays.stream(editor.getSite().getShell().getDisplay().getShells()).filter(Shell::isVisible).collect(Collectors.toSet()); editor.selectAndReveal(3, 0); @@ -138,20 +147,22 @@ public void testCodeActionsQuickAssist() throws CoreException { } @Test - public void testSlowCodeActionsQuickAssist() throws CoreException { - MockLanguageServer.reset(); + public void testSlowCodeActionsQuickAssist(MockLanguageServerFactory factory) throws CoreException { IFile f = TestUtils.createUniqueTestFile(project, "error"); - final var tEdit = new TextEdit(new Range(new Position(0, 0), new Position(0, 5)), "fixed"); - final var wEdit = new WorkspaceEdit(Collections.singletonMap(f.getLocationURI().toString(), List.of(tEdit))); - MockLanguageServer.INSTANCE.setCodeActions(List - .of(Either.forLeft(new Command( - "fixme", - "edit", - List.of(wEdit)) - ) - )); - MockLanguageServer.INSTANCE.setTimeToProceedQueries(1000); + factory.withConfiguration((idx, server)-> { + final var tEdit = new TextEdit(new Range(new Position(0, 0), new Position(0, 5)), "fixed"); + final var wEdit = new WorkspaceEdit(Collections.singletonMap(f.getLocationURI().toString(), List.of(tEdit))); + server.setCodeActions(List + .of(Either.forLeft(new Command( + "fixme", + "edit", + List.of(wEdit)) + ) + )); + server.setTimeToProceedQueries(1000); + }); + final var editor = (AbstractTextEditor)TestUtils.openEditor(f); final Set beforeShells = Arrays.stream(editor.getSite().getShell().getDisplay().getShells()).filter(Shell::isVisible).collect(Collectors.toSet()); editor.selectAndReveal(3, 0); @@ -166,27 +177,29 @@ public void testSlowCodeActionsQuickAssist() throws CoreException { final Table completionProposalList = TestUtils.findCompletionSelectionControl(completionShell); return completionProposalList.getItemCount() == 1 && "fixme".equals(completionProposalList.getItem(0).getText()); }); - assertEquals(1, MockLanguageServer.INSTANCE.getTextDocumentService().codeActionRequests); + assertEquals(1, factory.getServer().getTextDocumentService().codeActionRequests); } @Test - public void testCodeActionLiteralWorkspaceEdit() throws CoreException { + public void testCodeActionLiteralWorkspaceEdit(MockLanguageServerFactory factory) throws CoreException { IFile f = TestUtils.createUniqueTestFile(project, "error"); + factory.withConfiguration((idx, server)-> { + final var tEdit = new TextEdit(new Range(new Position(0, 0), new Position(0, 5)), "fixed"); + final var wEdit = new WorkspaceEdit(Collections.singletonMap(f.getLocationURI().toString(), List.of(tEdit))); + final var codeAction = new CodeAction("fixme"); + codeAction.setEdit(wEdit); + server.setCodeActions(List.of(Either.forRight(codeAction))); + server.setDiagnostics(List.of( + new Diagnostic(new Range(new Position(0, 0), new Position(0, 5)), "error", DiagnosticSeverity.Error, null))); + }); - final var tEdit = new TextEdit(new Range(new Position(0, 0), new Position(0, 5)), "fixed"); - final var wEdit = new WorkspaceEdit(Collections.singletonMap(f.getLocationURI().toString(), List.of(tEdit))); - final var codeAction = new CodeAction("fixme"); - codeAction.setEdit(wEdit); - MockLanguageServer.INSTANCE.setCodeActions(List.of(Either.forRight(codeAction))); - MockLanguageServer.INSTANCE.setDiagnostics(List.of( - new Diagnostic(new Range(new Position(0, 0), new Position(0, 5)), "error", DiagnosticSeverity.Error, null))); final var editor = (AbstractTextEditor)TestUtils.openEditor(f); IMarker m = assertDiagnostics(f, "error", "fixme"); assertResolution(editor, m, "fixed"); } @Test - public void testNoCodeActionOnReadOnlySource() throws CoreException { + public void testNoCodeActionOnReadOnlySource(MockLanguageServerFactory factory) throws CoreException { IFile f = TestUtils.createUniqueTestFile(project, "error"); f.setResourceAttributes(new ResourceAttributes() { @Override @@ -195,47 +208,53 @@ public boolean isReadOnly() { } }); - final var tEdit = new TextEdit(new Range(new Position(0, 0), new Position(0, 5)), "fixed"); - final var wEdit = new WorkspaceEdit(Collections.singletonMap(f.getLocationURI().toString(), List.of(tEdit))); - final var codeAction = new CodeAction("fixme"); - codeAction.setEdit(wEdit); - MockLanguageServer.INSTANCE.setCodeActions(List.of(Either.forRight(codeAction))); - MockLanguageServer.INSTANCE.setDiagnostics(List.of( - new Diagnostic(new Range(new Position(0, 0), new Position(0, 5)), "error", DiagnosticSeverity.Error, null))); + factory.withConfiguration((idx, server)-> { + final var tEdit = new TextEdit(new Range(new Position(0, 0), new Position(0, 5)), "fixed"); + final var wEdit = new WorkspaceEdit(Collections.singletonMap(f.getLocationURI().toString(), List.of(tEdit))); + final var codeAction = new CodeAction("fixme"); + codeAction.setEdit(wEdit); + server.setCodeActions(List.of(Either.forRight(codeAction))); + server.setDiagnostics(List.of( + new Diagnostic(new Range(new Position(0, 0), new Position(0, 5)), "error", DiagnosticSeverity.Error, null))); + }); TestUtils.openEditor(f); assertDiagnostics(f, "error", "fixme", false); } @Test - public void testCodeActionLiteralWithClientCommand() throws CoreException { + public void testCodeActionLiteralWithClientCommand(MockLanguageServerFactory factory) throws CoreException { IFile f = TestUtils.createUniqueTestFile(project, "error"); - final var tEdit = new TextEdit(new Range(new Position(0, 0), new Position(0, 5)), "fixed"); - final var wEdit = new WorkspaceEdit(Collections.singletonMap(f.getLocationURI().toString(), List.of(tEdit))); - final var codeAction = new CodeAction("fixme"); - codeAction.setCommand(new Command("editCommand", "mockEditCommand", List.of(wEdit))); - MockLanguageServer.INSTANCE.setCodeActions(List.of(Either.forRight(codeAction))); - MockLanguageServer.INSTANCE.setDiagnostics(List.of( - new Diagnostic(new Range(new Position(0, 0), new Position(0, 5)), "error", DiagnosticSeverity.Error, null))); + factory.withConfiguration((idx, server)-> { + final var tEdit = new TextEdit(new Range(new Position(0, 0), new Position(0, 5)), "fixed"); + final var wEdit = new WorkspaceEdit(Collections.singletonMap(f.getLocationURI().toString(), List.of(tEdit))); + final var codeAction = new CodeAction("fixme"); + codeAction.setCommand(new Command("editCommand", "mockEditCommand", List.of(wEdit))); + server.setCodeActions(List.of(Either.forRight(codeAction))); + server.setDiagnostics(List.of( + new Diagnostic(new Range(new Position(0, 0), new Position(0, 5)), "error", DiagnosticSeverity.Error, null))); + }); final var editor = (AbstractTextEditor)TestUtils.openEditor(f); IMarker m = assertDiagnostics(f, "error", "fixme"); assertResolution(editor, m, "fixed"); } @Test - public void testCodeActionWorkspaceEditlWithDifferentURI() throws CoreException { + public void testCodeActionWorkspaceEditlWithDifferentURI(MockLanguageServerFactory factory) throws CoreException { IFile sourceFile = TestUtils.createUniqueTestFile(project, "error"); IFile targetFile = TestUtils.createUniqueTestFile(project, "fixme"); - // create a diagnostic on the sourceFile with a code action - // that changes the targetFile - final var tEdit = new TextEdit(new Range(new Position(0, 0), new Position(0, 5)), "fixed"); - final var wEdit = new WorkspaceEdit(Collections.singletonMap(targetFile.getLocationURI().toString(), List.of(tEdit))); - final var codeAction = new CodeAction("fixme"); - codeAction.setCommand(new Command("editCommand", "mockEditCommand", List.of(wEdit))); - MockLanguageServer.INSTANCE.setCodeActions(List.of(Either.forRight(codeAction))); - MockLanguageServer.INSTANCE.setDiagnostics(List.of( - new Diagnostic(new Range(new Position(0, 0), new Position(0, 5)), "error", DiagnosticSeverity.Error, null))); + factory.withConfiguration((idx, server)-> { + // create a diagnostic on the sourceFile with a code action + // that changes the targetFile + final var tEdit = new TextEdit(new Range(new Position(0, 0), new Position(0, 5)), "fixed"); + final var wEdit = new WorkspaceEdit(Collections.singletonMap(targetFile.getLocationURI().toString(), List.of(tEdit))); + final var codeAction = new CodeAction("fixme"); + codeAction.setCommand(new Command("editCommand", "mockEditCommand", List.of(wEdit))); + server.setCodeActions(List.of(Either.forRight(codeAction))); + server.setDiagnostics(List.of( + new Diagnostic(new Range(new Position(0, 0), new Position(0, 5)), "error", DiagnosticSeverity.Error, null))); + }); TestUtils.openEditor(sourceFile); IMarker m = assertDiagnostics(sourceFile, "error", "fixme"); diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/color/ColorTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/color/ColorTest.java index d4136eef4..b09423179 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/color/ColorTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/color/ColorTest.java @@ -23,6 +23,7 @@ import org.eclipse.lsp4e.test.utils.AbstractTestWithProject; import org.eclipse.lsp4e.test.utils.TestUtils; import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4e.ui.UI; import org.eclipse.lsp4j.Color; import org.eclipse.lsp4j.ColorInformation; @@ -35,29 +36,26 @@ import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.widgets.Control; import org.eclipse.ui.ide.IDE; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; public class ColorTest extends AbstractTestWithProject { - private RGB color; - - @BeforeEach - public void setUp() { - color = new RGB(56, 78, 90); // a color that's not likely used anywhere else - MockLanguageServer.INSTANCE.getTextDocumentService().setDocumentColors(List.of(new ColorInformation(new Range(new Position(0, 0), new Position(0, 1)), new Color(color.red / 255., color.green / 255., color.blue / 255., 255)))); - } + // a color that's not likely used anywhere else + private RGB color = new RGB(56, 78, 90); @Test - public void testColorProvider() throws Exception { + public void testColorProvider(MockLanguageServerFactory factory) throws Exception { + factory.withConfiguration(this::configureColors); + ITextViewer viewer = TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project, "\u2588\u2588\u2588\u2588\u2588")); StyledText widget = viewer.getTextWidget(); waitForAndAssertCondition(3_000, widget.getDisplay(), () -> containsColor(widget, color, 10)); } @Test - public void testColorProviderExternalFile(@TempDir Path tempDir) throws Exception { + public void testColorProviderExternalFile(MockLanguageServerFactory factory, @TempDir Path tempDir) throws Exception { + factory.withConfiguration(this::configureColors); Path file = Files.write(tempDir.resolve("testColorProviderExternalFile.lspt"), "\u2588\u2588\u2588\u2588\u2588".getBytes()); ITextViewer viewer = LSPEclipseUtils.getTextViewer(IDE.openEditorOnFileStore(UI.getActivePage(), EFS.getStore(file.toUri()))); StyledText widget = viewer.getTextWidget(); @@ -100,4 +98,10 @@ private static int distance(RGB from, RGB to) { return (int) Math.sqrt((dR * dR + dG * dG + dB * dB) / 3); } + + private void configureColors(Integer idx, MockLanguageServer server) { + server.getTextDocumentService() + .setDocumentColors(List.of(new ColorInformation(new Range(new Position(0, 0), new Position(0, 1)), + new Color(color.red / 255., color.green / 255., color.blue / 255., 255)))); + } } diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/commands/DynamicRegistrationTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/commands/DynamicRegistrationTest.java index af2e90765..0dc0e5d81 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/commands/DynamicRegistrationTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/commands/DynamicRegistrationTest.java @@ -12,7 +12,6 @@ package org.eclipse.lsp4e.test.commands; import static org.eclipse.lsp4e.test.utils.TestUtils.waitForCondition; -import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -30,6 +29,7 @@ import org.eclipse.lsp4e.test.utils.AbstractTestWithProject; import org.eclipse.lsp4e.test.utils.TestUtils; import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4e.tests.mock.MockWorkspaceService; import org.eclipse.lsp4j.DidChangeWatchedFilesParams; import org.eclipse.lsp4j.ExecuteCommandOptions; @@ -42,7 +42,6 @@ import org.eclipse.lsp4j.WorkspaceFoldersOptions; import org.eclipse.lsp4j.WorkspaceServerCapabilities; import org.eclipse.lsp4j.services.LanguageClient; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; public class DynamicRegistrationTest extends AbstractTestWithProject { @@ -51,43 +50,45 @@ public class DynamicRegistrationTest extends AbstractTestWithProject { private static final String WORKSPACE_DID_CHANGE_FOLDERS = "workspace/didChangeWorkspaceFolders"; private static final String WORKSPACE_DID_CHANGE_WATCHED_FILES = "workspace/didChangeWatchedFiles"; - @BeforeEach - public void setUp() throws Exception { + @Test + public void testCommandRegistration(MockLanguageServerFactory factory) throws Exception { IFile testFile = TestUtils.createFile(project, "shouldUseExtension.lspt", ""); - // Make sure mock language server is created... IDocument document = LSPEclipseUtils.getDocument(testFile); assertNotNull(document); LanguageServers.forDocument(document).anyMatching(); - - waitForCondition(5_000, () -> !MockLanguageServer.INSTANCE.getRemoteProxies().isEmpty()); - getMockClient(); - } - - @Test - public void testCommandRegistration() throws Exception { + + waitForCondition(5_000, () -> !factory.getServers().isEmpty()); + assertTrue(LanguageServiceAccessor.hasActiveLanguageServers(c -> true)); assertFalse(LanguageServiceAccessor.hasActiveLanguageServers(handlesCommand("test.command"))); - UUID registration = registerCommands("test.command", "test.command.2"); + UUID registration = registerCommands(factory.getServer(), "test.command", "test.command.2"); try { assertTrue(LanguageServiceAccessor.hasActiveLanguageServers(handlesCommand("test.command"))); assertTrue(LanguageServiceAccessor.hasActiveLanguageServers(handlesCommand("test.command.2"))); } finally { - unregister(registration, WORKSPACE_EXECUTE_COMMAND); + unregister(registration, WORKSPACE_EXECUTE_COMMAND, factory.getServer()); } assertFalse(LanguageServiceAccessor.hasActiveLanguageServers(handlesCommand("test.command"))); assertFalse(LanguageServiceAccessor.hasActiveLanguageServers(handlesCommand("test.command.2"))); } @Test - public void testWatchedFilesRegistrationAndNotification() throws Exception { + public void testWatchedFilesRegistrationAndNotification(MockLanguageServerFactory factory) throws Exception { + IFile testFile = TestUtils.createFile(project, "shouldUseExtension.lspt", ""); + // Make sure mock language server is created... + IDocument document = LSPEclipseUtils.getDocument(testFile); + assertNotNull(document); + LanguageServers.forDocument(document).anyMatching(); + + waitForCondition(5_000, () -> !factory.getServers().isEmpty()); assertTrue(LanguageServiceAccessor.hasActiveLanguageServers(c -> true)); - UUID registration = registerWatchedFiles(); + UUID registration = registerWatchedFiles(factory.getServer()); try { - MockWorkspaceService workspaceService = MockLanguageServer.INSTANCE.getWorkspaceService(); + MockWorkspaceService workspaceService = factory.getServer().getWorkspaceService(); TestUtils.createFile(project, "watched.txt", ""); TestUtils.createFile(project, "unwatched.bin", ""); @@ -101,21 +102,29 @@ public void testWatchedFilesRegistrationAndNotification() throws Exception { assertFalse(params.getChanges().stream() .anyMatch(ev -> ev.getUri().endsWith("unwatched.bin"))); } finally { - unregister(registration, WORKSPACE_DID_CHANGE_WATCHED_FILES); + unregister(registration, WORKSPACE_DID_CHANGE_WATCHED_FILES, factory.getServer()); } } @Test - public void testWorkspaceFoldersRegistration() throws Exception { + public void testWorkspaceFoldersRegistration(MockLanguageServerFactory factory) throws Exception { + IFile testFile = TestUtils.createFile(project, "shouldUseExtension.lspt", ""); + // Make sure mock language server is created... + IDocument document = LSPEclipseUtils.getDocument(testFile); + assertNotNull(document); + LanguageServers.forDocument(document).anyMatching(); + + waitForCondition(5_000, () -> !factory.getServers().isEmpty()); + assertTrue(LanguageServiceAccessor.hasActiveLanguageServers(c -> true)); assertFalse(LanguageServiceAccessor.hasActiveLanguageServers(c -> hasWorkspaceFolderSupport(c))); - UUID registration = registerWorkspaceFolders(); + UUID registration = registerWorkspaceFolders(factory.getServer()); try { assertTrue(LanguageServiceAccessor.hasActiveLanguageServers(c -> hasWorkspaceFolderSupport(c))); } finally { - unregister(registration, WORKSPACE_DID_CHANGE_FOLDERS); + unregister(registration, WORKSPACE_DID_CHANGE_FOLDERS, factory.getServer()); } assertFalse(LanguageServiceAccessor.hasActiveLanguageServers(c -> hasWorkspaceFolderSupport(c))); assertTrue(LanguageServiceAccessor.hasActiveLanguageServers(c -> !hasWorkspaceFolderSupport(c))); @@ -123,16 +132,16 @@ public void testWorkspaceFoldersRegistration() throws Exception { ////////////////////////////////////////////////////////////////////////////////// - private void unregister(UUID registration, String method) throws Exception { - LanguageClient client = getMockClient(); + private void unregister(UUID registration, String method, MockLanguageServer server) throws Exception { + LanguageClient client = server.getRemoteProxy(); final var unregistration = new Unregistration(registration.toString(), method); client.unregisterCapability(new UnregistrationParams(List.of(unregistration))) .get(1, TimeUnit.SECONDS); } - private UUID registerWatchedFiles() throws Exception { + private UUID registerWatchedFiles(MockLanguageServer server) throws Exception { var id = UUID.randomUUID(); - LanguageClient client = getMockClient(); + LanguageClient client = server.getRemoteProxy(); final var registration = new Registration(); registration.setId(id.toString()); registration.setMethod(WORKSPACE_DID_CHANGE_WATCHED_FILES); @@ -146,9 +155,9 @@ private UUID registerWatchedFiles() throws Exception { return id; } - private UUID registerWorkspaceFolders() throws Exception { + private UUID registerWorkspaceFolders(MockLanguageServer server) throws Exception { UUID id = UUID.randomUUID(); - LanguageClient client = getMockClient(); + LanguageClient client = server.getRemoteProxy(); final var registration = new Registration(); registration.setId(id.toString()); registration.setMethod(WORKSPACE_DID_CHANGE_FOLDERS); @@ -157,9 +166,9 @@ private UUID registerWorkspaceFolders() throws Exception { return id; } - private UUID registerCommands(String... command) throws Exception { + private UUID registerCommands(MockLanguageServer server, String... command) throws Exception { UUID id = UUID.randomUUID(); - LanguageClient client = getMockClient(); + LanguageClient client = server.getRemoteProxy(); final var registration = new Registration(); registration.setId(id.toString()); registration.setMethod(WORKSPACE_EXECUTE_COMMAND); @@ -168,12 +177,6 @@ private UUID registerCommands(String... command) throws Exception { return id; } - private LanguageClient getMockClient() { - List proxies = MockLanguageServer.INSTANCE.getRemoteProxies(); - assertEquals(1, proxies.size()); - return proxies.get(0); - } - private Predicate handlesCommand(String command) { return cap -> { ExecuteCommandOptions commandProvider = cap.getExecuteCommandProvider(); diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/completion/AbstractCompletionTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/completion/AbstractCompletionTest.java index 8d29b7961..54b7b08d3 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/completion/AbstractCompletionTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/completion/AbstractCompletionTest.java @@ -22,7 +22,7 @@ import org.eclipse.lsp4e.operations.completion.LSContentAssistProcessor; import org.eclipse.lsp4e.test.utils.AbstractTestWithProject; import org.eclipse.lsp4e.test.utils.TestUtils; -import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4j.CompletionItem; import org.eclipse.lsp4j.CompletionItemKind; import org.eclipse.lsp4j.CompletionList; @@ -74,19 +74,21 @@ protected CompletionItem createCompletionItemWithInsertReplace(String label, Com } protected void confirmCompletionResults(String[] completions, String content, Integer cursorIndexInContent, - String[] expectedOrder) throws CoreException { + String[] expectedOrder, MockLanguageServerFactory factory) throws CoreException { final var range = new Range(new Position(0, 0), new Position(0, cursorIndexInContent)); final var items = new ArrayList(); for (String string : completions) { items.add(createCompletionItem(string, CompletionItemKind.Class, range)); } - confirmCompletionResults(items, content, cursorIndexInContent, expectedOrder); + confirmCompletionResults(items, content, cursorIndexInContent, expectedOrder, factory); } protected void confirmCompletionResults(List completions, String content, - Integer cursorIndexInContent, String[] expectedOrder) throws CoreException { - - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(false, completions)); + Integer cursorIndexInContent, String[] expectedOrder, MockLanguageServerFactory factory) throws CoreException { + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(false, completions)); + }); + ITextViewer viewer = TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project, content)); ICompletionProposal[] proposals = contentAssistProcessor.computeCompletionProposals(viewer, diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/completion/CompleteCompletionTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/completion/CompleteCompletionTest.java index e9220780a..5a09f24be 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/completion/CompleteCompletionTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/completion/CompleteCompletionTest.java @@ -42,8 +42,8 @@ import org.eclipse.lsp4e.LanguageServiceAccessor; import org.eclipse.lsp4e.operations.completion.LSCompletionProposal; import org.eclipse.lsp4e.test.utils.TestUtils; -import org.eclipse.lsp4e.tests.mock.MockConnectionProvider; import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4e.ui.UI; import org.eclipse.lsp4j.Command; import org.eclipse.lsp4j.CompletionItem; @@ -77,10 +77,13 @@ public class CompleteCompletionTest extends AbstractCompletionTest { * file-specific LS already associated is something we want to support. */ @Test - public void testAssistForUnknownButConnectedType() throws CoreException { + public void testAssistForUnknownButConnectedType(MockLanguageServerFactory factory) throws CoreException { final var items = new ArrayList(); items.add(createCompletionItem("FirstClass", CompletionItemKind.Class)); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(false, items)); + + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(false, items)); + }); IFile testFile = TestUtils.createUniqueTestFileOfUnknownType(project, ""); ITextViewer viewer = TestUtils.openTextViewer(testFile); @@ -103,10 +106,12 @@ public void testAssistForUnknownButConnectedType() throws CoreException { } @Test - public void testNoPrefix() throws CoreException { + public void testNoPrefix(MockLanguageServerFactory factory) throws CoreException { final var items = new ArrayList(); items.add(createCompletionItem("FirstClass", CompletionItemKind.Class)); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(false, items)); + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(false, items)); + }); IFile testFile = TestUtils.createUniqueTestFile(project, ""); ITextViewer viewer = TestUtils.openTextViewer(testFile); @@ -120,11 +125,13 @@ public void testNoPrefix() throws CoreException { } @Test - public void testPrefix() throws CoreException { + public void testPrefix(MockLanguageServerFactory factory) throws CoreException { final var items = new ArrayList(); items.add(createCompletionItem("FirstClass", CompletionItemKind.Class)); items.add(createCompletionItem("SecondClass", CompletionItemKind.Class)); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(false, items)); + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(false, items)); + }); final var content = "First"; ITextViewer viewer = TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project, content)); @@ -142,13 +149,15 @@ public void testPrefix() throws CoreException { * The test will use a Command that shall be handled by the langauge server. */ @Test - public void testCommandExecution() throws CoreException, InterruptedException, ExecutionException, TimeoutException { + public void testCommandExecution(MockLanguageServerFactory factory) throws CoreException, InterruptedException, ExecutionException, TimeoutException { CompletionItem completionItem = createCompletionItem("Bla", CompletionItemKind.Class); final var expectedParameter = "command execution parameter"; List commandArguments = List.of(expectedParameter); completionItem.setCommand(new Command("TestCommand", MockLanguageServer.SUPPORTED_COMMAND_ID, commandArguments)); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(false, List.of(completionItem))); + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(false, List.of(completionItem))); + }); ITextViewer viewer = TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project, "")); @@ -159,7 +168,7 @@ public void testCommandExecution() throws CoreException, InterruptedException, E lsCompletionProposal.apply(viewer, '\n', 0, 0); // Assert command was invoked on language server - ExecuteCommandParams executedCommand = MockLanguageServer.INSTANCE.getWorkspaceService().getExecutedCommand().get(2, TimeUnit.SECONDS); + ExecuteCommandParams executedCommand = factory.getServer().getWorkspaceService().getExecutedCommand().get(2, TimeUnit.SECONDS); assertEquals(MockLanguageServer.SUPPORTED_COMMAND_ID, executedCommand.getCommand()); List expectedParameterList = List.of(new JsonPrimitive(expectedParameter)); @@ -167,10 +176,12 @@ public void testCommandExecution() throws CoreException, InterruptedException, E } @Test - public void testPrefixCaseSensitivity() throws CoreException { + public void testPrefixCaseSensitivity(MockLanguageServerFactory factory) throws CoreException { final var items = new ArrayList(); items.add(createCompletionItem("FirstClass", CompletionItemKind.Class)); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(false, items)); + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(false, items)); + }); final var content = "FIRST"; ITextViewer viewer = TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project, content)); @@ -184,10 +195,12 @@ public void testPrefixCaseSensitivity() throws CoreException { } @Test - public void testPrefixCaseSensitivityWithoutTextEdit() throws CoreException { + public void testPrefixCaseSensitivityWithoutTextEdit(MockLanguageServerFactory factory) throws CoreException { final var items = new ArrayList(); items.add(createCompletionItemWithoutTextEdit("FirstClass", CompletionItemKind.Class)); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(false, items)); + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(false, items)); + }); final var content = "FIRST"; ITextViewer viewer = TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project, content)); @@ -201,10 +214,12 @@ public void testPrefixCaseSensitivityWithoutTextEdit() throws CoreException { } @Test - public void testPrefixCaseSensitivityWithoutTextEditAtOffset() throws CoreException { + public void testPrefixCaseSensitivityWithoutTextEditAtOffset(MockLanguageServerFactory factory) throws CoreException { final var items = new ArrayList(); items.add(createCompletionItemWithoutTextEdit("FirstClass", CompletionItemKind.Class)); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(false, items)); + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(false, items)); + }); final var content = "FIRST"; ITextViewer viewer = TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project, content)); @@ -218,13 +233,15 @@ public void testPrefixCaseSensitivityWithoutTextEditAtOffset() throws CoreExcept } @Test - public void testCompleteOnFileEnd() throws CoreException { // bug 508842 + public void testCompleteOnFileEnd(MockLanguageServerFactory factory) throws CoreException { // bug 508842 final var item = new CompletionItem(); item.setLabel("1024M"); item.setKind(CompletionItemKind.Value); item.setTextEdit(Either.forLeft(new TextEdit(new Range(new Position(2, 10), new Position(2, 10)), "1024M"))); final var completionList = new CompletionList(false, List.of(item)); - MockLanguageServer.INSTANCE.setCompletionList(completionList); + factory.withConfiguration((idx, server) -> { + server.setCompletionList(completionList); + }); final var content = "applications:\n" + "- name: hello\n" + " memory: "; ITextViewer viewer = TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project, content)); @@ -239,9 +256,11 @@ public void testCompleteOnFileEnd() throws CoreException { // bug 508842 } @Test - public void testTriggerCharsWithoutPreliminaryCompletion() throws CoreException { // bug 508463 + public void testTriggerCharsWithoutPreliminaryCompletion(MockLanguageServerFactory factory) throws CoreException { // bug 508463 final Set triggers = Set.of("a", "b"); - MockLanguageServer.INSTANCE.setCompletionTriggerChars(triggers); + factory.withConfiguration((idx, server) -> { + server.setCompletionTriggerChars(triggers); + }); final var content = "First"; TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project, content)); @@ -253,8 +272,10 @@ public void testTriggerCharsWithoutPreliminaryCompletion() throws CoreException } @Test - public void testTriggerCharsNullList() throws CoreException { - MockLanguageServer.INSTANCE.setCompletionTriggerChars(null); + public void testTriggerCharsNullList(MockLanguageServerFactory factory) throws CoreException { + factory.withConfiguration((idx, server) -> { + server.setCompletionTriggerChars(null); + }); TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project, "First")); @@ -262,11 +283,13 @@ public void testTriggerCharsNullList() throws CoreException { } @Test - public void testApplyCompletionWithPrefix() throws CoreException { + public void testApplyCompletionWithPrefix(MockLanguageServerFactory factory) throws CoreException { final var range = new Range(new Position(0, 0), new Position(0, 5)); List items = List .of(createCompletionItem("FirstClass", CompletionItemKind.Class, range)); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(false, items)); + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(false, items)); + }); final var content = "First"; ITextViewer viewer = TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project, content)); @@ -279,11 +302,13 @@ public void testApplyCompletionWithPrefix() throws CoreException { } @Test - public void testApplyCompletionReplace() throws CoreException { + public void testApplyCompletionReplace(MockLanguageServerFactory factory) throws CoreException { final var range = new Range(new Position(0, 0), new Position(0, 20)); List items = List .of(createCompletionItem("FirstClass", CompletionItemKind.Class, range)); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(false, items)); + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(false, items)); + }); final var content = "FirstNotMatchedLabel"; ITextViewer viewer = TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project, content)); @@ -295,11 +320,13 @@ public void testApplyCompletionReplace() throws CoreException { } @Test - public void testApplyCompletionReplaceAndTypingWithTextEdit() throws CoreException, BadLocationException { + public void testApplyCompletionReplaceAndTypingWithTextEdit(MockLanguageServerFactory factory) throws CoreException, BadLocationException { final var range = new Range(new Position(0, 0), new Position(0, 20)); List items = List .of(createCompletionItem("FirstClass", CompletionItemKind.Class, range)); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(false, items)); + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(false, items)); + }); final var content = "FirstNotMatchedLabel"; ITextViewer viewer = TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project,content)); @@ -317,12 +344,14 @@ public void testApplyCompletionReplaceAndTypingWithTextEdit() throws CoreExcepti } @Test - public void testApplyCompletionReplaceAndTyping() throws CoreException, BadLocationException { + public void testApplyCompletionReplaceAndTyping(MockLanguageServerFactory factory) throws CoreException, BadLocationException { final var item = new CompletionItem("strncasecmp"); item.setKind(CompletionItemKind.Function); item.setInsertText("strncasecmp()"); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(false, List.of(item))); + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(false, List.of(item))); + }); final var content = "str"; ITextViewer viewer = TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project, content)); @@ -341,12 +370,14 @@ public void testApplyCompletionReplaceAndTyping() throws CoreException, BadLocat } @Test - public void testCompletionReplace() throws CoreException { + public void testCompletionReplace(MockLanguageServerFactory factory) throws CoreException { + factory.withConfiguration((idx, server) -> { + server.setCompletionList( + new CompletionList(false, List.of(createCompletionItem("Inserted", CompletionItemKind.Text, + new Range(new Position(1, 4), new Position(1, 4 + "InsertHere".length())))))); + }); IFile file = TestUtils.createUniqueTestFile(project, "line1\nlineInsertHere"); ITextViewer viewer = TestUtils.openTextViewer(file); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(false, List.of( - createCompletionItem("Inserted", CompletionItemKind.Text, new Range(new Position(1, 4), new Position(1, 4 + "InsertHere".length()))) - ))); int invokeOffset = viewer.getDocument().getLength() - "InsertHere".length(); ICompletionProposal[] proposals = contentAssistProcessor.computeCompletionProposals(viewer, invokeOffset); @@ -357,7 +388,7 @@ public void testCompletionReplace() throws CoreException { } @Test - public void testItemOrdering() throws Exception { + public void testItemOrdering(MockLanguageServerFactory factory) throws Exception { final var range = new Range(new Position(0, 0), new Position(0, 1)); List items = List.of( // createCompletionItem("AA", CompletionItemKind.Class, range), @@ -366,7 +397,9 @@ public void testItemOrdering() throws Exception { createCompletionItem("BB", CompletionItemKind.Class, range), createCompletionItem("CB", CompletionItemKind.Class, range), createCompletionItem("CC", CompletionItemKind.Class, range)); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(false, items)); + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(false, items)); + }); final var content = "B"; ITextViewer viewer = TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project,content)); @@ -384,10 +417,12 @@ public void testItemOrdering() throws Exception { } @Test - public void testBasicSnippet() throws CoreException { + public void testBasicSnippet(MockLanguageServerFactory factory) throws CoreException { CompletionItem completionItem = createCompletionItem("$1 and ${2:foo}", CompletionItemKind.Class, new Range(new Position(0, 0), new Position(0, 1))); completionItem.setInsertTextFormat(InsertTextFormat.Snippet); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(false, List.of(completionItem))); + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(false, List.of(completionItem))); + }); ITextViewer viewer = TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project,"")); int invokeOffset = 0; ICompletionProposal[] proposals = contentAssistProcessor.computeCompletionProposals(viewer, invokeOffset); @@ -398,10 +433,12 @@ public void testBasicSnippet() throws CoreException { } @Test - public void testChoiceSnippet() throws CoreException { + public void testChoiceSnippet(MockLanguageServerFactory factory) throws CoreException { CompletionItem completionItem = createCompletionItem("1${1|a,b|}2", CompletionItemKind.Class); completionItem.setInsertTextFormat(InsertTextFormat.Snippet); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(false, List.of(completionItem))); + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(false, List.of(completionItem))); + }); ITextViewer viewer = TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project,"")); int invokeOffset = 0; ICompletionProposal[] proposals = contentAssistProcessor.computeCompletionProposals(viewer, invokeOffset); @@ -418,10 +455,12 @@ public void testChoiceSnippet() throws CoreException { } @Test - public void testDuplicateVariable() throws CoreException { + public void testDuplicateVariable(MockLanguageServerFactory factory) throws CoreException { CompletionItem completionItem = createCompletionItem("${1:foo} and ${1:foo}", CompletionItemKind.Class, new Range(new Position(0, 0), new Position(0, 1))); completionItem.setInsertTextFormat(InsertTextFormat.Snippet); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(false, List.of(completionItem))); + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(false, List.of(completionItem))); + }); ITextViewer viewer = TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project,"")); int invokeOffset = 0; ICompletionProposal[] proposals = contentAssistProcessor.computeCompletionProposals(viewer, invokeOffset); @@ -464,14 +503,16 @@ public void testDuplicateVariable() throws CoreException { @ParameterizedTest @FieldSource - public void testComplexSnippets(String completion, String expected, String fileContent, int caretPos, int selectionLen) throws CoreException { + public void testComplexSnippets(String completion, String expected, String fileContent, int caretPos, int selectionLen, MockLanguageServerFactory factory) throws CoreException { CompletionItem completionItem = createCompletionItem( // completion, // CompletionItemKind.Snippet, // new Range(new Position(0, caretPos), new Position(0, caretPos + selectionLen))); completionItem.setInsertTextFormat(InsertTextFormat.Snippet); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(false, List.of(completionItem))); + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(false, List.of(completionItem))); + }); ITextViewer viewer = TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project, fileContent)); viewer.setSelectedRange(caretPos, selectionLen); @@ -485,12 +526,13 @@ public void testComplexSnippets(String completion, String expected, String fileC } @Test - public void testSnippetTabStops() throws CoreException { + public void testSnippetTabStops(MockLanguageServerFactory factory) throws CoreException { CompletionItem completionItem = createCompletionItem("sum(${1:x}, ${2:y})", CompletionItemKind.Method, new Range(new Position(0, 0), new Position(0, 1))); completionItem.setInsertTextFormat(InsertTextFormat.Snippet); - MockLanguageServer.INSTANCE - .setCompletionList(new CompletionList(false, List.of(completionItem))); + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(false, List.of(completionItem))); + }); ITextViewer viewer = TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project, "")); int invokeOffset = 0; ICompletionProposal[] proposals = contentAssistProcessor.computeCompletionProposals(viewer, invokeOffset); @@ -512,10 +554,12 @@ public void testSnippetTabStops() throws CoreException { } @Test - public void testMultipleLS() throws Exception { + public void testMultipleLS(MockLanguageServerFactory factory) throws Exception { final var items = new ArrayList(); items.add(createCompletionItem("FirstClass", CompletionItemKind.Class)); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(false, items)); + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(false, items)); + }); IFile testFile = TestUtils.createUniqueTestFileMultiLS(project, ""); ITextViewer viewer = TestUtils.openTextViewer(testFile); @@ -525,10 +569,12 @@ public void testMultipleLS() throws Exception { } @Test - public void testReopeningFileAndReusingContentAssist() throws CoreException { + public void testReopeningFileAndReusingContentAssist(MockLanguageServerFactory factory) throws CoreException { final var items = new ArrayList(); items.add(createCompletionItem("FirstClass", CompletionItemKind.Class)); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(false, items)); + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(false, items)); + }); IFile testFile = TestUtils.createUniqueTestFile(project, ""); ITextViewer viewer = TestUtils.openTextViewer(testFile); @@ -540,9 +586,7 @@ public void testReopeningFileAndReusingContentAssist() throws CoreException { assertEquals(new Point("FirstClass".length(), 0), lsCompletionProposal.getSelection(viewer.getDocument())); UI.getActivePage().closeAllEditors(false); - MockLanguageServer.reset(); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(false, items)); viewer = TestUtils.openTextViewer(testFile); proposals = contentAssistProcessor.computeCompletionProposals(viewer, 0); @@ -553,7 +597,7 @@ public void testReopeningFileAndReusingContentAssist() throws CoreException { } @Test - public void testFilterNonmatchingCompletions() throws Exception { + public void testFilterNonmatchingCompletions(MockLanguageServerFactory factory) throws Exception { final var items = new ArrayList(); var item = new CompletionItem("server.web"); item.setFilterText("server.web"); @@ -568,7 +612,7 @@ public void testFilterNonmatchingCompletions() throws Exception { items.add(new CompletionItem(": 1.0.1")); items.add(new CompletionItem("s.Status")); - confirmCompletionResults(items, "server", 6, new String[] { "server.web", ": 1.0.1", "s.Status" }); + confirmCompletionResults(items, "server", 6, new String[] { "server.web", ": 1.0.1", "s.Status" }, factory); } @Test @@ -587,11 +631,13 @@ public void testFilterNonmatchingCompletionsMovieOffset() throws Exception { } @Test - public void testAdjustIndentation() throws Exception { - ITextViewer viewer = TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project, "a\n\tb\n\t\nc")); + public void testAdjustIndentation(MockLanguageServerFactory factory) throws Exception { final var item = new CompletionItem("line1\nline2"); item.setInsertTextMode(InsertTextMode.AdjustIndentation); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(false, List.of(item))); + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(false, List.of(item))); + }); + ITextViewer viewer = TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project, "a\n\tb\n\t\nc")); int invokeOffset = 6; ICompletionProposal[] proposals = contentAssistProcessor.computeCompletionProposals(viewer, invokeOffset); assertEquals(1, proposals.length); @@ -600,12 +646,14 @@ public void testAdjustIndentation() throws Exception { } @Test - public void testAdjustIndentationIsDefault() throws Exception { - ITextViewer viewer = TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project, "a\n\tb\n\t\nc")); + public void testAdjustIndentationIsDefault(MockLanguageServerFactory factory) throws Exception { final var item = new CompletionItem("line1\nline2"); // No insert mode specified -> fall back to default, which is AdjustIndentation item.setInsertTextMode(null); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(false, List.of(item))); + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(false, List.of(item))); + }); + ITextViewer viewer = TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project, "a\n\tb\n\t\nc")); int invokeOffset = 6; ICompletionProposal[] proposals = contentAssistProcessor.computeCompletionProposals(viewer, invokeOffset); assertEquals(1, proposals.length); @@ -614,11 +662,13 @@ public void testAdjustIndentationIsDefault() throws Exception { } @Test - public void testAdjustIndentationWithPrefixInLine() throws Exception { - ITextViewer viewer = TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project, "a\n\tb\n\tprefix\nc")); + public void testAdjustIndentationWithPrefixInLine(MockLanguageServerFactory factory) throws Exception { final var item = new CompletionItem("line1\n\tline2\nline3"); item.setInsertTextMode(InsertTextMode.AdjustIndentation); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(false, List.of(item))); + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(false, List.of(item))); + }); + ITextViewer viewer = TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project, "a\n\tb\n\tprefix\nc")); int invokeOffset = 12; ICompletionProposal[] proposals = contentAssistProcessor.computeCompletionProposals(viewer, invokeOffset); assertEquals(1, proposals.length); @@ -627,16 +677,15 @@ public void testAdjustIndentationWithPrefixInLine() throws Exception { } @Test - public void testCancellation() throws Exception { - MockConnectionProvider.cancellations.clear(); + public void testCancellation(MockLanguageServerFactory factory) throws Exception { ITextViewer viewer = TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project, "a\n\tb\n\t\nc")); final var item = new CompletionItem("a"); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(false, List.of(item))); - MockLanguageServer.INSTANCE.setTimeToProceedQueries(10000); + factory.getServer().setCompletionList(new CompletionList(false, List.of(item))); + factory.getServer().setTimeToProceedQueries(10000); CompletableFuture.runAsync(() -> contentAssistProcessor.computeCompletionProposals(viewer, 1)); Thread.sleep(500); CompletableFuture.runAsync(() -> contentAssistProcessor.computeCompletionProposals(viewer, 1)); - DisplayHelper.waitAndAssertCondition(viewer.getTextWidget().getDisplay(), () -> assertEquals(1, MockConnectionProvider.cancellations.size())); + DisplayHelper.waitAndAssertCondition(viewer.getTextWidget().getDisplay(), () -> assertEquals(1, factory.cancellations.size())); } /** @@ -644,13 +693,15 @@ public void testCancellation() throws Exception { * the start of the edit range when available. */ @Test - public void testContextInformationPositionUsesEditRangeStart() throws CoreException { + public void testContextInformationPositionUsesEditRangeStart(MockLanguageServerFactory factory) throws CoreException { final int editOffset = 2; CompletionItem completionItem = createCompletionItem( // "hello", // CompletionItemKind.Text, // new Range(new Position(0, editOffset), new Position(0, editOffset + 1))); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(true, List.of(completionItem))); + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(true, List.of(completionItem))); + }); ITextViewer viewer = TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project, "ABCDE")); @@ -668,14 +719,16 @@ public void testContextInformationPositionUsesEditRangeStart() throws CoreExcept * even when the TextEdit range is on a different line. */ @Test - public void testVariablesUseViewerLineNotEditRange() throws CoreException { + public void testVariablesUseViewerLineNotEditRange(MockLanguageServerFactory factory) throws CoreException { final CompletionItem completionItem = createCompletionItem( // "$TM_LINE_INDEX $TM_LINE_NUMBER $TM_CURRENT_LINE", // CompletionItemKind.Snippet, // // Replace the entire 3rd line (line2) to avoid trailing leftovers new Range(new Position(2, 0), new Position(2, 5))); completionItem.setInsertTextFormat(InsertTextFormat.Snippet); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(true, List.of(completionItem))); + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(true, List.of(completionItem))); + }); ITextViewer viewer = TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project, "line0\nline1\nline2")); diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/completion/CompletionOrderingTests.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/completion/CompletionOrderingTests.java index 5dabeca45..28ed73336 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/completion/CompletionOrderingTests.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/completion/CompletionOrderingTests.java @@ -24,6 +24,7 @@ import org.eclipse.lsp4e.operations.completion.LSCompletionProposal; import org.eclipse.lsp4e.test.utils.TestUtils; import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4j.CompletionItem; import org.eclipse.lsp4j.CompletionItemKind; import org.eclipse.lsp4j.CompletionList; @@ -32,88 +33,77 @@ import org.eclipse.lsp4j.TextEdit; import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.FieldSource; public class CompletionOrderingTests extends AbstractCompletionTest { @Test - public void testItemOrdering() throws Exception { + public void testItemOrdering(MockLanguageServerFactory factory) throws Exception { confirmCompletionResults(new String[] { "AA", "AB", "BA", "BB", "CB", "CC" }, "B", 1, - new String[] { "BA", "BB", "AB", "CB" }); + new String[] { "BA", "BB", "AB", "CB" }, factory); } - @Test - public void testOrderByCategory() throws Exception { - // Category 1 before Category 2 (testa) - var completions = new String[] { "testa", "test.a", "a.test.a", "a.testa", "test" }; - var orderedResults = new String[] { "test", "testa", "a.testa", "test.a", "a.test.a" }; - confirmCompletionResults(completions, "test", 4, orderedResults); - - // Category 2 before Category 3 (atest) - completions = new String[] { "testa", "atest", "a.testa" }; - orderedResults = new String[] { "testa", "a.testa", "atest" }; - confirmCompletionResults(completions, "test", 4, orderedResults); - - // Category 3 before Category 4 (tZesZt) - completions = new String[] { "atesta", "tZesZt", "atest" }; - orderedResults = new String[] { "atest", "atesta", "tZesZt" }; - confirmCompletionResults(completions, "test", 4, orderedResults); - - // Category 4 before Category 5 (qwerty) - completions = new String[] { "qwerty", "tZesZt", "t.e.s.t" }; - orderedResults = new String[] { "tZesZt", "t.e.s.t", "qwerty" }; - confirmCompletionResults(completions, "test", 4, orderedResults); + public static final Arguments[] testOrderByCategory = { + Arguments.argumentSet("Category 1 before Category 2 (testa)", + new String[] { "testa", "test.a", "a.test.a", "a.testa", "test" }, + new String[] { "test", "testa", "a.testa", "test.a", "a.test.a" }), + Arguments.argumentSet("Category 2 before Category 3 (atest)", new String[] { "testa", "atest", "a.testa" }, + new String[] { "testa", "a.testa", "atest" }), + Arguments.argumentSet("Category 3 before Category 4 (tZesZt)", new String[] { "atesta", "tZesZt", "atest" }, + new String[] { "atest", "atesta", "tZesZt" }), + Arguments.argumentSet("Category 4 before Category 5 (qwerty)", + new String[] { "qwerty", "tZesZt", "t.e.s.t" }, new String[] { "tZesZt", "t.e.s.t", "qwerty" }) }; + + @ParameterizedTest + @FieldSource + public void testOrderByCategory(String[] completions, String[] orderedResults, MockLanguageServerFactory factory) throws Exception { + confirmCompletionResults(completions, "test", 4, orderedResults, factory); } - - @Test - public void testOrderByRank() throws Exception { - // Category 1 - var completions = new String[] { "prefix.test", "alongprefix.test", "test", "test.test", "pretest.test" }; - var orderedResults = new String[] { "test", "test.test", "pretest.test", "prefix.test", - "alongprefix.test" }; - confirmCompletionResults(completions, "test", 4, orderedResults); - - // Category 2 - completions = new String[] { "testa", "alongprefix.testa", "testatest", "prefix.testa" }; - orderedResults = new String[] { "testa", "prefix.testa", "alongprefix.testa", "testatest" }; - confirmCompletionResults(completions, "test", 4, orderedResults); - - // Category 3 - completions = new String[] { "atesta", "teteteststst", "long.prefixtest.suffix" }; - orderedResults = new String[] { "atesta", "teteteststst", "long.prefixtest.suffix" }; - confirmCompletionResults(completions, "test", 4, orderedResults); - - // Category 4 - completions = new String[] { "tlongbreakbetweenest", "tZesZt", "t.e.s.t", "tes.tst" }; - orderedResults = new String[] { "tes.tst", "tZesZt", "t.e.s.t", "tlongbreakbetweenest" }; - confirmCompletionResults(completions, "test", 4, orderedResults); + + public static final Arguments[] testOrderByRank = { + Arguments.argumentSet("Category 1", + new String[] { "prefix.test", "alongprefix.test", "test", "test.test", "pretest.test" }, + new String[] { "test", "test.test", "pretest.test", "prefix.test", "alongprefix.test" }), + Arguments.argumentSet("Category 2", + new String[] { "testa", "alongprefix.testa", "testatest", "prefix.testa" }, + new String[] { "testa", "prefix.testa", "alongprefix.testa", "testatest" }), + Arguments.argumentSet("Category 3", new String[] { "atesta", "teteteststst", "long.prefixtest.suffix" }, + new String[] { "atesta", "teteteststst", "long.prefixtest.suffix" }), + Arguments.argumentSet("Category 4", new String[] { "tlongbreakbetweenest", "tZesZt", "t.e.s.t", "tes.tst" }, + new String[] { "tes.tst", "tZesZt", "t.e.s.t", "tlongbreakbetweenest" }) }; + + @ParameterizedTest + @FieldSource + public void testOrderByRank(String[] completions, String[] orderedResults, MockLanguageServerFactory factory) throws Exception { + confirmCompletionResults(completions, "test", 4, orderedResults, factory); } - @Test - public void testOrderWithCapitalization() throws Exception { - // Category 1 - var completions = new String[] { "prefiX.Test", "alongprefix.test", "tEsT", "teSt.teST", "preTEst.test" }; - var orderedResults = new String[] { "tEsT", "teSt.teST", "preTEst.test", "prefiX.Test", - "alongprefix.test" }; - confirmCompletionResults(completions, "test", 4, orderedResults); - - // Category 2 - completions = new String[] { "teSTa", "alonGPrefix.TESTA", "tEStatest", "prefix.testa" }; - orderedResults = new String[] { "teSTa", "prefix.testa", "alonGPrefix.TESTA", "tEStatest" }; - confirmCompletionResults(completions, "tESt", 4, orderedResults); - - // Category 3 - completions = new String[] { "ATesta", "teTETesTSTst", "long.prefixtest.suffix" }; - orderedResults = new String[] { "ATesta", "teTETesTSTst", "long.prefixtest.suffix" }; - confirmCompletionResults(completions, "TEST", 4, orderedResults); - - // Category 4 - completions = new String[] { "TlongbreakbetweenEST", "TZesZT", "t.e.s.t", "teS.tst" }; - orderedResults = new String[] { "teS.tst", "TZesZT", "t.e.s.t", "TlongbreakbetweenEST" }; - confirmCompletionResults(completions, "test", 4, orderedResults); + public static final Arguments[] testOrderWithCapitalization = { + Arguments.argumentSet("Category 1", + new String[] { "prefiX.Test", "alongprefix.test", "tEsT", "teSt.teST", "preTEst.test" }, + new String[] { "tEsT", "teSt.teST", "preTEst.test", "prefiX.Test", + "alongprefix.test" }), + Arguments.argumentSet("Category 2", + new String[] { "teSTa", "alonGPrefix.TESTA", "tEStatest", "prefix.testa" }, + new String[] { "teSTa", "prefix.testa", "alonGPrefix.TESTA", "tEStatest" }), + Arguments.argumentSet("Category 3", + new String[] { "ATesta", "teTETesTSTst", "long.prefixtest.suffix" }, + new String[] { "ATesta", "teTETesTSTst", "long.prefixtest.suffix" }), + Arguments.argumentSet("Category 4", + new String[] { "TlongbreakbetweenEST", "TZesZT", "t.e.s.t", "teS.tst" }, + new String[] { "teS.tst", "TZesZT", "t.e.s.t", "TlongbreakbetweenEST" }), + }; + + @ParameterizedTest + @FieldSource + public void testOrderWithCapitalization(String[] completions, String[] orderedResults, MockLanguageServerFactory factory) throws Exception { + confirmCompletionResults(completions, "test", 4, orderedResults, factory); } @Test - public void testOrderWithLongInsert() throws Exception { + public void testOrderWithLongInsert(MockLanguageServerFactory factory) throws Exception { var items = new ArrayList(); var item = new CompletionItem("server.address"); item.setFilterText("server.address"); @@ -147,11 +137,11 @@ public void testOrderWithLongInsert() throws Exception { " application:\n" + " name: f\n" + "address", - 62, orderedResults); + 62, orderedResults, factory); } @Test - public void testSortTextIsComparedLexicographically() throws Exception { + public void testSortTextIsComparedLexicographically(MockLanguageServerFactory factory) throws Exception { final var completions = new ArrayList(); final var item15 = createCompletionItem("15", CompletionItemKind.Class); @@ -162,7 +152,7 @@ public void testSortTextIsComparedLexicographically() throws Exception { item5.setSortText("5"); completions.add(item5); - confirmCompletionResults(completions, "", 0, new String[] { "15", "5" }); + confirmCompletionResults(completions, "", 0, new String[] { "15", "5" }, factory); } @Test @@ -209,7 +199,7 @@ public void testMovingOffset() throws Exception { } @Test - public void testPerformance() throws Exception { + public void testPerformance(MockLanguageServerFactory factory) throws Exception { final var batchSizes = new int[] { 10, 100, 1000, 10000 }; final var resultAverages = new int[batchSizes.length]; final int repeat = 5; @@ -218,7 +208,7 @@ public void testPerformance() throws Exception { for (int i = 0; i < batchSizes.length; i++) { long resultSum = 0; for (int j = 0; j < repeat; j++) { - resultSum += timeToDisplayCompletionList(viewer, batchSizes[i]); + resultSum += timeToDisplayCompletionList(viewer, batchSizes[i], factory.getServer()); } resultAverages[i] = (int) (resultSum / repeat); } @@ -247,13 +237,13 @@ private double isLinearCorelation(int[] batchSizes, int[] resultAverages) { return denominator == 0 ? 0 : numerator / denominator; } - private long timeToDisplayCompletionList(ITextViewer viewer, int size) { + private long timeToDisplayCompletionList(ITextViewer viewer, int size, MockLanguageServer mockLanguageServer) { final var range = new Range(new Position(0, 0), new Position(0, 8)); final var items = new ArrayList(); for (int i = 0; i < size; i++) { items.add(createCompletionItem(randomString(), CompletionItemKind.Class, range)); } - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(false, items)); + mockLanguageServer.setCompletionList(new CompletionList(false, items)); long startTimeControl = System.currentTimeMillis(); contentAssistProcessor.computeCompletionProposals(viewer, 0); diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/completion/ContextInformationTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/completion/ContextInformationTest.java index badbb1502..53830e0cf 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/completion/ContextInformationTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/completion/ContextInformationTest.java @@ -25,7 +25,7 @@ import org.eclipse.lsp4e.LSPEclipseUtils; import org.eclipse.lsp4e.operations.completion.LSContentAssistProcessor; import org.eclipse.lsp4e.test.utils.TestUtils; -import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4j.SignatureHelp; import org.eclipse.lsp4j.SignatureInformation; import org.junit.jupiter.api.BeforeEach; @@ -40,8 +40,10 @@ public void setUp() { } @Test - public void testNoContextInformation() throws CoreException { - MockLanguageServer.INSTANCE.setSignatureHelp(new SignatureHelp()); + public void testNoContextInformation(MockLanguageServerFactory factory) throws CoreException { + factory.withConfiguration((idx, server)-> { + server.setSignatureHelp(new SignatureHelp()); + }); IFile testFile = TestUtils.createUniqueTestFile(project, ""); ITextViewer viewer = TestUtils.openTextViewer(testFile); @@ -51,11 +53,13 @@ public void testNoContextInformation() throws CoreException { } @Test - public void testContextInformationNoParameters() throws CoreException { + public void testContextInformationNoParameters(MockLanguageServerFactory factory) throws CoreException { final var signatureHelp = new SignatureHelp(); final var information = new SignatureInformation("label", "documentation", Collections.emptyList()); signatureHelp.setSignatures(List.of(information)); - MockLanguageServer.INSTANCE.setSignatureHelp(signatureHelp); + factory.withConfiguration((idx, server) -> { + server.setSignatureHelp(signatureHelp); + }); IFile testFile = TestUtils.createUniqueTestFile(project, "method()"); ITextViewer viewer = TestUtils.openTextViewer(testFile); @@ -70,9 +74,11 @@ public void testContextInformationNoParameters() throws CoreException { } @Test - public void testTriggerChars() throws CoreException { + public void testTriggerChars(MockLanguageServerFactory factory) throws CoreException { final Set triggers = Set.of("a", "b"); - MockLanguageServer.INSTANCE.setContextInformationTriggerChars(triggers); + factory.withConfiguration((idx, server) -> { + server.setContextInformationTriggerChars(triggers); + }); final var content = "First"; TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project, content)); @@ -82,8 +88,10 @@ public void testTriggerChars() throws CoreException { } @Test - public void testTriggerCharsNullList() throws CoreException { - MockLanguageServer.INSTANCE.setContextInformationTriggerChars(null); + public void testTriggerCharsNullList(MockLanguageServerFactory factory) throws CoreException { + factory.withConfiguration((idx, server)-> { + server.setContextInformationTriggerChars(null); + }); TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project, "First")); diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/completion/DynamicCompletionRegistrationTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/completion/DynamicCompletionRegistrationTest.java index a751b94e1..756aa047d 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/completion/DynamicCompletionRegistrationTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/completion/DynamicCompletionRegistrationTest.java @@ -26,7 +26,7 @@ import org.eclipse.lsp4e.operations.completion.LSContentAssistProcessor; import org.eclipse.lsp4e.test.utils.AbstractTestWithProject; import org.eclipse.lsp4e.test.utils.TestUtils; -import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4j.CompletionItem; import org.eclipse.lsp4j.CompletionItemKind; import org.eclipse.lsp4j.CompletionList; @@ -52,17 +52,17 @@ public class DynamicCompletionRegistrationTest extends AbstractTestWithProject { @BeforeEach public void setup() { contentAssistProcessor = new LSContentAssistProcessor(true, false); - } + } @Test - public void testDynamicCompletionRegistrationProvidesProposalsAndTriggers() throws Exception { + public void testDynamicCompletionRegistrationProvidesProposalsAndTriggers(MockLanguageServerFactory factory) throws Exception { // Prepare a file and open a viewer IFile file = TestUtils.createUniqueTestFile(project, ""); ITextViewer viewer = TestUtils.openTextViewer(file); // Ensure the mock LS is up - waitForAndAssertCondition(5_000, () -> !MockLanguageServer.INSTANCE.getRemoteProxies().isEmpty()); - LanguageClient client = getMockClient(); + waitForAndAssertCondition(5_000, () -> factory.getServerCount() == 1); + LanguageClient client = factory.getServer().getRemoteProxy(); assertNotNull(client); // Provide a simple completion item in the mock LS @@ -72,7 +72,7 @@ public void testDynamicCompletionRegistrationProvidesProposalsAndTriggers() thro item.setKind(CompletionItemKind.Text); item.setTextEdit(Either.forLeft(new TextEdit(new Range(new Position(0, 0), new Position(0, 0)), "Alpha"))); items.add(item); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(false, items)); + factory.getServer().setCompletionList(new CompletionList(false, items)); // Dynamically register completion with trigger characters (server-like behavior) var registration = new Registration(); @@ -96,9 +96,4 @@ public void testDynamicCompletionRegistrationProvidesProposalsAndTriggers() thro assertTrue(trig.indexOf('#') >= 0); } - private LanguageClient getMockClient() { - var proxies = MockLanguageServer.INSTANCE.getRemoteProxies(); - assertEquals(1, proxies.size()); - return proxies.get(0); - } } diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/completion/IncompleteCompletionTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/completion/IncompleteCompletionTest.java index b725afe39..07ed85522 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/completion/IncompleteCompletionTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/completion/IncompleteCompletionTest.java @@ -42,7 +42,7 @@ import org.eclipse.lsp4e.operations.completion.LSCompletionProposal; import org.eclipse.lsp4e.operations.completion.LSContentAssistProcessor; import org.eclipse.lsp4e.test.utils.TestUtils; -import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4e.ui.UI; import org.eclipse.lsp4j.CompletionItem; import org.eclipse.lsp4j.CompletionItemKind; @@ -66,11 +66,13 @@ public class IncompleteCompletionTest extends AbstractCompletionTest { * file-specific LS already associated is something we want to support. */ @Test - public void testAssistForUnknownButConnectedType() throws CoreException { + public void testAssistForUnknownButConnectedType(MockLanguageServerFactory factory) throws CoreException { final var items = new ArrayList(); items.add(createCompletionItem("FirstClass", CompletionItemKind.Class)); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(true, items)); - + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(true, items)); + }); + IFile testFile = TestUtils.createUniqueTestFileOfUnknownType(project, ""); ITextViewer viewer = TestUtils.openTextViewer(testFile); @@ -93,10 +95,12 @@ public void testAssistForUnknownButConnectedType() throws CoreException { } @Test - public void testNoPrefix() throws CoreException { + public void testNoPrefix(MockLanguageServerFactory factory) throws CoreException { final var items = new ArrayList(); items.add(createCompletionItem("FirstClass", CompletionItemKind.Class)); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(true, items)); + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(true, items)); + }); IFile testFile = TestUtils.createUniqueTestFile(project, ""); ITextViewer viewer = TestUtils.openTextViewer(testFile); @@ -111,14 +115,16 @@ public void testNoPrefix() throws CoreException { } @Test - public void testDeprecatedCompletion() throws Exception { + public void testDeprecatedCompletion(MockLanguageServerFactory factory) throws Exception { BoldStylerProvider boldStyleProvider = null; try { final var items = new ArrayList(); CompletionItem completionItem = createCompletionItem("FirstClassDeprecated", CompletionItemKind.Class); completionItem.setDeprecated(true); items.add(completionItem); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(true, items)); + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(true, items)); + }); final var content = "First"; ITextViewer viewer = TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project, content)); @@ -148,11 +154,13 @@ public void testDeprecatedCompletion() throws Exception { } @Test - public void testPrefix() throws CoreException { + public void testPrefix(MockLanguageServerFactory factory) throws CoreException { final var items = new ArrayList(); items.add(createCompletionItem("FirstClass", CompletionItemKind.Class)); items.add(createCompletionItem("SecondClass", CompletionItemKind.Class)); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(true, items)); + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(true, items)); + }); final var content = "First"; ITextViewer viewer = TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project, content)); @@ -167,10 +175,12 @@ public void testPrefix() throws CoreException { } @Test - public void testPrefixCaseSensitivity() throws CoreException { + public void testPrefixCaseSensitivity(MockLanguageServerFactory factory) throws CoreException { final var items = new ArrayList(); items.add(createCompletionItem("FirstClass", CompletionItemKind.Class)); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(true, items)); + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(true, items)); + }); final var content = "FIRST"; ITextViewer viewer = TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project, content)); @@ -185,13 +195,16 @@ public void testPrefixCaseSensitivity() throws CoreException { } @Test - public void testCompleteOnFileEnd() throws CoreException { // bug 508842 + public void testCompleteOnFileEnd(MockLanguageServerFactory factory) throws CoreException { // bug 508842 final var item = new CompletionItem(); item.setLabel("1024M"); item.setKind(CompletionItemKind.Value); item.setTextEdit(Either.forLeft(new TextEdit(new Range(new Position(2, 10), new Position(2, 10)), "1024M"))); final var completionList = new CompletionList(true, List.of(item)); - MockLanguageServer.INSTANCE.setCompletionList(completionList); + + factory.withConfiguration((idx, server) -> { + server.setCompletionList(completionList); + }); final var content = "applications:\n" + "- name: hello\n" + " memory: "; ITextViewer viewer = TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project, content)); @@ -207,7 +220,7 @@ public void testCompleteOnFileEnd() throws CoreException { // bug 508842 } @Test - public void testCompletionWithAdditionalEditsBeforeOffsetInSameLine() throws CoreException { + public void testCompletionWithAdditionalEditsBeforeOffsetInSameLine(MockLanguageServerFactory factory) throws CoreException { final var items = new ArrayList(); final var item = new CompletionItem("additionaEditsCompletion"); item.setKind(CompletionItemKind.Function); @@ -222,7 +235,9 @@ public void testCompletionWithAdditionalEditsBeforeOffsetInSameLine() throws Cor item.setAdditionalTextEdits(additionalTextEdits); items.add(item); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(true, items)); + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(true, items)); + }); final var content = "this <> is <> the main <> content of the file"; IFile testFile = TestUtils.createUniqueTestFile(project, content); @@ -239,7 +254,7 @@ public void testCompletionWithAdditionalEditsBeforeOffsetInSameLine() throws Cor } @Test - public void testCompletionWithAdditionalEditsBeforeAndAfterOffsetInSameLine() throws CoreException { + public void testCompletionWithAdditionalEditsBeforeAndAfterOffsetInSameLine(MockLanguageServerFactory factory) throws CoreException { final var items = new ArrayList(); final var item = new CompletionItem("additionaEditsCompletion"); item.setKind(CompletionItemKind.Function); @@ -254,7 +269,9 @@ public void testCompletionWithAdditionalEditsBeforeAndAfterOffsetInSameLine() th item.setAdditionalTextEdits(additionalTextEdits); items.add(item); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(true, items)); + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(true, items)); + }); final var content = "this <> is <> the main <> content of the file"; IFile testFile = TestUtils.createUniqueTestFile(project, content); @@ -271,7 +288,7 @@ public void testCompletionWithAdditionalEditsBeforeAndAfterOffsetInSameLine() th } @Test - public void testCompletionWithAdditionalEditsBeforeAndAfterOffsetInVariousLines() throws CoreException { + public void testCompletionWithAdditionalEditsBeforeAndAfterOffsetInVariousLines(MockLanguageServerFactory factory) throws CoreException { final var items = new ArrayList(); final var item = new CompletionItem("additionaEditsCompletion"); item.setKind(CompletionItemKind.Function); @@ -288,7 +305,9 @@ public void testCompletionWithAdditionalEditsBeforeAndAfterOffsetInVariousLines( item.setAdditionalTextEdits(additionalTextEdits); items.add(item); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(true, items)); + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(true, items)); + }); final var content = "this <> is <> the main <> content of the file\nthis is <> the second line"; IFile testFile = TestUtils.createUniqueTestFile(project, content); @@ -305,7 +324,7 @@ public void testCompletionWithAdditionalEditsBeforeAndAfterOffsetInVariousLines( } @Test - public void testCompletionWithAdditionalEditsBeforeAndAfterOffsetInVariousLinesAndTypedText() throws CoreException { + public void testCompletionWithAdditionalEditsBeforeAndAfterOffsetInVariousLinesAndTypedText(MockLanguageServerFactory factory) throws CoreException { final var items = new ArrayList(); final var item = new CompletionItem("additionaEditsCompletion"); item.setKind(CompletionItemKind.Function); @@ -322,7 +341,9 @@ public void testCompletionWithAdditionalEditsBeforeAndAfterOffsetInVariousLinesA item.setAdditionalTextEdits(additionalTextEdits); items.add(item); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(true, items)); + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(true, items)); + }); final var content = "this <> is
the main <> content of the file\nthis is <> the second line"; IFile testFile = TestUtils.createUniqueTestFile(project, content); @@ -339,7 +360,7 @@ public void testCompletionWithAdditionalEditsBeforeAndAfterOffsetInVariousLinesA } @Test - public void testSnippetCompletionWithAdditionalEdits() throws CoreException { + public void testSnippetCompletionWithAdditionalEdits(MockLanguageServerFactory factory) throws CoreException { final var item = new CompletionItem("snippet item"); item.setInsertText("$1 and ${2:foo}"); item.setKind(CompletionItemKind.Class); @@ -353,7 +374,9 @@ public void testSnippetCompletionWithAdditionalEdits() throws CoreException { item.setAdditionalTextEdits(additionalTextEdits); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(true, List.of(item))); + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(true, List.of(item))); + }); final var content = "this <> is <> the main <> content of the file"; ITextViewer viewer = TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project, content)); @@ -368,11 +391,13 @@ public void testSnippetCompletionWithAdditionalEdits() throws CoreException { } @Test - public void testApplyCompletionWithPrefix() throws CoreException { + public void testApplyCompletionWithPrefix(MockLanguageServerFactory factory) throws CoreException { final var range = new Range(new Position(0, 0), new Position(0, 5)); List items = List .of(createCompletionItem("FirstClass", CompletionItemKind.Class, range)); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(true, items)); + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(true, items)); + }); final var content = "First"; ITextViewer viewer = TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project, content)); @@ -386,11 +411,13 @@ public void testApplyCompletionWithPrefix() throws CoreException { } @Test - public void testApplyCompletionReplace() throws CoreException { + public void testApplyCompletionReplace(MockLanguageServerFactory factory) throws CoreException { final var range = new Range(new Position(0, 0), new Position(0, 20)); List items = List .of(createCompletionItem("FirstClass", CompletionItemKind.Class, range)); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(true, items)); + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(true, items)); + }); final var content = "FirstNotMatchedLabel"; ITextViewer viewer = TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project, content)); @@ -403,11 +430,13 @@ public void testApplyCompletionReplace() throws CoreException { } @Test - public void testApplyCompletionReplaceAndTypingWithTextEdit() throws CoreException, BadLocationException { + public void testApplyCompletionReplaceAndTypingWithTextEdit(MockLanguageServerFactory factory) throws CoreException, BadLocationException { final var range = new Range(new Position(0, 0), new Position(0, 22)); List items = List .of(createCompletionItem("FirstClass", CompletionItemKind.Class, range)); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(true, items)); + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(true, items)); + }); final var content = "FirstNotMatchedLabel"; ITextViewer viewer = TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project,content)); @@ -426,12 +455,13 @@ public void testApplyCompletionReplaceAndTypingWithTextEdit() throws CoreExcepti } @Test - public void testApplyCompletionReplaceAndTyping() throws CoreException, BadLocationException { + public void testApplyCompletionReplaceAndTyping(MockLanguageServerFactory factory) throws CoreException, BadLocationException { final var item = new CompletionItem("strncasecmp"); item.setKind(CompletionItemKind.Function); item.setInsertText("strncasecmp()"); - - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(true, List.of(item))); + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(true, List.of(item))); + }); final var content = "str"; ITextViewer viewer = TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project, content)); @@ -451,12 +481,14 @@ public void testApplyCompletionReplaceAndTyping() throws CoreException, BadLocat } @Test - public void testCompletionReplace() throws CoreException { + public void testCompletionReplace(MockLanguageServerFactory factory) throws CoreException { + factory.withConfiguration((idx, server) -> { + server.setCompletionList( + new CompletionList(true, List.of(createCompletionItem("Inserted", CompletionItemKind.Text, + new Range(new Position(1, 4), new Position(1, 4 + "InsertHere".length())))))); + }); IFile file = TestUtils.createUniqueTestFile(project, "line1\nlineInsertHere"); ITextViewer viewer = TestUtils.openTextViewer(file); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(true, List.of( - createCompletionItem("Inserted", CompletionItemKind.Text, new Range(new Position(1, 4), new Position(1, 4 + "InsertHere".length()))) - ))); int invokeOffset = viewer.getDocument().getLength() - "InsertHere".length(); ICompletionProposal[] proposals = contentAssistProcessor.computeCompletionProposals(viewer, invokeOffset); @@ -468,7 +500,7 @@ public void testCompletionReplace() throws CoreException { } @Test - public void testItemOrdering() throws Exception { + public void testItemOrdering(MockLanguageServerFactory factory) throws Exception { final var range = new Range(new Position(0, 0), new Position(0, 1)); List items = List.of( // createCompletionItem("AA", CompletionItemKind.Class, range), @@ -477,7 +509,9 @@ public void testItemOrdering() throws Exception { createCompletionItem("BB", CompletionItemKind.Class, range), createCompletionItem("CB", CompletionItemKind.Class, range), createCompletionItem("CC", CompletionItemKind.Class, range)); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(true, items)); + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(true, items)); + }); final var content = "B"; ITextViewer viewer = TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project,content)); @@ -495,11 +529,12 @@ public void testItemOrdering() throws Exception { } @Test - public void testBasicSnippet() throws CoreException { + public void testBasicSnippet(MockLanguageServerFactory factory) throws CoreException { CompletionItem completionItem = createCompletionItem("$1 and ${2:foo}", CompletionItemKind.Class, new Range(new Position(0, 0), new Position(0, 1))); completionItem.setInsertTextFormat(InsertTextFormat.Snippet); - MockLanguageServer.INSTANCE - .setCompletionList(new CompletionList(true, List.of(completionItem))); + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(true, List.of(completionItem))); + }); ITextViewer viewer = TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project,"")); int invokeOffset = 0; ICompletionProposal[] proposals = contentAssistProcessor.computeCompletionProposals(viewer, invokeOffset); @@ -510,10 +545,12 @@ public void testBasicSnippet() throws CoreException { } @Test - public void testMultipleLS() throws Exception { + public void testMultipleLS(MockLanguageServerFactory factory) throws Exception { final var items = new ArrayList(); items.add(createCompletionItem("FirstClass", CompletionItemKind.Class)); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(true, items)); + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(true, items)); + }); IFile testFile = TestUtils.createUniqueTestFileMultiLS(project, ""); ITextViewer viewer = TestUtils.openTextViewer(testFile); @@ -523,7 +560,7 @@ public void testMultipleLS() throws Exception { } @Test - public void testCompletionWithAdditionalTextEditInsertion() throws Exception { + public void testCompletionWithAdditionalTextEditInsertion(MockLanguageServerFactory factory) throws Exception { IFile file = TestUtils.createUniqueTestFile(project, "Some Text Before\ntagText\nSome Text After"); ITextViewer viewer = TestUtils.openTextViewer(file); // Create item @@ -546,7 +583,7 @@ public void testCompletionWithAdditionalTextEditInsertion() throws Exception { "\npostfixText")); item.setAdditionalTextEdits(additionalEdits); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(true, List.of(item))); + factory.getServer().setCompletionList(new CompletionList(true, List.of(item))); String text = viewer.getDocument().get(); int invokeOffset = text.indexOf("tag") + "tag".length(); @@ -568,10 +605,12 @@ public void testCompletionWithAdditionalTextEditInsertion() throws Exception { } @Test - public void testCompletionExternalFile(@TempDir Path tempDir) throws Exception { + public void testCompletionExternalFile(@TempDir Path tempDir, MockLanguageServerFactory factory) throws Exception { final var items = new ArrayList(); items.add(createCompletionItem("FirstClassExternal", CompletionItemKind.Class)); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(true, items)); + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(true, items)); + }); Path file = Files.createFile(tempDir.resolve("testCompletionExternalFile.lspt")); final var editor = (ITextEditor) IDE.openEditorOnFileStore(UI.getActivePage(), EFS.getStore(file.toUri())); @@ -655,10 +694,12 @@ public void testAdditionalInformationWithDocumentation() throws Exception { } @Test - public void testIncompleteIndication() throws CoreException { + public void testIncompleteIndication(MockLanguageServerFactory factory) throws CoreException { final var items = new ArrayList(); items.add(createCompletionItem("FirstClass", CompletionItemKind.Class)); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(true, items)); + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(true, items)); + }); IFile testFile = TestUtils.createUniqueTestFile(project, ""); ITextViewer viewer = TestUtils.openTextViewer(testFile); @@ -679,8 +720,10 @@ public void testIncompleteIndication() throws CoreException { } @Test - public void testIncompleteIndicationWithEmptyList() throws CoreException { - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(true, List.of())); + public void testIncompleteIndicationWithEmptyList(MockLanguageServerFactory factory) throws CoreException { + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(true, List.of())); + }); IFile testFile = TestUtils.createUniqueTestFile(project, ""); ITextViewer viewer = TestUtils.openTextViewer(testFile); diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/completion/InsertReplaceCompletionTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/completion/InsertReplaceCompletionTest.java index 2cd2cf7c1..5a948ca9f 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/completion/InsertReplaceCompletionTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/completion/InsertReplaceCompletionTest.java @@ -25,7 +25,7 @@ import org.eclipse.jface.text.contentassist.ICompletionProposal; import org.eclipse.lsp4e.operations.completion.LSCompletionProposal; import org.eclipse.lsp4e.test.utils.TestUtils; -import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4j.CompletionItemKind; import org.eclipse.lsp4j.CompletionList; import org.eclipse.lsp4j.Position; @@ -36,16 +36,18 @@ public class InsertReplaceCompletionTest extends AbstractCompletionTest { @Test - public void testInsert() throws Exception { + public void testInsert(MockLanguageServerFactory factory) throws Exception { + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(false, List.of( + createCompletionItemWithInsertReplace( + "Inserted", + CompletionItemKind.Text, + new Range(new Position(1, 4), new Position(1, 4 + "InsertHere".length())), + new Range(new Position(0,0),new Position(0,0))) + ))); + }); IFile file = TestUtils.createUniqueTestFile(project, "line1\nlineInsertHere"); ITextViewer viewer = TestUtils.openTextViewer(file); - MockLanguageServer.INSTANCE.setCompletionList(new CompletionList(false, List.of( - createCompletionItemWithInsertReplace( - "Inserted", - CompletionItemKind.Text, - new Range(new Position(1, 4), new Position(1, 4 + "InsertHere".length())), - new Range(new Position(0,0),new Position(0,0))) - ))); int invokeOffset = viewer.getDocument().getLength() - "InsertHere".length(); ICompletionProposal[] proposals = contentAssistProcessor.computeCompletionProposals(viewer, invokeOffset); diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/completion/VariableReplacementTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/completion/VariableReplacementTest.java index 9b6e0afe4..49c84f094 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/completion/VariableReplacementTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/completion/VariableReplacementTest.java @@ -18,7 +18,7 @@ import org.eclipse.jface.text.contentassist.ICompletionProposal; import org.eclipse.lsp4e.operations.completion.LSCompletionProposal; import org.eclipse.lsp4e.test.utils.TestUtils; -import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4j.CompletionItem; import org.eclipse.lsp4j.CompletionItemKind; import org.eclipse.lsp4j.CompletionList; @@ -31,11 +31,12 @@ public class VariableReplacementTest extends AbstractCompletionTest { @Test - public void testDuplicateVariable() throws PartInitException, CoreException { + public void testDuplicateVariable(MockLanguageServerFactory factory) throws PartInitException, CoreException { CompletionItem completionItem = createCompletionItem("${1:foo} and ${1:foo}", CompletionItemKind.Class, new Range(new Position(0, 0), new Position(0, 1))); completionItem.setInsertTextFormat(InsertTextFormat.Snippet); - MockLanguageServer.INSTANCE - .setCompletionList(new CompletionList(true, List.of(completionItem))); + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(true, List.of(completionItem))); + }); ITextViewer viewer = TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project,"")); int invokeOffset = 0; ICompletionProposal[] proposals = contentAssistProcessor.computeCompletionProposals(viewer, invokeOffset); @@ -46,13 +47,14 @@ public void testDuplicateVariable() throws PartInitException, CoreException { } @Test - public void testVariableReplacement() throws PartInitException, CoreException { + public void testVariableReplacement(MockLanguageServerFactory factory) throws PartInitException, CoreException { CompletionItem completionItem = createCompletionItem( "${1:$TM_FILENAME_BASE} ${2:$TM_FILENAME} ${3:$TM_FILEPATH} ${4:$TM_DIRECTORY} ${5:$TM_LINE_INDEX} ${6:$TM_LINE_NUMBER} ${7:$TM_CURRENT_LINE} ${8:$TM_SELECTED_TEXT}", CompletionItemKind.Class, new Range(new Position(0, 0), new Position(0, 1))); completionItem.setInsertTextFormat(InsertTextFormat.Snippet); - MockLanguageServer.INSTANCE - .setCompletionList(new CompletionList(true, List.of(completionItem))); + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(true, List.of(completionItem))); + }); final var content = "line1\nline2\nline3"; IFile testFile = TestUtils.createUniqueTestFile(project, content); ITextViewer viewer = TestUtils.openTextViewer(testFile); @@ -71,13 +73,14 @@ public void testVariableReplacement() throws PartInitException, CoreException { } @Test - public void testVariableNameWithoutBraces() throws PartInitException, CoreException { + public void testVariableNameWithoutBraces(MockLanguageServerFactory factory) throws PartInitException, CoreException { CompletionItem completionItem = createCompletionItem( "$TM_FILENAME_BASE", CompletionItemKind.Class, new Range(new Position(0, 0), new Position(0, 1))); completionItem.setInsertTextFormat(InsertTextFormat.Snippet); - MockLanguageServer.INSTANCE - .setCompletionList(new CompletionList(true, List.of(completionItem))); + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(true, List.of(completionItem))); + }); final var content = "line1\nline2\nline3"; IFile testFile = TestUtils.createUniqueTestFile(project, content); ITextViewer viewer = TestUtils.openTextViewer(testFile); @@ -92,13 +95,14 @@ public void testVariableNameWithoutBraces() throws PartInitException, CoreExcept } @Test - public void testVariableNameWithBraces() throws PartInitException, CoreException { + public void testVariableNameWithBraces(MockLanguageServerFactory factory) throws PartInitException, CoreException { CompletionItem completionItem = createCompletionItem( "${TM_FILENAME_BASE}", CompletionItemKind.Class, new Range(new Position(0, 0), new Position(0, 1))); completionItem.setInsertTextFormat(InsertTextFormat.Snippet); - MockLanguageServer.INSTANCE - .setCompletionList(new CompletionList(true, List.of(completionItem))); + factory.withConfiguration((idx, server) -> { + server.setCompletionList(new CompletionList(true, List.of(completionItem))); + }); final var content = "line1\nline2\nline3"; IFile testFile = TestUtils.createUniqueTestFile(project, content); ITextViewer viewer = TestUtils.openTextViewer(testFile); diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/debug/debugmodel/JsonParserWithStringSubstitutionTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/debug/debugmodel/JsonParserWithStringSubstitutionTest.java index 8ecb3c8e1..2cb5096b4 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/debug/debugmodel/JsonParserWithStringSubstitutionTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/debug/debugmodel/JsonParserWithStringSubstitutionTest.java @@ -22,10 +22,9 @@ import org.eclipse.core.variables.IValueVariable; import org.eclipse.core.variables.IValueVariableListener; import org.eclipse.lsp4e.debug.debugmodel.JsonParserWithStringSubstitution; -import org.eclipse.lsp4e.test.utils.AbstractTest; import org.junit.jupiter.api.Test; -public class JsonParserWithStringSubstitutionTest extends AbstractTest { +public class JsonParserWithStringSubstitutionTest { private static final class StringVariableManagerMock implements IStringVariableManager { diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/definition/DefinitionTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/definition/DefinitionTest.java index 69faea54b..4fdf571be 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/definition/DefinitionTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/definition/DefinitionTest.java @@ -33,7 +33,7 @@ import org.eclipse.lsp4e.operations.declaration.OpenDeclarationHyperlinkDetector; import org.eclipse.lsp4e.test.utils.AbstractTestWithProject; import org.eclipse.lsp4e.test.utils.TestUtils; -import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4e.ui.UI; import org.eclipse.lsp4j.Location; import org.eclipse.lsp4j.LocationLink; @@ -49,9 +49,11 @@ public class DefinitionTest extends AbstractTestWithProject { private final OpenDeclarationHyperlinkDetector hyperlinkDetector = new OpenDeclarationHyperlinkDetector(); @Test - public void testDefinitionOneLocation() throws Exception { - final var location = new Location("file://test", new Range(new Position(0, 0), new Position(0, 10))); - MockLanguageServer.INSTANCE.setDefinition(List.of(location)); + public void testDefinitionOneLocation(MockLanguageServerFactory factory) throws Exception { + factory.withConfiguration((idx, server)-> { + final var location = new Location("file://test", new Range(new Position(0, 0), new Position(0, 10))); + server.setDefinition(List.of(location)); + }); IFile file = TestUtils.createUniqueTestFile(project, "Example Text"); ITextViewer viewer = TestUtils.openTextViewer(file); @@ -62,11 +64,13 @@ public void testDefinitionOneLocation() throws Exception { } @Test - public void testDefinitionAndTypeDefinition() throws Exception { - final var definitionRange = new Range(new Position(0, 0), new Position(0, 1)); - MockLanguageServer.INSTANCE.setDefinition(List.of(new Location("file://testDefinition", definitionRange))); - final var typeDefinitionRange = new Range(new Position(0, 2), new Position(0, 3)); - MockLanguageServer.INSTANCE.setTypeDefinitions(List.of(new LocationLink("file://testTypeDefinition", typeDefinitionRange, typeDefinitionRange))); + public void testDefinitionAndTypeDefinition(MockLanguageServerFactory factory) throws Exception { + factory.withConfiguration((idx, server)-> { + final var definitionRange = new Range(new Position(0, 0), new Position(0, 1)); + server.setDefinition(List.of(new Location("file://testDefinition", definitionRange))); + final var typeDefinitionRange = new Range(new Position(0, 2), new Position(0, 3)); + server.setTypeDefinitions(List.of(new LocationLink("file://testTypeDefinition", typeDefinitionRange, typeDefinitionRange))); + }); IFile file = TestUtils.createUniqueTestFile(project, "Example Text"); ITextViewer viewer = TestUtils.openTextViewer(file); @@ -84,9 +88,11 @@ public void testDefinitionAndTypeDefinition() throws Exception { } @Test - public void testDefinitionOneLocationExternalFile(@TempDir Path tempDir) throws Exception { - final var location = new Location("file://test", new Range(new Position(0, 0), new Position(0, 10))); - MockLanguageServer.INSTANCE.setDefinition(List.of(location)); + public void testDefinitionOneLocationExternalFile(@TempDir Path tempDir, MockLanguageServerFactory factory) throws Exception { + factory.withConfiguration((idx, server)-> { + final var location = new Location("file://test", new Range(new Position(0, 0), new Position(0, 10))); + server.setDefinition(List.of(location)); + }); Path file = Files.createFile(tempDir.resolve("testDocumentLinkExternalFile.lspt")); final var editor = (ITextEditor) IDE.openInternalEditorOnFileStore(UI.getActivePage(), EFS.getStore(file.toUri())); @@ -97,12 +103,14 @@ public void testDefinitionOneLocationExternalFile(@TempDir Path tempDir) throws } @Test - public void testDefinitionManyLocation() throws Exception { - final var locations = new ArrayList(); - locations.add(new Location("file://test0", new Range(new Position(0, 0), new Position(0, 10)))); - locations.add(new Location("file://test1", new Range(new Position(1, 0), new Position(1, 10)))); - locations.add(new Location("file://test2", new Range(new Position(2, 0), new Position(2, 10)))); - MockLanguageServer.INSTANCE.setDefinition(locations); + public void testDefinitionManyLocation(MockLanguageServerFactory factory) throws Exception { + factory.withConfiguration((idx, server)-> { + final var locations = new ArrayList(); + locations.add(new Location("file://test0", new Range(new Position(0, 0), new Position(0, 10)))); + locations.add(new Location("file://test1", new Range(new Position(1, 0), new Position(1, 10)))); + locations.add(new Location("file://test2", new Range(new Position(2, 0), new Position(2, 10)))); + server.setDefinition(locations); + }); IFile file = TestUtils.createUniqueTestFile(project, "Example Text"); ITextViewer viewer = TestUtils.openTextViewer(file); @@ -113,8 +121,10 @@ public void testDefinitionManyLocation() throws Exception { } @Test - public void testDefinitionNoLocations() throws Exception { - MockLanguageServer.INSTANCE.setDefinition(null); + public void testDefinitionNoLocations(MockLanguageServerFactory factory) throws Exception { + factory.withConfiguration((idx, server)-> { + server.setDefinition(null); + }); IFile file = TestUtils.createUniqueTestFile(project, "Example Text"); ITextViewer viewer = TestUtils.openTextViewer(file); @@ -124,8 +134,10 @@ public void testDefinitionNoLocations() throws Exception { } @Test - public void testDefinitionEmptyLocations() throws Exception { - MockLanguageServer.INSTANCE.setDefinition(Collections.emptyList()); + public void testDefinitionEmptyLocations(MockLanguageServerFactory factory) throws Exception { + factory.withConfiguration((idx, server)-> { + server.setDefinition(Collections.emptyList()); + }); IFile file = TestUtils.createUniqueTestFile(project, "Example Text"); ITextViewer viewer = TestUtils.openTextViewer(file); @@ -135,9 +147,11 @@ public void testDefinitionEmptyLocations() throws Exception { } @Test - public void testReturnsPromptly() throws Exception { - final var location = new Location("file://test", new Range(new Position(0, 0), new Position(0, 10))); - MockLanguageServer.INSTANCE.setDefinition(List.of(location)); + public void testReturnsPromptly(MockLanguageServerFactory factory) throws Exception { + factory.withConfiguration((idx, server)-> { + final var location = new Location("file://test", new Range(new Position(0, 0), new Position(0, 10))); + server.setDefinition(List.of(location)); + }); IFile file = TestUtils.createUniqueTestFile(project, "Example Text"); ITextViewer viewer = TestUtils.openTextViewer(file); diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/definition/HyperlinkDetectorErrorHandlingTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/definition/HyperlinkDetectorErrorHandlingTest.java index 348ed934b..7b80ad358 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/definition/HyperlinkDetectorErrorHandlingTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/definition/HyperlinkDetectorErrorHandlingTest.java @@ -27,6 +27,7 @@ import org.eclipse.lsp4e.test.utils.AbstractTestWithProject; import org.eclipse.lsp4e.test.utils.TestUtils; import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4e.tests.mock.MockTextDocumentService; import org.eclipse.lsp4j.DeclarationParams; import org.eclipse.lsp4j.ImplementationParams; @@ -43,8 +44,7 @@ public class HyperlinkDetectorErrorHandlingTest extends AbstractTestWithProject private final OpenDeclarationHyperlinkDetector detector = new OpenDeclarationHyperlinkDetector(); - @Override - protected ServerCapabilities getServerCapabilities() { + protected ServerCapabilities capabilities() { // Ensure providers are enabled to exercise all branches var caps = MockLanguageServer.defaultServerCapabilities(); caps.setDefinitionProvider(true); @@ -55,48 +55,52 @@ protected ServerCapabilities getServerCapabilities() { } @Test - public void testDefinitionRemainsWhenTypeDefinitionErrors() throws Exception { - MockLanguageServer.INSTANCE.setTextDocumentService( - // Simulate server error for typeDefinition (mirrors issue - // https://github.com/eclipse-lsp4e/lsp4e/issues/1169) - new MockTextDocumentService(MockLanguageServer.INSTANCE::buildMaybeDelayedFuture) { - @Override - public CompletableFuture, List>> typeDefinition( - TypeDefinitionParams params) { - var f = new CompletableFuture, List>>(); - f.completeExceptionally( - new RuntimeException("unexpected error during typeDefinition retrieval")); - return f; - } - - @Override - public CompletableFuture, List>> implementation( - ImplementationParams params) { - throw new RuntimeException("unexpected error during implementation retrieval"); - } - - @Override - public CompletableFuture, List>> declaration( - DeclarationParams params) { - throw new RuntimeException("unexpected error during declaration retrieval"); - } - }); + public void testDefinitionRemainsWhenTypeDefinitionErrors(MockLanguageServerFactory factory) throws Exception { + factory.withCapabilities(this::capabilities); + factory.withConfiguration((idx, server)-> { + server.setTextDocumentService( + // Simulate server error for typeDefinition (mirrors issue + // https://github.com/eclipse-lsp4e/lsp4e/issues/1169) + new MockTextDocumentService(server::buildMaybeDelayedFuture) { + @Override + public CompletableFuture, List>> typeDefinition( + TypeDefinitionParams params) { + var f = new CompletableFuture, List>>(); + f.completeExceptionally( + new RuntimeException("unexpected error during typeDefinition retrieval")); + return f; + } + + @Override + public CompletableFuture, List>> implementation( + ImplementationParams params) { + throw new RuntimeException("unexpected error during implementation retrieval"); + } + + @Override + public CompletableFuture, List>> declaration( + DeclarationParams params) { + throw new RuntimeException("unexpected error during declaration retrieval"); + } + }); + }); + IFile file = TestUtils.createUniqueTestFile(project, "Example Text"); + ITextViewer viewer = TestUtils.openTextViewer(file); + // ensure TextDocumentService is faulty assertThrows(RuntimeException.class, - () -> MockLanguageServer.INSTANCE.getTextDocumentService().declaration(null)); + () -> factory.getServer().getTextDocumentService().declaration(null)); assertThrows(RuntimeException.class, - () -> MockLanguageServer.INSTANCE.getTextDocumentService().implementation(null)); + () -> factory.getServer().getTextDocumentService().implementation(null)); assertTrue( - MockLanguageServer.INSTANCE.getTextDocumentService().typeDefinition(null).isCompletedExceptionally()); + factory.getServer().getTextDocumentService().typeDefinition(null).isCompletedExceptionally()); // Configure 1 good definition result - MockLanguageServer.INSTANCE.setDefinition(List.of( // + factory.getServer().setDefinition(List.of( // new Location("file://def", new Range(new Position(0, 0), new Position(0, 10))), // new Location("file://def", new Range(new Position(1, 10), new Position(1, 20))))); - IFile file = TestUtils.createUniqueTestFile(project, "Example Text"); - ITextViewer viewer = TestUtils.openTextViewer(file); IHyperlink[] links = detector.detectHyperlinks(viewer, new Region(0, 0), true); diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/diagnostics/DiagnosticsTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/diagnostics/DiagnosticsTest.java index 04cf29368..016b1464a 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/diagnostics/DiagnosticsTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/diagnostics/DiagnosticsTest.java @@ -13,10 +13,12 @@ *******************************************************************************/ package org.eclipse.lsp4e.test.diagnostics; -import static org.eclipse.lsp4e.test.utils.TestUtils.*; -import static org.hamcrest.CoreMatchers.*; -import static org.hamcrest.MatcherAssert.*; -import static org.junit.jupiter.api.Assertions.*; +import static org.eclipse.lsp4e.test.utils.TestUtils.waitForAndAssertCondition; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.nio.file.Files; import java.nio.file.Path; @@ -46,7 +48,7 @@ import org.eclipse.lsp4e.test.utils.AbstractTestWithProject; import org.eclipse.lsp4e.test.utils.BlockingWorkspaceJob; import org.eclipse.lsp4e.test.utils.TestUtils; -import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4e.ui.UI; import org.eclipse.lsp4j.Diagnostic; import org.eclipse.lsp4j.DiagnosticSeverity; @@ -296,12 +298,14 @@ public void testDiagnosticsOnContainerResourceWithoutDocument() throws Exception } @Test - public void testDiagnosticsFromVariousLS() throws Exception { + public void testDiagnosticsFromVariousLS(MockLanguageServerFactory factory) throws Exception { final var content = "Diagnostic Other Text"; IFile file = TestUtils.createUniqueTestFileMultiLS(project, content); - final var range = new Range(new Position(1, 0), new Position(1, 0)); - MockLanguageServer.INSTANCE.setDiagnostics(List.of( - createDiagnostic("1", "message1", range, DiagnosticSeverity.Error, "source1"))); + factory.withConfiguration((idx, server)-> { + final var range = new Range(new Position(1, 0), new Position(1, 0)); + server.setDiagnostics(List.of( + createDiagnostic("1", "message1", range, DiagnosticSeverity.Error, "source1"))); + }); IMarker[] markers = file.findMarkers(LSPDiagnosticsToMarkers.LS_DIAGNOSTIC_MARKER_TYPE, true, IResource.DEPTH_ZERO); assertEquals(0, markers.length, "no marker should be shown at file initialization"); TestUtils.openEditor(file); @@ -335,8 +339,10 @@ public void testDiagnosticRedrawingCalls() throws CoreException { } @Test - public void testDiagnosticsOnExternalFile(@TempDir Path tempDir) throws Exception { - MockLanguageServer.INSTANCE.setDiagnostics(List.of(new Diagnostic(new Range(new Position(0, 0), new Position(0, 1)), "This is a warning", DiagnosticSeverity.Warning, null))); + public void testDiagnosticsOnExternalFile(@TempDir Path tempDir, MockLanguageServerFactory factory) throws Exception { + factory.withConfiguration((idx, server)-> { + server.setDiagnostics(List.of(new Diagnostic(new Range(new Position(0, 0), new Position(0, 1)), "This is a warning", DiagnosticSeverity.Warning, null))); + }); Path file = Files.writeString(tempDir.resolve("testDiagnosticsOnExternalFile.lspt"), "a"); Font font = null; try { diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/documentLink/DocumentLinkReconcilingTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/documentLink/DocumentLinkReconcilingTest.java index afbd0f257..b03ec3ae8 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/documentLink/DocumentLinkReconcilingTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/documentLink/DocumentLinkReconcilingTest.java @@ -30,7 +30,7 @@ import org.eclipse.jface.text.source.projection.ProjectionViewer; import org.eclipse.lsp4e.test.utils.AbstractTestWithProject; import org.eclipse.lsp4e.test.utils.TestUtils; -import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4j.DocumentLink; import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.Range; @@ -72,8 +72,10 @@ public class DocumentLinkReconcilingTest extends AbstractTestWithProject { private List textPresentations = new ArrayList<>(4); @Test - public void testFullDocumentLinkReconciling() throws Exception { - MockLanguageServer.INSTANCE.setDocumentLinks(CONTENT_LINKS); + public void testFullDocumentLinkReconciling(MockLanguageServerFactory factory) throws Exception { + factory.withConfiguration((idx, server)-> { + server.setDocumentLinks(CONTENT_LINKS); + }); TextViewer viewer = (TextViewer) TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project, CONTENT)); IDocument doc = viewer.getDocument(); @@ -137,8 +139,10 @@ public void testFullDocumentLinkReconciling() throws Exception { } @Test - public void testMidLineClippedDocumentLinkReconciling() throws Exception { - MockLanguageServer.INSTANCE.setDocumentLinks(CONTENT_LINKS); + public void testMidLineClippedDocumentLinkReconciling(MockLanguageServerFactory factory) throws Exception { + factory.withConfiguration((idx, server)-> { + server.setDocumentLinks(CONTENT_LINKS); + }); ProjectionViewer viewer = (ProjectionViewer) TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project, CONTENT)); IDocument doc = viewer.getDocument(); @@ -188,8 +192,10 @@ public void testMidLineClippedDocumentLinkReconciling() throws Exception { } @Test - public void testClippedDocumentLinkReconciling() throws Exception { - MockLanguageServer.INSTANCE.setDocumentLinks(CONTENT_LINKS); + public void testClippedDocumentLinkReconciling(MockLanguageServerFactory factory) throws Exception { + factory.withConfiguration((idx, server)-> { + server.setDocumentLinks(CONTENT_LINKS); + }); ProjectionViewer viewer = (ProjectionViewer) TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project, CONTENT)); IDocument doc = viewer.getDocument(); @@ -239,8 +245,10 @@ public void testClippedDocumentLinkReconciling() throws Exception { } @Test - public void testDocumentWithFoldingLinkReconciling() throws Exception { - MockLanguageServer.INSTANCE.setDocumentLinks(CONTENT_LINKS); + public void testDocumentWithFoldingLinkReconciling(MockLanguageServerFactory factory) throws Exception { + factory.withConfiguration((idx, server)-> { + server.setDocumentLinks(CONTENT_LINKS); + }); ProjectionViewer viewer = (ProjectionViewer) TestUtils.openTextViewer(TestUtils.createUniqueTestFile(project, CONTENT)); IDocument doc = viewer.getDocument(); diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/documentLink/DocumentLinkTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/documentLink/DocumentLinkTest.java index 6d3f698b9..211b0c222 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/documentLink/DocumentLinkTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/documentLink/DocumentLinkTest.java @@ -27,7 +27,7 @@ import org.eclipse.lsp4e.operations.documentLink.DocumentLinkDetector; import org.eclipse.lsp4e.test.utils.AbstractTestWithProject; import org.eclipse.lsp4e.test.utils.TestUtils; -import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4e.ui.UI; import org.eclipse.lsp4j.DocumentLink; import org.eclipse.lsp4j.Position; @@ -51,10 +51,12 @@ public void testDocumentLinkNoResults() throws Exception { } @Test - public void testDocumentLink() throws Exception { + public void testDocumentLink(MockLanguageServerFactory factory) throws Exception { final var links = new ArrayList(); links.add(new DocumentLink(new Range(new Position(0, 9), new Position(0, 15)), "file://test0")); - MockLanguageServer.INSTANCE.setDocumentLinks(links); + factory.withConfiguration((idx, server)-> { + server.setDocumentLinks(links); + }); IFile file = TestUtils.createUniqueTestFile(project, "not_link "); ITextViewer viewer = TestUtils.openTextViewer(file); @@ -65,10 +67,12 @@ public void testDocumentLink() throws Exception { } @Test - public void testDocumentLinkExternalFile(@TempDir Path tempDir) throws Exception { + public void testDocumentLinkExternalFile(@TempDir Path tempDir, MockLanguageServerFactory factory) throws Exception { final var links = new ArrayList(); links.add(new DocumentLink(new Range(new Position(0, 9), new Position(0, 15)), "file://test0")); - MockLanguageServer.INSTANCE.setDocumentLinks(links); + factory.withConfiguration((idx, server)-> { + server.setDocumentLinks(links); + }); Path file = Files.createFile(tempDir.resolve("testDocumentLinkExternalFile.lspt")); final var editor = (ITextEditor) IDE.openInternalEditorOnFileStore(UI.getActivePage(), EFS.getStore(file.toUri())); @@ -81,10 +85,12 @@ public void testDocumentLinkExternalFile(@TempDir Path tempDir) throws Exception } @Test - public void testDocumentLinkWithEncodedUri() throws Exception { + public void testDocumentLinkWithEncodedUri(MockLanguageServerFactory factory) throws Exception { final var links = new ArrayList(); links.add(new DocumentLink(new Range(new Position(0, 9), new Position(0, 15)), "file:///tmp/fi%C3%A9le.ts")); - MockLanguageServer.INSTANCE.setDocumentLinks(links); + factory.withConfiguration((idx, server)-> { + server.setDocumentLinks(links); + }); IFile file = TestUtils.createUniqueTestFile(project, "not_link "); ITextViewer viewer = TestUtils.openTextViewer(file); @@ -95,10 +101,12 @@ public void testDocumentLinkWithEncodedUri() throws Exception { } @Test - public void testDocumentLinkWrongRegion() throws Exception { + public void testDocumentLinkWrongRegion(MockLanguageServerFactory factory) throws Exception { final var links = new ArrayList(); links.add(new DocumentLink(new Range(new Position(0, 9), new Position(0, 15)), "file://test0")); - MockLanguageServer.INSTANCE.setDocumentLinks(links); + factory.withConfiguration((idx, server)-> { + server.setDocumentLinks(links); + }); IFile file = TestUtils.createUniqueTestFile(project, "not_link "); ITextViewer viewer = TestUtils.openTextViewer(file); diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/edit/DocumentDidChangeTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/edit/DocumentDidChangeTest.java index 87d859d91..e9d73480d 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/edit/DocumentDidChangeTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/edit/DocumentDidChangeTest.java @@ -30,6 +30,7 @@ import org.eclipse.lsp4e.test.utils.AbstractTestWithProject; import org.eclipse.lsp4e.test.utils.TestUtils; import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4e.ui.UI; import org.eclipse.lsp4j.DidChangeTextDocumentParams; import org.eclipse.lsp4j.Range; @@ -45,9 +46,12 @@ public class DocumentDidChangeTest extends AbstractTestWithProject { @Test - public void testIncrementalSync() throws Exception { - MockLanguageServer.INSTANCE.getInitializeResult().getCapabilities() - .setTextDocumentSync(TextDocumentSyncKind.Incremental); + public void testIncrementalSync(MockLanguageServerFactory factory) throws Exception { + factory.withCapabilities(() -> { + var caps = MockLanguageServer.defaultServerCapabilities(); + caps.setTextDocumentSync(TextDocumentSyncKind.Incremental); + return caps; + }); IFile testFile = TestUtils.createUniqueTestFile(project, ""); ITextViewer viewer = TestUtils.openTextViewer(testFile); @@ -62,8 +66,8 @@ public boolean test(ServerCapabilities t) { // Test initial insert viewer.getDocument().replace(0, 0, "Hello"); - waitForAndAssertCondition(1_000, numberOfChangesIs(1)); - DidChangeTextDocumentParams lastChange = MockLanguageServer.INSTANCE.getDidChangeEvents().get(0); + waitForAndAssertCondition(1_000, numberOfChangesIs(1, factory.getServer())); + DidChangeTextDocumentParams lastChange = factory.getServer().getDidChangeEvents().get(0); assertNotNull(lastChange.getContentChanges()); assertEquals(1, lastChange.getContentChanges().size()); TextDocumentContentChangeEvent change0 = lastChange.getContentChanges().get(0); @@ -78,8 +82,8 @@ public boolean test(ServerCapabilities t) { // Test additional insert viewer.getDocument().replace(5, 0, " "); - waitForAndAssertCondition(1_000, numberOfChangesIs(2)); - lastChange = MockLanguageServer.INSTANCE.getDidChangeEvents().get(1); + waitForAndAssertCondition(1_000, numberOfChangesIs(2, factory.getServer())); + lastChange = factory.getServer().getDidChangeEvents().get(1); assertNotNull(lastChange.getContentChanges()); assertEquals(1, lastChange.getContentChanges().size()); change0 = lastChange.getContentChanges().get(0); @@ -94,8 +98,8 @@ public boolean test(ServerCapabilities t) { // test replace viewer.getDocument().replace(0, 5, "Hallo"); - waitForAndAssertCondition(1_000, numberOfChangesIs(3)); - lastChange = MockLanguageServer.INSTANCE.getDidChangeEvents().get(2); + waitForAndAssertCondition(1_000, numberOfChangesIs(3, factory.getServer())); + lastChange = factory.getServer().getDidChangeEvents().get(2); assertNotNull(lastChange.getContentChanges()); assertEquals(1, lastChange.getContentChanges().size()); change0 = lastChange.getContentChanges().get(0); @@ -110,9 +114,12 @@ public boolean test(ServerCapabilities t) { } @Test - public void testIncrementalSync_deleteLastLine() throws Exception { - MockLanguageServer.INSTANCE.getInitializeResult().getCapabilities() - .setTextDocumentSync(TextDocumentSyncKind.Incremental); + public void testIncrementalSync_deleteLastLine(MockLanguageServerFactory factory) throws Exception { + factory.withCapabilities(() -> { + var caps = MockLanguageServer.defaultServerCapabilities(); + caps.setTextDocumentSync(TextDocumentSyncKind.Incremental); + return caps; + }); final var multiLineText = "line1\nline2\nline3\n"; IFile testFile = TestUtils.createUniqueTestFile(project, multiLineText); @@ -127,8 +134,8 @@ public boolean test(ServerCapabilities t) { // Test initial insert viewer.getDocument().replace("line1\nline2\n".length(), "line3\n".length(), ""); - waitForAndAssertCondition(1_000, numberOfChangesIs(1)); - DidChangeTextDocumentParams lastChange = MockLanguageServer.INSTANCE.getDidChangeEvents().get(0); + waitForAndAssertCondition(1_000, numberOfChangesIs(1, factory.getServer())); + DidChangeTextDocumentParams lastChange = factory.getServer().getDidChangeEvents().get(0); assertNotNull(lastChange.getContentChanges()); assertEquals(1, lastChange.getContentChanges().size()); TextDocumentContentChangeEvent change0 = lastChange.getContentChanges().get(0); @@ -143,16 +150,20 @@ public boolean test(ServerCapabilities t) { } @Test - public void testIncrementalEditOrdering() throws Exception { - MockLanguageServer.INSTANCE.getInitializeResult().getCapabilities().setTextDocumentSync(TextDocumentSyncKind.Incremental); + public void testIncrementalEditOrdering(MockLanguageServerFactory factory) throws Exception { + factory.withCapabilities(() -> { + var caps = MockLanguageServer.defaultServerCapabilities(); + caps.setTextDocumentSync(TextDocumentSyncKind.Incremental); + return caps; + }); IFile testFile = TestUtils.createUniqueTestFile(project, ""); ITextViewer viewer = TestUtils.openTextViewer(testFile); StyledText text = viewer.getTextWidget(); for (int i = 0; i < 500; i++) { text.append(i + "\n"); } - waitForAndAssertCondition(10_000, numberOfChangesIs(500)); - List changes = MockLanguageServer.INSTANCE.getDidChangeEvents(); + waitForAndAssertCondition(10_000, numberOfChangesIs(500, factory.getServer())); + List changes = factory.getServer().getDidChangeEvents(); for (int i = 0; i < 500; i++) { String delta = changes.get(i).getContentChanges().get(0).getText(); assertEquals(i + "\n", delta); @@ -160,9 +171,12 @@ public void testIncrementalEditOrdering() throws Exception { } @Test - public void testFullSync() throws Exception { - MockLanguageServer.INSTANCE.getInitializeResult().getCapabilities() - .setTextDocumentSync(TextDocumentSyncKind.Full); + public void testFullSync(MockLanguageServerFactory factory) throws Exception { + factory.withCapabilities(() -> { + var caps = MockLanguageServer.defaultServerCapabilities(); + caps.setTextDocumentSync(TextDocumentSyncKind.Full); + return caps; + }); IFile testFile = TestUtils.createUniqueTestFile(project, ""); ITextViewer viewer = TestUtils.openTextViewer(testFile); @@ -176,8 +190,8 @@ public boolean test(ServerCapabilities t) { // Test initial insert final var text = "Hello"; viewer.getDocument().replace(0, 0, text); - waitForAndAssertCondition(1_000, numberOfChangesIs(1)); - DidChangeTextDocumentParams lastChange = MockLanguageServer.INSTANCE.getDidChangeEvents().get(0); + waitForAndAssertCondition(1_000, numberOfChangesIs(1, factory.getServer())); + DidChangeTextDocumentParams lastChange = factory.getServer().getDidChangeEvents().get(0); assertNotNull(lastChange.getContentChanges()); assertEquals(1, lastChange.getContentChanges().size()); TextDocumentContentChangeEvent change0 = lastChange.getContentChanges().get(0); @@ -186,8 +200,8 @@ public boolean test(ServerCapabilities t) { // Test additional insert viewer.getDocument().replace(5, 0, " World"); - waitForAndAssertCondition(1_000, numberOfChangesIs(2)); - lastChange = MockLanguageServer.INSTANCE.getDidChangeEvents().get(1); + waitForAndAssertCondition(1_000, numberOfChangesIs(2, factory.getServer())); + lastChange = factory.getServer().getDidChangeEvents().get(1); assertNotNull(lastChange.getContentChanges()); assertEquals(1, lastChange.getContentChanges().size()); change0 = lastChange.getContentChanges().get(0); @@ -195,9 +209,12 @@ public boolean test(ServerCapabilities t) { } @Test - public void testFullSyncExternalFile(@TempDir Path tempDir) throws Exception { - MockLanguageServer.INSTANCE.getInitializeResult().getCapabilities() - .setTextDocumentSync(TextDocumentSyncKind.Full); + public void testFullSyncExternalFile(@TempDir Path tempDir, MockLanguageServerFactory factory) throws Exception { + factory.withCapabilities(() -> { + var caps = MockLanguageServer.defaultServerCapabilities(); + caps.setTextDocumentSync(TextDocumentSyncKind.Full); + return caps; + }); Path file = Files.createFile(tempDir.resolve("testFullSyncExternalFile.lspt")); IEditorPart editor = IDE.openEditorOnFileStore(UI.getActivePage(), EFS.getStore(file.toUri())); @@ -212,8 +229,8 @@ public boolean test(ServerCapabilities t) { // Test initial insert final var text = "Hello"; viewer.getDocument().replace(0, 0, text); - waitForAndAssertCondition(1_000, numberOfChangesIs(1)); - DidChangeTextDocumentParams lastChange = MockLanguageServer.INSTANCE.getDidChangeEvents().get(0); + waitForAndAssertCondition(1_000, numberOfChangesIs(1, factory.getServer())); + DidChangeTextDocumentParams lastChange = factory.getServer().getDidChangeEvents().get(0); assertNotNull(lastChange.getContentChanges()); assertEquals(1, lastChange.getContentChanges().size()); TextDocumentContentChangeEvent change0 = lastChange.getContentChanges().get(0); @@ -221,8 +238,8 @@ public boolean test(ServerCapabilities t) { // Test additional insert viewer.getDocument().replace(5, 0, " World"); - waitForAndAssertCondition(1_000, numberOfChangesIs(2)); - lastChange = MockLanguageServer.INSTANCE.getDidChangeEvents().get(1); + waitForAndAssertCondition(1_000, numberOfChangesIs(2, factory.getServer())); + lastChange = factory.getServer().getDidChangeEvents().get(1); assertNotNull(lastChange.getContentChanges()); assertEquals(1, lastChange.getContentChanges().size()); change0 = lastChange.getContentChanges().get(0); diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/edit/DocumentDidCloseTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/edit/DocumentDidCloseTest.java index c19818103..36f0bc51e 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/edit/DocumentDidCloseTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/edit/DocumentDidCloseTest.java @@ -26,7 +26,7 @@ import org.eclipse.lsp4e.LanguageServers; import org.eclipse.lsp4e.test.utils.AbstractTestWithProject; import org.eclipse.lsp4e.test.utils.TestUtils; -import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4e.ui.UI; import org.eclipse.lsp4j.DidCloseTextDocumentParams; import org.eclipse.ui.IEditorPart; @@ -37,7 +37,7 @@ public class DocumentDidCloseTest extends AbstractTestWithProject { @Test - public void testClose() throws Exception { + public void testClose(MockLanguageServerFactory factory) throws Exception { IFile testFile = TestUtils.createUniqueTestFile(project, ""); IEditorPart editor = TestUtils.openEditor(testFile); @@ -47,7 +47,7 @@ public void testClose() throws Exception { LanguageServers.forDocument(document).anyMatching(); final var didCloseExpectation = new CompletableFuture(); - MockLanguageServer.INSTANCE.setDidCloseCallback(didCloseExpectation); + factory.getServer().setDidCloseCallback(didCloseExpectation); TestUtils.closeEditor(editor, false); DidCloseTextDocumentParams lastChange = didCloseExpectation.get(1000, TimeUnit.MILLISECONDS); @@ -56,7 +56,7 @@ public void testClose() throws Exception { } @Test - public void testCloseExternalFile(@TempDir Path tempDir) throws Exception { + public void testCloseExternalFile(@TempDir Path tempDir, MockLanguageServerFactory factory) throws Exception { Path testFile = Files.createFile(tempDir.resolve("testCloseExternalFile.lspt")); IEditorPart editor = IDE.openEditorOnFileStore(UI.getActivePage(), EFS.getStore(testFile.toUri())); @@ -64,7 +64,7 @@ public void testCloseExternalFile(@TempDir Path tempDir) throws Exception { LanguageServers.forDocument(LSPEclipseUtils.getDocument(editor.getEditorInput())).anyMatching(); final var didCloseExpectation = new CompletableFuture(); - MockLanguageServer.INSTANCE.setDidCloseCallback(didCloseExpectation); + factory.getServer().setDidCloseCallback(didCloseExpectation); TestUtils.closeEditor(editor, false); diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/edit/DocumentDidOpenTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/edit/DocumentDidOpenTest.java index 86b7e4e78..810c258b3 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/edit/DocumentDidOpenTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/edit/DocumentDidOpenTest.java @@ -26,7 +26,7 @@ import org.eclipse.lsp4e.LanguageServers; import org.eclipse.lsp4e.test.utils.AbstractTestWithProject; import org.eclipse.lsp4e.test.utils.TestUtils; -import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4e.ui.UI; import org.eclipse.lsp4j.DidOpenTextDocumentParams; import org.eclipse.ui.IEditorPart; @@ -38,11 +38,14 @@ public class DocumentDidOpenTest extends AbstractTestWithProject { @Test - public void testOpen() throws Exception { + public void testOpen(MockLanguageServerFactory factory) throws Exception { + final var didOpenExpectation = new CompletableFuture(); + factory.withConfiguration((idx, server)-> { + server.setDidOpenCallback(didOpenExpectation); + }); + IFile testFile = TestUtils.createUniqueTestFile(project, ""); - final var didOpenExpectation = new CompletableFuture(); - MockLanguageServer.INSTANCE.setDidOpenCallback(didOpenExpectation); TestUtils.openEditor(testFile); @@ -57,10 +60,12 @@ public void testOpen() throws Exception { } @Test - public void testOpenExternalFile(@TempDir Path tempDir) throws Exception { + public void testOpenExternalFile(@TempDir Path tempDir, MockLanguageServerFactory factory) throws Exception { Path file = Files.createFile(tempDir.resolve("testOpenExternalFile.lspt")); final var didOpenExpectation = new CompletableFuture(); - MockLanguageServer.INSTANCE.setDidOpenCallback(didOpenExpectation); + factory.withConfiguration((idx, server)-> { + server.setDidOpenCallback(didOpenExpectation); + }); IEditorPart editor = IDE.openEditorOnFileStore(UI.getActivePage(), EFS.getStore(file.toUri())); // Force LS to initialize and open file LanguageServers.forDocument(LSPEclipseUtils.getDocument(editor.getEditorInput())).anyMatching(); @@ -71,11 +76,13 @@ public void testOpenExternalFile(@TempDir Path tempDir) throws Exception { } @Test - public void testOpenWithSpecificLanguageId() throws Exception { + public void testOpenWithSpecificLanguageId(MockLanguageServerFactory factory) throws Exception { IFile testFile = TestUtils.createUniqueTestFile(project, "lspt-different", ""); final var didOpenExpectation = new CompletableFuture(); - MockLanguageServer.INSTANCE.setDidOpenCallback(didOpenExpectation); + factory.withConfiguration((idx, server)-> { + server.setDidOpenCallback(didOpenExpectation); + }); IEditorPart editor = TestUtils.openEditor(testFile); diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/edit/DocumentDidSaveTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/edit/DocumentDidSaveTest.java index eaabb9ad2..74da0e698 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/edit/DocumentDidSaveTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/edit/DocumentDidSaveTest.java @@ -30,7 +30,7 @@ import org.eclipse.lsp4e.LanguageServers; import org.eclipse.lsp4e.test.utils.AbstractTestWithProject; import org.eclipse.lsp4e.test.utils.TestUtils; -import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4e.ui.UI; import org.eclipse.lsp4j.DidSaveTextDocumentParams; import org.eclipse.ui.IEditorPart; @@ -41,7 +41,7 @@ public class DocumentDidSaveTest extends AbstractTestWithProject { @Test - public void testSave() throws Exception { + public void testSave(MockLanguageServerFactory factory) throws Exception { IFile testFile = TestUtils.createUniqueTestFile(project, ""); IEditorPart editor = TestUtils.openEditor(testFile); ITextViewer viewer = LSPEclipseUtils.getTextViewer(editor); @@ -54,7 +54,7 @@ public void testSave() throws Exception { assertNotNull(document); LanguageServers.forDocument(document).anyMatching(); final var didSaveExpectation = new CompletableFuture(); - MockLanguageServer.INSTANCE.setDidSaveCallback(didSaveExpectation); + factory.getServer().setDidSaveCallback(didSaveExpectation); // simulate change in file viewer.getDocument().replace(0, 0, "Hello"); @@ -69,7 +69,7 @@ public void testSave() throws Exception { } @Test - public void testSaveExternalFile(@TempDir Path tempDir) throws Exception { + public void testSaveExternalFile(@TempDir Path tempDir, MockLanguageServerFactory factory) throws Exception { Path file = Files.createFile(tempDir.resolve("testSaveExternalFile.lspt")); IEditorPart editor = IDE.openEditorOnFileStore(UI.getActivePage(), EFS.getStore(file.toUri())); ITextViewer viewer = LSPEclipseUtils.getTextViewer(editor); @@ -80,7 +80,7 @@ public void testSaveExternalFile(@TempDir Path tempDir) throws Exception { // Force LS to initialize and open file LanguageServers.forDocument(LSPEclipseUtils.getDocument(editor.getEditorInput())).anyMatching(); final var didSaveExpectation = new CompletableFuture(); - MockLanguageServer.INSTANCE.setDidSaveCallback(didSaveExpectation); + factory.getServer().setDidSaveCallback(didSaveExpectation); // simulate change in file viewer.getDocument().replace(0, 0, "Hello"); diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/edit/DocumentEditAndUndoTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/edit/DocumentEditAndUndoTest.java index ad5e5ac72..a2c60013d 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/edit/DocumentEditAndUndoTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/edit/DocumentEditAndUndoTest.java @@ -26,7 +26,7 @@ import org.eclipse.lsp4e.LanguageServers; import org.eclipse.lsp4e.test.utils.AbstractTestWithProject; import org.eclipse.lsp4e.test.utils.TestUtils; -import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4j.LinkedEditingRanges; import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.Range; @@ -42,11 +42,14 @@ public class DocumentEditAndUndoTest extends AbstractTestWithProject { @Test - public void testDocumentEditAndUndo() throws Exception { - MockLanguageServer.INSTANCE.setLinkedEditingRanges(new LinkedEditingRanges(List.of( // - new Range(new Position(0, 1), new Position(0, 2)), // - new Range(new Position(0, 5), new Position(0, 6))), - "[:A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02ff\\u0370-\\u037d\\u037f-\\u1fff\\u200c\\u200d\\u2070-\\u218f\\u2c00-\\u2fef\\u3001-\\udfff\\uf900-\\ufdcf\\ufdf0-\\ufffd\\u10000-\\uEFFFF][:A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02ff\\u0370-\\u037d\\u037f-\\u1fff\\u200c\\u200d\\u2070-\\u218f\\u2c00-\\u2fef\\u3001-\\udfff\\uf900-\\ufdcf\\ufdf0-\\ufffd\\u10000-\\uEFFFF\\-\\.0-9\\u00b7\\u0300-\\u036f\\u203f-\\u2040]*")); + public void testDocumentEditAndUndo(MockLanguageServerFactory factory) throws Exception { + factory.withConfiguration((idx, server)-> { + server.setLinkedEditingRanges(new LinkedEditingRanges(List.of( // + new Range(new Position(0, 1), new Position(0, 2)), // + new Range(new Position(0, 5), new Position(0, 6))), + "[:A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02ff\\u0370-\\u037d\\u037f-\\u1fff\\u200c\\u200d\\u2070-\\u218f\\u2c00-\\u2fef\\u3001-\\udfff\\uf900-\\ufdcf\\ufdf0-\\ufffd\\u10000-\\uEFFFF][:A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02ff\\u0370-\\u037d\\u037f-\\u1fff\\u200c\\u200d\\u2070-\\u218f\\u2c00-\\u2fef\\u3001-\\udfff\\uf900-\\ufdcf\\ufdf0-\\ufffd\\u10000-\\uEFFFF\\-\\.0-9\\u00b7\\u0300-\\u036f\\u203f-\\u2040]*")); + }); + final var initialContent = ""; IFile testFile = TestUtils.createUniqueTestFile(project, initialContent); diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/edit/DocumentRevertAndCloseTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/edit/DocumentRevertAndCloseTest.java index a12ed1261..c60550f40 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/edit/DocumentRevertAndCloseTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/edit/DocumentRevertAndCloseTest.java @@ -21,7 +21,8 @@ import org.eclipse.lsp4e.LanguageServers; import org.eclipse.lsp4e.test.utils.AbstractTestWithProject; import org.eclipse.lsp4e.test.utils.TestUtils; -import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; +import org.eclipse.lsp4e.tests.mock.MockServerState; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.texteditor.AbstractTextEditor; import org.junit.jupiter.api.Test; @@ -29,7 +30,7 @@ public class DocumentRevertAndCloseTest extends AbstractTestWithProject { @Test - public void testShutdownLsp() throws Exception { + public void testShutdownLsp(MockLanguageServerFactory factory) throws Exception { IFile testFile = TestUtils.createUniqueTestFile(project, "Hello!"); IEditorPart editor = TestUtils.openEditor(testFile); ITextViewer viewer = LSPEclipseUtils.getTextViewer(editor); @@ -46,6 +47,6 @@ public void testShutdownLsp() throws Exception { ((AbstractTextEditor)editor).doRevertToSaved(); ((AbstractTextEditor)editor).getSite().getPage().closeEditor(editor, false); - waitForAndAssertCondition(3_000, () -> !MockLanguageServer.INSTANCE.isRunning()); + waitForAndAssertCondition(3_000, () -> factory.getServer().getState() != MockServerState.RUNNING); } } diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/edit/DocumentWillSaveWaitUntilTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/edit/DocumentWillSaveWaitUntilTest.java index 2bfdedb0f..3501ae04b 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/edit/DocumentWillSaveWaitUntilTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/edit/DocumentWillSaveWaitUntilTest.java @@ -25,7 +25,7 @@ import org.eclipse.lsp4e.LanguageServers; import org.eclipse.lsp4e.test.utils.AbstractTestWithProject; import org.eclipse.lsp4e.test.utils.TestUtils; -import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.Range; import org.eclipse.lsp4j.TextEdit; @@ -42,11 +42,13 @@ private List createSingleTextEditAtFileStart(String newText) { } @Test - public void testSave() throws Exception { + public void testSave(MockLanguageServerFactory factory) throws Exception { final var oldText = "Hello"; final var newText = "hello"; - MockLanguageServer.INSTANCE.setWillSaveWaitUntil(createSingleTextEditAtFileStart(newText)); + factory.withConfiguration((idx, server)-> { + server.setWillSaveWaitUntil(createSingleTextEditAtFileStart(newText)); + }); IFile testFile = TestUtils.createUniqueTestFile(project, ""); IEditorPart editor = TestUtils.openEditor(testFile); diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/folding/FoldingCommandsTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/folding/FoldingCommandsTest.java index b95f78f03..a3e363df4 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/folding/FoldingCommandsTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/folding/FoldingCommandsTest.java @@ -24,9 +24,8 @@ import org.eclipse.jface.text.source.projection.ProjectionViewer; import org.eclipse.lsp4e.LSPEclipseUtils; import org.eclipse.lsp4e.LanguageServerPlugin; -import org.eclipse.lsp4e.test.utils.AbstractTest; import org.eclipse.lsp4e.test.utils.TestUtils; -import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4e.ui.FoldingPreferencePage; import org.eclipse.lsp4j.FoldingRange; import org.eclipse.lsp4j.FoldingRangeKind; @@ -34,7 +33,7 @@ import org.eclipse.ui.handlers.IHandlerService; import org.junit.jupiter.api.Test; -public class FoldingCommandsTest extends AbstractTest { +public class FoldingCommandsTest { private static final int MAX_WAIT_MS = 5_000; @@ -52,16 +51,18 @@ public class FoldingCommandsTest extends AbstractTest { """; @Test - public void foldAndUnfoldAllCommands() throws Exception { + public void foldAndUnfoldAllCommands(MockLanguageServerFactory factory) throws Exception { // Ensure no auto-folding interferes with the command behavior configureAutoFolding(false); - // Provide folding ranges from the Mock LS: license header and imports - final var foldingRangeLicense = new FoldingRange(0, 2); - foldingRangeLicense.setKind(FoldingRangeKind.Comment); - final var foldingRangeImport = new FoldingRange(3, 5); - foldingRangeImport.setKind(FoldingRangeKind.Imports); - MockLanguageServer.INSTANCE.setFoldingRanges(List.of(foldingRangeLicense, foldingRangeImport)); + factory.withConfiguration((idx, server)-> { + // Provide folding ranges from the Mock LS: license header and imports + final var foldingRangeLicense = new FoldingRange(0, 2); + foldingRangeLicense.setKind(FoldingRangeKind.Comment); + final var foldingRangeImport = new FoldingRange(3, 5); + foldingRangeImport.setKind(FoldingRangeKind.Imports); + server.setFoldingRanges(List.of(foldingRangeLicense, foldingRangeImport)); + }); // Open editor and wait until folding annotations are present final var editor = TestUtils.openEditor(TestUtils.createUniqueTestFile(null, CONTENT)); diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/folding/FoldingTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/folding/FoldingTest.java index 154f88918..5b3592541 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/folding/FoldingTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/folding/FoldingTest.java @@ -15,9 +15,8 @@ import org.eclipse.core.runtime.CoreException; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.lsp4e.LanguageServerPlugin; -import org.eclipse.lsp4e.test.utils.AbstractTest; import org.eclipse.lsp4e.test.utils.TestUtils; -import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4e.ui.FoldingPreferencePage; import org.eclipse.lsp4j.FoldingRange; import org.eclipse.lsp4j.FoldingRangeKind; @@ -27,7 +26,7 @@ import org.eclipse.ui.tests.harness.util.DisplayHelper; import org.junit.jupiter.api.Test; -public class FoldingTest extends AbstractTest { +public class FoldingTest { private static final int MAX_WAIT_FOR_FOLDING = 3_000; @@ -45,10 +44,10 @@ public class FoldingTest extends AbstractTest { """; @Test - public void testLicenseHeaderAutoFolding() throws CoreException { + public void testLicenseHeaderAutoFolding(MockLanguageServerFactory factory) throws CoreException { configureCollapse(FoldingPreferencePage.PREF_AUTOFOLD_LICENSE_HEADERS_COMMENTS, true); configureCollapse(FoldingPreferencePage.PREF_AUTOFOLD_IMPORT_STATEMENTS, false); - IEditorPart editor = createEditor(); + IEditorPart editor = createEditor(factory); // wait for folding to happen TestUtils.waitForAndAssertCondition(MAX_WAIT_FOR_FOLDING, () -> assertEquals(""" @@ -63,11 +62,11 @@ public void testLicenseHeaderAutoFolding() throws CoreException { } @Test - public void testImportsAutoFolding() throws CoreException { + public void testImportsAutoFolding(MockLanguageServerFactory factory) throws CoreException { configureCollapse(FoldingPreferencePage.PREF_AUTOFOLD_LICENSE_HEADERS_COMMENTS, false); configureCollapse(FoldingPreferencePage.PREF_AUTOFOLD_IMPORT_STATEMENTS, true); - IEditorPart editor = createEditor(); + IEditorPart editor = createEditor(factory); // wait for folding to happen TestUtils.waitForAndAssertCondition(MAX_WAIT_FOR_FOLDING, () -> assertEquals(""" @@ -82,22 +81,24 @@ public void testImportsAutoFolding() throws CoreException { } @Test - public void testAutoFoldingDisabled() throws CoreException { + public void testAutoFoldingDisabled(MockLanguageServerFactory factory) throws CoreException { configureCollapse(FoldingPreferencePage.PREF_AUTOFOLD_LICENSE_HEADERS_COMMENTS, false); configureCollapse(FoldingPreferencePage.PREF_AUTOFOLD_IMPORT_STATEMENTS, false); - IEditorPart editor = createEditor(); + IEditorPart editor = createEditor(factory); // wait a few seconds before testing to ensure no folding happened DisplayHelper.sleep(MAX_WAIT_FOR_FOLDING); assertEquals(CONTENT, ((StyledText) editor.getAdapter(Control.class)).getText()); } - private IEditorPart createEditor() throws CoreException { - final var foldingRangeLicense = new FoldingRange(0, 2); - foldingRangeLicense.setKind(FoldingRangeKind.Comment); - final var foldingRangeImport = new FoldingRange(3, 5); - foldingRangeImport.setKind(FoldingRangeKind.Imports); - MockLanguageServer.INSTANCE.setFoldingRanges(List.of(foldingRangeLicense, foldingRangeImport)); + private IEditorPart createEditor(MockLanguageServerFactory factory) throws CoreException { + factory.withConfiguration((idx, server)-> { + final var foldingRangeLicense = new FoldingRange(0, 2); + foldingRangeLicense.setKind(FoldingRangeKind.Comment); + final var foldingRangeImport = new FoldingRange(3, 5); + foldingRangeImport.setKind(FoldingRangeKind.Imports); + server.setFoldingRanges(List.of(foldingRangeLicense, foldingRangeImport)); + }); return TestUtils.openEditor(TestUtils.createUniqueTestFile(null, CONTENT)); } diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/format/FormatHandlerReadOnlyTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/format/FormatHandlerReadOnlyTest.java index fe0fc3e60..8403314ed 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/format/FormatHandlerReadOnlyTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/format/FormatHandlerReadOnlyTest.java @@ -24,7 +24,7 @@ import org.eclipse.jface.text.TextSelection; import org.eclipse.lsp4e.test.utils.AbstractTestWithProject; import org.eclipse.lsp4e.test.utils.TestUtils; -import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4e.ui.Messages; import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.Range; @@ -44,12 +44,14 @@ public class FormatHandlerReadOnlyTest extends AbstractTestWithProject { @Test - public void testFormatOnReadOnlyFileAndMakeWritable() throws Exception { - // Mock formatting to prepend "//" at the start of each line - var edits = List.of( // - new TextEdit(new Range(new Position(0, 0), new Position(0, 0)), "//"), - new TextEdit(new Range(new Position(1, 0), new Position(1, 0)), "//")); - MockLanguageServer.INSTANCE.setFormattingTextEdits(edits); + public void testFormatOnReadOnlyFileAndMakeWritable(MockLanguageServerFactory factory) throws Exception { + factory.withConfiguration((idx, server)-> { + // Mock formatting to prepend "//" at the start of each line + var edits = List.of( // + new TextEdit(new Range(new Position(0, 0), new Position(0, 0)), "//"), + new TextEdit(new Range(new Position(1, 0), new Position(1, 0)), "//")); + server.setFormattingTextEdits(edits); + }); String content = "line1\nline2\n"; IFile file = TestUtils.createUniqueTestFile(project, content); diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/format/FormatTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/format/FormatTest.java index 464d94529..c8a125518 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/format/FormatTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/format/FormatTest.java @@ -39,6 +39,7 @@ import org.eclipse.lsp4e.test.utils.AbstractTestWithProject; import org.eclipse.lsp4e.test.utils.TestUtils; import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.Range; import org.eclipse.lsp4j.ServerCapabilities; @@ -64,8 +65,10 @@ public void testFormattingInvalidDocument() throws Exception { * and leaves the document content unchanged. */ @Test - public void testFormattingEmptyEditsYieldEmptyOptional() throws Exception { - MockLanguageServer.INSTANCE.setFormattingTextEdits(Collections.emptyList()); + public void testFormattingEmptyEditsYieldEmptyOptional(MockLanguageServerFactory factory) throws Exception { + factory.withConfiguration((idx, server)-> { + server.setFormattingTextEdits(Collections.emptyList()); + }); IFile file = TestUtils.createUniqueTestFile(project, "Formatting Other Text"); IEditorPart editor = TestUtils.openEditor(file); @@ -82,8 +85,10 @@ public void testFormattingEmptyEditsYieldEmptyOptional() throws Exception { } @Test - public void testFormattingNoChanges() throws Exception { - MockLanguageServer.INSTANCE.setFormattingTextEdits(Collections.emptyList()); + public void testFormattingNoChanges(MockLanguageServerFactory factory) throws Exception { + factory.withConfiguration((idx, server)-> { + server.setFormattingTextEdits(Collections.emptyList()); + }); IFile file = TestUtils.createUniqueTestFile(project, "Formatting Other Text"); IEditorPart editor = TestUtils.openEditor(file); @@ -105,13 +110,16 @@ public void testFormattingNoChanges() throws Exception { } @Test - public void testFormatting() + public void testFormatting(MockLanguageServerFactory factory) throws Exception { + final var formattingTextEdits = new ArrayList(); formattingTextEdits.add(new TextEdit(new Range(new Position(0, 0), new Position(0, 1)), "MyF")); formattingTextEdits.add(new TextEdit(new Range(new Position(0, 10), new Position(0, 11)), "")); formattingTextEdits.add(new TextEdit(new Range(new Position(0, 21), new Position(0, 21)), " Second")); - MockLanguageServer.INSTANCE.setFormattingTextEdits(formattingTextEdits); + factory.withConfiguration((idx, server)-> { + server.setFormattingTextEdits(formattingTextEdits); + }); IFile file = TestUtils.createUniqueTestFile(project, "Formatting Other Text"); IEditorPart editor = TestUtils.openEditor(file); @@ -138,13 +146,15 @@ public void testFormatting() } @Test - public void testSelectiveFormatting() throws Exception { + public void testSelectiveFormatting(MockLanguageServerFactory factory) throws Exception { String fileContent = "Line 1\nLine 2\n\nText to be formatted.\nLine 5"; final var formattingTextEdits = new ArrayList(); formattingTextEdits.add(new TextEdit(new Range(new Position(0, 5), new Position(0, 5)), " changed")); formattingTextEdits.add(new TextEdit(new Range(new Position(3, 10), new Position(3, 11)), "\n")); - MockLanguageServer.INSTANCE.setFormattingTextEdits(formattingTextEdits); + factory.withConfiguration((idx, server)-> { + server.setFormattingTextEdits(formattingTextEdits); + }); IFile file = TestUtils.createUniqueTestFile(project, fileContent); IEditorPart editor = TestUtils.openEditor(file); @@ -177,13 +187,15 @@ public void testSelectiveFormatting() throws Exception { } @Test - public void testSelectiveFormattingWithEmptySelection() throws Exception { + public void testSelectiveFormattingWithEmptySelection(MockLanguageServerFactory factory) throws Exception { String fileContent = "Line 1\nLine 2\n\nText to be formatted.\nLine 5"; final var formattingTextEdits = new ArrayList(); formattingTextEdits.add(new TextEdit(new Range(new Position(0, 6), new Position(0, 6)), " changed")); formattingTextEdits.add(new TextEdit(new Range(new Position(3, 10), new Position(3, 11)), "\n")); - MockLanguageServer.INSTANCE.setFormattingTextEdits(formattingTextEdits); + factory.withConfiguration((idx, server)-> { + server.setFormattingTextEdits(formattingTextEdits); + }); IFile file = TestUtils.createUniqueTestFile(project, fileContent); IEditorPart editor = TestUtils.openEditor(file); @@ -221,15 +233,17 @@ private static ServerCapabilities customServerWithoutRangeFormatting() { } @Test - public void testSelectiveFormattingWithIncapableServer() throws Exception { - MockLanguageServer.reset(FormatTest::customServerWithoutRangeFormatting); + public void testSelectiveFormattingWithIncapableServer(MockLanguageServerFactory factory) throws Exception { + factory.withCapabilities(FormatTest::customServerWithoutRangeFormatting); String fileContent = "Line 1\nLine 2\n\nText to be formatted.\nLine 5"; final var formattingTextEdits = new ArrayList(); formattingTextEdits.add(new TextEdit(new Range(new Position(0, 6), new Position(0, 6)), " changed")); formattingTextEdits.add(new TextEdit(new Range(new Position(3, 10), new Position(3, 11)), "\n")); - MockLanguageServer.INSTANCE.setFormattingTextEdits(formattingTextEdits); + factory.withConfiguration((idx, server)-> { + server.setFormattingTextEdits(formattingTextEdits); + }); IFile file = TestUtils.createUniqueTestFile(project, fileContent); IEditorPart editor = TestUtils.openEditor(file); @@ -261,10 +275,12 @@ public void testSelectiveFormattingWithIncapableServer() throws Exception { } @Test - public void testOutdatedFormatting() + public void testOutdatedFormatting(MockLanguageServerFactory factory) throws CoreException, InterruptedException, ExecutionException, BadLocationException { - // Use a non-empty edit list so that a VersionedEdits is produced - MockLanguageServer.INSTANCE.setFormattingTextEdits(List.of(new TextEdit(new Range(new Position(0, 0), new Position(0, 0)), "X"))); + factory.withConfiguration((idx, server)-> { + // Use a non-empty edit list so that a VersionedEdits is produced + server.setFormattingTextEdits(List.of(new TextEdit(new Range(new Position(0, 0), new Position(0, 0)), "X"))); + }); IFile file = TestUtils.createUniqueTestFile(project, "Formatting Other Text"); IEditorPart editor = TestUtils.openEditor(file); @@ -276,7 +292,7 @@ public void testOutdatedFormatting() Optional edits = formatter.requestFormatting(viewer.getDocument(), (ITextSelection) selection).get(); assertTrue(edits.isPresent()); viewer.getDocument().replace(0, 0, "Hello"); - waitForAndAssertCondition(1_000, numberOfChangesIs(1)); + waitForAndAssertCondition(1_000, numberOfChangesIs(1, factory.getServer())); assertThrows(ConcurrentModificationException.class, () -> edits.get().apply()); diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/highlight/HighlightTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/highlight/HighlightTest.java index 457d22a2e..4388f897d 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/highlight/HighlightTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/highlight/HighlightTest.java @@ -33,7 +33,7 @@ import org.eclipse.lsp4e.operations.highlight.HighlightReconcilingStrategy; import org.eclipse.lsp4e.test.utils.AbstractTestWithProject; import org.eclipse.lsp4e.test.utils.TestUtils; -import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4j.DocumentHighlight; import org.eclipse.lsp4j.DocumentHighlightKind; import org.eclipse.lsp4j.Position; @@ -46,15 +46,17 @@ public class HighlightTest extends AbstractTestWithProject{ @Test - public void testHighlight() throws CoreException { + public void testHighlight(MockLanguageServerFactory factory) throws CoreException { checkGenericEditorVersion(); + factory.withConfiguration((idx, server)-> { + server.setDocumentHighlights(Map.ofEntries( // + Map.entry(new Position(0, 1), List.of( // + new DocumentHighlight(new Range(new Position(0, 2), new Position(0, 6)), DocumentHighlightKind.Read), + new DocumentHighlight(new Range(new Position(0, 7), new Position(0, 12)), DocumentHighlightKind.Write), + new DocumentHighlight(new Range(new Position(0, 13), new Position(0, 17)), DocumentHighlightKind.Text) // + )))); + }); - MockLanguageServer.INSTANCE.setDocumentHighlights(Map.ofEntries( // - Map.entry(new Position(0, 1), List.of( // - new DocumentHighlight(new Range(new Position(0, 2), new Position(0, 6)), DocumentHighlightKind.Read), - new DocumentHighlight(new Range(new Position(0, 7), new Position(0, 12)), DocumentHighlightKind.Write), - new DocumentHighlight(new Range(new Position(0, 13), new Position(0, 17)), DocumentHighlightKind.Text) // - )))); final IFile testFile = TestUtils.createUniqueTestFile(project, " READ WRITE TEXT"); final ITextViewer viewer = TestUtils.openTextViewer(testFile); @@ -76,13 +78,16 @@ public void testHighlight() throws CoreException { } @Test - public void testCheckIfOtherAnnotationsRemains() throws CoreException { + public void testCheckIfOtherAnnotationsRemains(MockLanguageServerFactory factory) throws CoreException { checkGenericEditorVersion(); + + factory.withConfiguration((idx, server)-> { + server.setDocumentHighlights(Map.ofEntries( // + Map.entry(new Position(0, 1), List.of( // + new DocumentHighlight(new Range(new Position(0, 2), new Position(0, 6)), DocumentHighlightKind.Read) + )))); + }); - MockLanguageServer.INSTANCE.setDocumentHighlights(Map.ofEntries( // - Map.entry(new Position(0, 1), List.of( // - new DocumentHighlight(new Range(new Position(0, 2), new Position(0, 6)), DocumentHighlightKind.Read) - )))); final IFile testFile = TestUtils.createUniqueTestFile(project, " READ WRITE TEXT"); final ITextViewer viewer = TestUtils.openTextViewer(testFile); @@ -107,19 +112,21 @@ public void testCheckIfOtherAnnotationsRemains() throws CoreException { } @Test - public void testHighlightsInMultipleViewersForOneSource() throws CoreException { + public void testHighlightsInMultipleViewersForOneSource(MockLanguageServerFactory factory) throws CoreException { checkGenericEditorVersion(); // Create a test file with two sets of highlights final IFile testFile = TestUtils.createUniqueTestFile(project, "ONE\nTWO"); - MockLanguageServer.INSTANCE.setDocumentHighlights(Map.ofEntries( // - Map.entry(new Position(0, 1), List.of( // - new DocumentHighlight(new Range(new Position(0, 0), new Position(0, 3)), DocumentHighlightKind.Write) - )), - Map.entry(new Position(1, 1), List.of( // - new DocumentHighlight(new Range(new Position(1, 0), new Position(1, 3)), DocumentHighlightKind.Write) - )))); + factory.withConfiguration((idx, server)-> { + server.setDocumentHighlights(Map.ofEntries( // + Map.entry(new Position(0, 1), List.of( // + new DocumentHighlight(new Range(new Position(0, 0), new Position(0, 3)), DocumentHighlightKind.Write) + )), + Map.entry(new Position(1, 1), List.of( // + new DocumentHighlight(new Range(new Position(1, 0), new Position(1, 3)), DocumentHighlightKind.Write) + )))); + }); // Open the first viewer final var viewer1 = (ISourceViewer) TestUtils.openTextViewer(testFile); diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/hover/HoverTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/hover/HoverTest.java index 2739460cc..f504c920a 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/hover/HoverTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/hover/HoverTest.java @@ -37,7 +37,7 @@ import org.eclipse.lsp4e.operations.hover.LSPTextHover; import org.eclipse.lsp4e.test.utils.AbstractTestWithProject; import org.eclipse.lsp4e.test.utils.TestUtils; -import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4e.ui.UI; import org.eclipse.lsp4j.Hover; import org.eclipse.lsp4j.Position; @@ -67,10 +67,12 @@ public void setUp() { } @Test - public void testHoverRegion() throws CoreException { + public void testHoverRegion(MockLanguageServerFactory factory) throws CoreException { final var hoverResponse = new Hover(List.of(Either.forLeft("HoverContent")), new Range(new Position(0, 0), new Position(0, 10))); - MockLanguageServer.INSTANCE.setHover(hoverResponse); + factory.withConfiguration((idx, server)-> { + server.setHover(hoverResponse); + }); IFile file = TestUtils.createUniqueTestFile(project, "HoverRange Other Text"); ITextViewer viewer = TestUtils.openTextViewer(file); @@ -79,8 +81,10 @@ public void testHoverRegion() throws CoreException { } @Test - public void testHoverRegionInvalidOffset() throws CoreException { - MockLanguageServer.INSTANCE.setHover(null); + public void testHoverRegionInvalidOffset(MockLanguageServerFactory factory) throws CoreException { + factory.withConfiguration((idx, server)-> { + server.setHover(null); + }); IFile file = TestUtils.createUniqueTestFile(project, "HoverRange Other Text"); ITextViewer viewer = TestUtils.openTextViewer(file); @@ -92,10 +96,12 @@ public void testHoverRegionInvalidOffset() throws CoreException { } @Test - public void testHoverInfo() throws Exception { + public void testHoverInfo(MockLanguageServerFactory factory) throws Exception { final var hoverResponse = new Hover(List.of(Either.forLeft("HoverContent")), new Range(new Position(0, 0), new Position(0, 10))); - MockLanguageServer.INSTANCE.setHover(hoverResponse); + factory.withConfiguration((idx, server)-> { + server.setHover(hoverResponse); + }); IFile file = TestUtils.createUniqueTestFile(project, "HoverRange Other Text"); ITextViewer viewer = TestUtils.openTextViewer(file); @@ -107,10 +113,12 @@ public void testHoverInfo() throws Exception { } @Test - public void testHoverInfoEmptyContentList() throws CoreException { + public void testHoverInfoEmptyContentList(MockLanguageServerFactory factory) throws CoreException { final var hoverResponse = new Hover(Collections.emptyList(), new Range(new Position(0, 0), new Position(0, 10))); - MockLanguageServer.INSTANCE.setHover(hoverResponse); + factory.withConfiguration((idx, server)-> { + server.setHover(hoverResponse); + }); IFile file = TestUtils.createUniqueTestFile(project, "HoverRange Other Text"); ITextViewer viewer = TestUtils.openTextViewer(file); @@ -119,8 +127,10 @@ public void testHoverInfoEmptyContentList() throws CoreException { } @Test - public void testHoverInfoInvalidOffset() throws CoreException { - MockLanguageServer.INSTANCE.setHover(null); + public void testHoverInfoInvalidOffset(MockLanguageServerFactory factory) throws CoreException { + factory.withConfiguration((idx, server)-> { + server.setHover(null); + }); IFile file = TestUtils.createUniqueTestFile(project, "HoverRange Other Text"); ITextViewer viewer = TestUtils.openTextViewer(file); @@ -130,10 +140,12 @@ public void testHoverInfoInvalidOffset() throws CoreException { } @Test - public void testHoverEmptyContentItem() throws CoreException { + public void testHoverEmptyContentItem(MockLanguageServerFactory factory) throws CoreException { final var hoverResponse = new Hover(List.of(Either.forLeft("")), new Range(new Position(0, 0), new Position(0, 10))); - MockLanguageServer.INSTANCE.setHover(hoverResponse); + factory.withConfiguration((idx, server)-> { + server.setHover(hoverResponse); + }); IFile file = TestUtils.createUniqueTestFile(project, "HoverRange Other Text"); ITextViewer viewer = TestUtils.openTextViewer(file); @@ -143,10 +155,12 @@ public void testHoverEmptyContentItem() throws CoreException { } @Test - public void testHoverOnExternalFile(@TempDir Path tempDir) throws Exception { + public void testHoverOnExternalFile(@TempDir Path tempDir, MockLanguageServerFactory factory) throws Exception { final var hoverResponse = new Hover(List.of(Either.forLeft("blah")), new Range(new Position(0, 0), new Position(0, 0))); - MockLanguageServer.INSTANCE.setHover(hoverResponse); + factory.withConfiguration((idx, server)-> { + server.setHover(hoverResponse); + }); Path file = Files.createFile(tempDir.resolve("testHoverOnExternalfile.lspt")); ITextViewer viewer = LSPEclipseUtils @@ -157,10 +171,12 @@ public void testHoverOnExternalFile(@TempDir Path tempDir) throws Exception { } @Test - public void testMultipleHovers() throws Exception { + public void testMultipleHovers(MockLanguageServerFactory factory) throws Exception { final var hoverResponse = new Hover(List.of(Either.forLeft("HoverContent")), new Range(new Position(0, 0), new Position(0, 10))); - MockLanguageServer.INSTANCE.setHover(hoverResponse); + factory.withConfiguration((idx, server)-> { + server.setHover(hoverResponse); + }); IFile file = TestUtils.createUniqueTestFileMultiLS(project, "HoverRange Other Text"); ITextViewer viewer = TestUtils.openTextViewer(file); @@ -175,12 +191,14 @@ public void testMultipleHovers() throws Exception { } @Test - public void testIntroUrlLink() throws Exception { + public void testIntroUrlLink(MockLanguageServerFactory factory) throws Exception { final var hoverResponse = new Hover( List.of(Either.forLeft( "[My intro URL link](http://org.eclipse.ui.intro/execute?command=org.eclipse.ui.file.close)")), new Range(new Position(0, 0), new Position(0, 10))); - MockLanguageServer.INSTANCE.setHover(hoverResponse); + factory.withConfiguration((idx, server)-> { + server.setHover(hoverResponse); + }); IFile file = TestUtils.createUniqueTestFile(project, "HoverRange Other Text"); IEditorPart editorPart = TestUtils.openEditor(file); @@ -245,7 +263,7 @@ public void completed(ProgressEvent event) { } @Test - public void testHoverRegionRefreshesForSameOffsetAfterCompletedRequest() throws Exception { + public void testHoverRegionRefreshesForSameOffsetAfterCompletedRequest(MockLanguageServerFactory factory) throws Exception { // Test for https://github.com/eclipse-lsp4e/lsp4e/issues/1514 // Verifies that getHoverRegion refreshes for the same offset after a completed // request, instead of reusing the previous completed hover range indefinitely. @@ -257,15 +275,15 @@ public void testHoverRegionRefreshesForSameOffsetAfterCompletedRequest() throws IFile file = TestUtils.createUniqueTestFile(project, "HoverRange Other Text"); ITextViewer viewer = TestUtils.openTextViewer(file); - MockLanguageServer.INSTANCE.setHover(firstHover); + factory.getServer().setHover(firstHover); assertEquals(new Region(0, 5), hover.getHoverRegion(viewer, 2)); - MockLanguageServer.INSTANCE.setHover(secondHover); + factory.getServer().setHover(secondHover); assertEquals(new Region(6, 4), hover.getHoverRegion(viewer, 2)); } @Test - public void testHoverInfoRefreshesForSameOffsetAfterCompletedRequest() throws Exception { + public void testHoverInfoRefreshesForSameOffsetAfterCompletedRequest(MockLanguageServerFactory factory) throws Exception { // Test for https://github.com/eclipse-lsp4e/lsp4e/issues/1514 // Verifies that a second hover at the same offset recomputes the hover region // and refreshes the hover content after the previous request completed. @@ -277,7 +295,7 @@ public void testHoverInfoRefreshesForSameOffsetAfterCompletedRequest() throws Ex IFile file = TestUtils.createUniqueTestFile(project, "HoverRange Other Text"); ITextViewer viewer = TestUtils.openTextViewer(file); - MockLanguageServer.INSTANCE.setHover(firstHover); + factory.getServer().setHover(firstHover); Region firstRegion = (Region) hover.getHoverRegion(viewer, 2); assertEquals(new Region(0, 5), firstRegion); @@ -285,7 +303,7 @@ public void testHoverInfoRefreshesForSameOffsetAfterCompletedRequest() throws Ex assertNotNull(firstHtml); assertTrue(firstHtml.contains("FirstValue")); - MockLanguageServer.INSTANCE.setHover(secondHover); + factory.getServer().setHover(secondHover); Region secondRegion = (Region) hover.getHoverRegion(viewer, 2); assertEquals(new Region(6, 4), secondRegion); diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/linkedediting/LinkedEditingTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/linkedediting/LinkedEditingTest.java index f612fc756..984b96a18 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/linkedediting/LinkedEditingTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/linkedediting/LinkedEditingTest.java @@ -32,7 +32,7 @@ import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.lsp4e.test.utils.AbstractTestWithProject; import org.eclipse.lsp4e.test.utils.TestUtils; -import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4j.LinkedEditingRanges; import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.Range; @@ -41,8 +41,8 @@ public class LinkedEditingTest extends AbstractTestWithProject { @Test - public void testLinkedEditing() throws CoreException { - final var sourceViewer = setupSimpleHtmlPageViewer(); + public void testLinkedEditing(MockLanguageServerFactory factory) throws CoreException { + final var sourceViewer = setupSimpleHtmlPageViewer(factory); sourceViewer.getTextWidget().setSelection(11); // 10-14 @@ -63,8 +63,8 @@ public void testLinkedEditing() throws CoreException { } @Test - public void testLinkedEditingExitPolicy() throws CoreException { - final var sourceViewer = setupSimpleHtmlPageViewer(); + public void testLinkedEditingExitPolicy(MockLanguageServerFactory factory) throws CoreException { + final var sourceViewer = setupSimpleHtmlPageViewer(factory); // Test linked editing annotation in a tag name position sourceViewer.getTextWidget().setCaretOffset(14); @@ -97,14 +97,16 @@ public void testLinkedEditingExitPolicy() throws CoreException { } @Test - public void testSelectionChange() throws CoreException { + public void testSelectionChange(MockLanguageServerFactory factory) throws CoreException { final var ranges = new ArrayList(); ranges.add(new Range(new Position(0, 0), new Position(0, 5))); ranges.add(new Range(new Position(0, 6), new Position(0, 12))); final var linkedEditingRanges = new LinkedEditingRanges(ranges, "[:A-Z_a-z]*\\b"); - MockLanguageServer.INSTANCE.setLinkedEditingRanges(linkedEditingRanges); + factory.withConfiguration((idx, server)-> { + server.setLinkedEditingRanges(linkedEditingRanges); + }); IFile testFile = TestUtils.createUniqueTestFile(project, "first second"); ITextViewer viewer = TestUtils.openTextViewer(testFile); @@ -137,13 +139,15 @@ private void waitForAnnotationsPresent(final ISourceViewer sourceViewer) { } - private ISourceViewer setupSimpleHtmlPageViewer() throws CoreException { + private ISourceViewer setupSimpleHtmlPageViewer(MockLanguageServerFactory factory) throws CoreException { final var ranges = new ArrayList(); ranges.add(new Range(new Position(1, 3), new Position(1, 7))); ranges.add(new Range(new Position(3, 4), new Position(3, 8))); final var linkkedEditingRanges = new LinkedEditingRanges(ranges, "[:A-Z_a-z]*\\Z"); - MockLanguageServer.INSTANCE.setLinkedEditingRanges(linkkedEditingRanges); + factory.withConfiguration((idx, server)-> { + server.setLinkedEditingRanges(linkkedEditingRanges); + }); IFile testFile = TestUtils.createUniqueTestFile(project, "\n \n a body text\n \n"); ITextViewer viewer = TestUtils.openTextViewer(testFile); diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/message/ShowMessageTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/message/ShowMessageTest.java index c96bcab11..5b4bdc111 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/message/ShowMessageTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/message/ShowMessageTest.java @@ -10,7 +10,6 @@ import static org.eclipse.lsp4e.test.utils.TestUtils.waitForAndAssertCondition; -import java.util.List; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -19,11 +18,10 @@ import org.eclipse.core.runtime.CoreException; import org.eclipse.lsp4e.test.utils.AbstractTestWithProject; import org.eclipse.lsp4e.test.utils.TestUtils; -import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4e.ui.UI; import org.eclipse.lsp4j.MessageParams; import org.eclipse.lsp4j.MessageType; -import org.eclipse.lsp4j.services.LanguageClient; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.ide.IDE; @@ -32,15 +30,14 @@ public class ShowMessageTest extends AbstractTestWithProject { @Test - public void testShowMessage() throws CoreException { + public void testShowMessage(MockLanguageServerFactory factory) throws CoreException { IFile file = TestUtils.createUniqueTestFile(project, ""); IDE.openEditor(UI.getActivePage(), file); final var messageContent = "test notification " + System.currentTimeMillis(); final var message = new MessageParams(MessageType.Error, messageContent); Display display = Display.getDefault(); Set currentShells = Stream.of(display.getShells()).filter(Shell::isVisible).collect(Collectors.toSet()); - List remoteProxies = MockLanguageServer.INSTANCE.getRemoteProxies(); - remoteProxies.forEach(client -> client.showMessage(message)); + factory.getServer().getRemoteProxy().showMessage(message); waitForAndAssertCondition(3_000, () -> Stream.of(display.getShells()).filter(Shell::isVisible).count() > currentShells.size()); } diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/operations/codelens/LSPCodeMiningTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/operations/codelens/LSPCodeMiningTest.java index 0cbcef5f7..504b94803 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/operations/codelens/LSPCodeMiningTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/operations/codelens/LSPCodeMiningTest.java @@ -31,6 +31,7 @@ import org.eclipse.lsp4e.test.utils.AbstractTestWithProject; import org.eclipse.lsp4e.test.utils.TestUtils; import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4j.CodeLens; import org.eclipse.lsp4j.Command; import org.eclipse.lsp4j.ExecuteCommandParams; @@ -91,7 +92,7 @@ public Object execute(ExecutionEvent event, Command command, IPath context) thro } @Test - public void testLSPCodeMiningActionServerSideHandling() + public void testLSPCodeMiningActionServerSideHandling(MockLanguageServerFactory factory) throws Exception { final CodeLens lens = createCodeLens(MockLanguageServer.SUPPORTED_COMMAND_ID); Command command = lens.getCommand(); @@ -103,7 +104,7 @@ public void testLSPCodeMiningActionServerSideHandling() IFile file = TestUtils.createUniqueTestFile(project, "lspt", "test content"); IDocument document = TestUtils.openTextViewer(file).getDocument(); - MockLanguageServer languageServer = MockLanguageServer.INSTANCE; + MockLanguageServer languageServer = factory.getServer(); final var provider = new CodeLensProvider(); LanguageServerWrapper wrapper = LanguageServiceAccessor.getLSWrapper(project, LanguageServersRegistry.getInstance().getDefinition(MOCK_SERVER_ID)); diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/operations/inlayhint/LSPLineContentCodeMiningTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/operations/inlayhint/LSPLineContentCodeMiningTest.java index 2fbded965..591035d1e 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/operations/inlayhint/LSPLineContentCodeMiningTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/operations/inlayhint/LSPLineContentCodeMiningTest.java @@ -28,6 +28,7 @@ import org.eclipse.lsp4e.test.utils.AbstractTestWithProject; import org.eclipse.lsp4e.test.utils.TestUtils; import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4j.Command; import org.eclipse.lsp4j.ExecuteCommandParams; import org.eclipse.lsp4j.InlayHint; @@ -47,7 +48,7 @@ public class LSPLineContentCodeMiningTest extends AbstractTestWithProject { private static final String MOCK_SERVER_ID = "org.eclipse.lsp4e.test.server"; @Test - public void singleLabelPartCommand() throws Exception { + public void singleLabelPartCommand(MockLanguageServerFactory factory) throws Exception { final InlayHint inlay = createMultiLabelInlayHint(createInlayLabelPart("Label-Text", MockLanguageServer.SUPPORTED_COMMAND_ID)); Command command = inlay.getLabel().getRight().get(0).getCommand(); final var jsonObject = new JsonObject(); @@ -59,7 +60,7 @@ public void singleLabelPartCommand() throws Exception { ITextViewer textViewer = TestUtils.openTextViewer(file); IDocument document = textViewer.getDocument(); - MockLanguageServer languageServer = MockLanguageServer.INSTANCE; + MockLanguageServer languageServer = factory.getServer(); final var provider = new InlayHintProvider(); LanguageServerWrapper wrapper = LanguageServiceAccessor.getLSWrapper(project, LanguageServersRegistry.getInstance().getDefinition(MOCK_SERVER_ID)); diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/operations/rename/FileOperationParticipantsTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/operations/rename/FileOperationParticipantsTest.java index af6121fd5..fce118b43 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/operations/rename/FileOperationParticipantsTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/operations/rename/FileOperationParticipantsTest.java @@ -11,7 +11,9 @@ *******************************************************************************/ package org.eclipse.lsp4e.test.operations.rename; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.net.URI; import java.util.List; @@ -23,6 +25,7 @@ import org.eclipse.lsp4e.test.utils.AbstractTestWithProject; import org.eclipse.lsp4e.test.utils.TestUtils; import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4e.tests.mock.MockWorkspaceService; import org.eclipse.lsp4j.CreateFilesParams; import org.eclipse.lsp4j.DeleteFilesParams; @@ -36,30 +39,26 @@ import org.eclipse.lsp4j.RenameFilesParams; import org.eclipse.lsp4j.ServerCapabilities; import org.eclipse.lsp4j.WorkspaceServerCapabilities; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; class FileOperationParticipantsTest extends AbstractTestWithProject { - @BeforeEach - void setupCaps() { - MockLanguageServer.reset(() -> { - ServerCapabilities caps = MockLanguageServer.defaultServerCapabilities(); - var ws = new WorkspaceServerCapabilities(); - var fileOps = new FileOperationsServerCapabilities(); - fileOps.setWillCreate(new FileOperationOptions()); - fileOps.setWillRename(new FileOperationOptions()); - fileOps.setWillDelete(new FileOperationOptions()); - ws.setFileOperations(fileOps); - caps.setWorkspace(ws); - return caps; - }); + private ServerCapabilities capabilities() { + ServerCapabilities caps = MockLanguageServer.defaultServerCapabilities(); + var ws = new WorkspaceServerCapabilities(); + var fileOps = new FileOperationsServerCapabilities(); + fileOps.setWillCreate(new FileOperationOptions()); + fileOps.setWillRename(new FileOperationOptions()); + fileOps.setWillDelete(new FileOperationOptions()); + ws.setFileOperations(fileOps); + caps.setWorkspace(ws); + return caps; } @Test - void testFilterGlobMatching() throws Exception { + void testFilterGlobMatching(MockLanguageServerFactory factory) throws Exception { // Reconfigure with a forward-slash glob filter - MockLanguageServer.reset(() -> { + factory.withCapabilities(() -> { ServerCapabilities caps = MockLanguageServer.defaultServerCapabilities(); var ws = new WorkspaceServerCapabilities(); var fileOps = new FileOperationsServerCapabilities(); @@ -81,7 +80,8 @@ void testFilterGlobMatching() throws Exception { } @Test - void testWillRename() throws Exception { + void testWillRename(MockLanguageServerFactory factory) throws Exception { + factory.withCapabilities(this::capabilities); IFile file = TestUtils.createUniqueTestFile(project, "content"); TestUtils.openTextViewer(file); URI uri = LSPEclipseUtils.toUri(file); @@ -102,7 +102,7 @@ void testWillRename() throws Exception { LSPFileOperationParticipantSupport.computePreChange("rename", params, executor, (ws, p) -> ws.willRenameFiles(p)); - MockWorkspaceService ws = MockLanguageServer.INSTANCE.getWorkspaceService(); + MockWorkspaceService ws = factory.getServer().getWorkspaceService(); assertNotNull(ws.getLastWillRename()); assertEquals(1, ws.getLastWillRename().getFiles().size()); assertEquals(uri.toString(), ws.getLastWillRename().getFiles().get(0).getOldUri()); @@ -110,7 +110,8 @@ void testWillRename() throws Exception { } @Test - void testWillCreate() throws Exception { + void testWillCreate(MockLanguageServerFactory factory) throws Exception { + factory.withCapabilities(this::capabilities); IFile file = TestUtils.createUniqueTestFile(project, "content"); TestUtils.openTextViewer(file); URI uri = LSPEclipseUtils.toUri(file); @@ -126,14 +127,15 @@ void testWillCreate() throws Exception { LSPFileOperationParticipantSupport.computePreChange("create", params, executor, (ws, p) -> ws.willCreateFiles(p)); - MockWorkspaceService ws = MockLanguageServer.INSTANCE.getWorkspaceService(); + MockWorkspaceService ws = factory.getServer().getWorkspaceService(); assertNotNull(ws.getLastWillCreate()); assertEquals(1, ws.getLastWillCreate().getFiles().size()); assertEquals(uri.toString(), ws.getLastWillCreate().getFiles().get(0).getUri()); } @Test - void testWillDelete() throws Exception { + void testWillDelete(MockLanguageServerFactory factory) throws Exception { + factory.withCapabilities(this::capabilities); IFile file = TestUtils.createUniqueTestFile(project, "content"); TestUtils.openTextViewer(file); URI uri = LSPEclipseUtils.toUri(file); @@ -149,7 +151,7 @@ void testWillDelete() throws Exception { LSPFileOperationParticipantSupport.computePreChange("delete", params, executor, (ws, p) -> ws.willDeleteFiles(p)); - MockWorkspaceService ws = MockLanguageServer.INSTANCE.getWorkspaceService(); + MockWorkspaceService ws = factory.getServer().getWorkspaceService(); assertNotNull(ws.getLastWillDelete()); assertEquals(1, ws.getLastWillDelete().getFiles().size()); assertEquals(uri.toString(), ws.getLastWillDelete().getFiles().get(0).getUri()); diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/operations/rename/FolderOperationParticipantsTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/operations/rename/FolderOperationParticipantsTest.java index 148f3b3a4..2593382ab 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/operations/rename/FolderOperationParticipantsTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/operations/rename/FolderOperationParticipantsTest.java @@ -11,7 +11,9 @@ *******************************************************************************/ package org.eclipse.lsp4e.test.operations.rename; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.net.URI; import java.util.List; @@ -24,6 +26,7 @@ import org.eclipse.lsp4e.test.utils.AbstractTestWithProject; import org.eclipse.lsp4e.test.utils.TestUtils; import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4e.tests.mock.MockWorkspaceService; import org.eclipse.lsp4j.CreateFilesParams; import org.eclipse.lsp4j.DeleteFilesParams; @@ -43,9 +46,9 @@ class FolderOperationParticipantsTest extends AbstractTestWithProject { @Test - void testFolderFilterGlobMatching() throws Exception { + void testFolderFilterGlobMatching(MockLanguageServerFactory factory) throws Exception { // Reconfigure with a folder-only glob filter - MockLanguageServer.reset(() -> { + factory.withCapabilities(() -> { ServerCapabilities caps = MockLanguageServer.defaultServerCapabilities(); var ws = new WorkspaceServerCapabilities(); var fileOps = new FileOperationsServerCapabilities(); @@ -76,9 +79,9 @@ void testFolderFilterGlobMatching() throws Exception { } @Test - void testFolderWillRename() throws Exception { + void testFolderWillRename(MockLanguageServerFactory factory) throws Exception { // Enable unfiltered file ops - MockLanguageServer.reset(() -> { + factory.withCapabilities(() -> { ServerCapabilities caps = MockLanguageServer.defaultServerCapabilities(); var ws = new WorkspaceServerCapabilities(); var fileOps = new FileOperationsServerCapabilities(); @@ -111,7 +114,7 @@ void testFolderWillRename() throws Exception { LSPFileOperationParticipantSupport.computePreChange("rename-folder", params, executor, (ws, p) -> ws.willRenameFiles(p)); - MockWorkspaceService ws = MockLanguageServer.INSTANCE.getWorkspaceService(); + MockWorkspaceService ws = factory.getServer().getWorkspaceService(); assertNotNull(ws.getLastWillRename()); assertEquals(1, ws.getLastWillRename().getFiles().size()); assertEquals(oldUri.toString(), ws.getLastWillRename().getFiles().get(0).getOldUri()); @@ -119,8 +122,8 @@ void testFolderWillRename() throws Exception { } @Test - void testFolderWillCreate() throws Exception { - MockLanguageServer.reset(() -> { + void testFolderWillCreate(MockLanguageServerFactory factory) throws Exception { + factory.withCapabilities(() -> { ServerCapabilities caps = MockLanguageServer.defaultServerCapabilities(); var ws = new WorkspaceServerCapabilities(); var fileOps = new FileOperationsServerCapabilities(); @@ -148,15 +151,15 @@ void testFolderWillCreate() throws Exception { LSPFileOperationParticipantSupport.computePreChange("create-folder", params, executor, (ws, p) -> ws.willCreateFiles(p)); - MockWorkspaceService ws = MockLanguageServer.INSTANCE.getWorkspaceService(); + MockWorkspaceService ws = factory.getServer().getWorkspaceService(); assertNotNull(ws.getLastWillCreate()); assertEquals(1, ws.getLastWillCreate().getFiles().size()); assertEquals(uri.toString(), ws.getLastWillCreate().getFiles().get(0).getUri()); } @Test - void testFolderWillDelete() throws Exception { - MockLanguageServer.reset(() -> { + void testFolderWillDelete(MockLanguageServerFactory factory) throws Exception { + factory.withCapabilities(() -> { ServerCapabilities caps = MockLanguageServer.defaultServerCapabilities(); var ws = new WorkspaceServerCapabilities(); var fileOps = new FileOperationsServerCapabilities(); @@ -186,7 +189,7 @@ void testFolderWillDelete() throws Exception { LSPFileOperationParticipantSupport.computePreChange("delete-folder", params, executor, (ws, p) -> ws.willDeleteFiles(p)); - MockWorkspaceService ws = MockLanguageServer.INSTANCE.getWorkspaceService(); + MockWorkspaceService ws = factory.getServer().getWorkspaceService(); assertNotNull(ws.getLastWillDelete()); assertEquals(1, ws.getLastWillDelete().getFiles().size()); assertEquals(uri.toString(), ws.getLastWillDelete().getFiles().get(0).getUri()); diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/operations/rename/LSPCreateParticipantTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/operations/rename/LSPCreateParticipantTest.java index a842e78fe..7694ad84f 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/operations/rename/LSPCreateParticipantTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/operations/rename/LSPCreateParticipantTest.java @@ -11,7 +11,9 @@ *******************************************************************************/ package org.eclipse.lsp4e.test.operations.rename; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.net.URI; @@ -24,6 +26,7 @@ import org.eclipse.lsp4e.test.utils.AbstractTestWithProject; import org.eclipse.lsp4e.test.utils.TestUtils; import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4e.tests.mock.MockWorkspaceService; import org.eclipse.lsp4j.FileOperationOptions; import org.eclipse.lsp4j.FileOperationsServerCapabilities; @@ -31,7 +34,6 @@ import org.eclipse.lsp4j.WorkspaceServerCapabilities; import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext; import org.eclipse.ltk.core.refactoring.participants.CreateArguments; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; class LSPCreateParticipantTest extends AbstractTestWithProject { @@ -54,21 +56,10 @@ public CreateArguments getArguments() { } } - @BeforeEach - void setupCaps() { - MockLanguageServer.reset(() -> { - ServerCapabilities caps = MockLanguageServer.defaultServerCapabilities(); - var ws = new WorkspaceServerCapabilities(); - var fileOps = new FileOperationsServerCapabilities(); - fileOps.setWillCreate(new FileOperationOptions()); - ws.setFileOperations(fileOps); - caps.setWorkspace(ws); - return caps; - }); - } - @Test - void fileCreateSendsWillCreate() throws Exception { + void fileCreateSendsWillCreate(MockLanguageServerFactory serverConfig) throws Exception { + serverConfig.withCapabilities(this::capabilitiesWithWillCreate); + // start LS IFile starter = TestUtils.createUniqueTestFile(project, "content"); TestUtils.openTextViewer(starter); @@ -84,14 +75,26 @@ void fileCreateSendsWillCreate() throws Exception { participant.checkConditions(new NullProgressMonitor(), new CheckConditionsContext()); participant.createPreChange(new NullProgressMonitor()); - MockWorkspaceService ws = MockLanguageServer.INSTANCE.getWorkspaceService(); + MockWorkspaceService ws = serverConfig.getServer().getWorkspaceService(); assertNotNull(ws.getLastWillCreate()); assertEquals(1, ws.getLastWillCreate().getFiles().size()); assertEquals(uri.toString(), ws.getLastWillCreate().getFiles().get(0).getUri()); } + private ServerCapabilities capabilitiesWithWillCreate() { + ServerCapabilities caps = MockLanguageServer.defaultServerCapabilities(); + var ws = new WorkspaceServerCapabilities(); + var fileOps = new FileOperationsServerCapabilities(); + fileOps.setWillCreate(new FileOperationOptions()); + ws.setFileOperations(fileOps); + caps.setWorkspace(ws); + return caps; + } + @Test - void folderCreateSendsWillCreate() throws Exception { + void folderCreateSendsWillCreate(MockLanguageServerFactory serverConfig) throws Exception { + serverConfig.withCapabilities(this::capabilitiesWithWillCreate); + // start LS IFile starter = TestUtils.createUniqueTestFile(project, "content"); TestUtils.openTextViewer(starter); @@ -107,7 +110,7 @@ void folderCreateSendsWillCreate() throws Exception { participant.checkConditions(new NullProgressMonitor(), new CheckConditionsContext()); participant.createPreChange(new NullProgressMonitor()); - MockWorkspaceService ws = MockLanguageServer.INSTANCE.getWorkspaceService(); + MockWorkspaceService ws = serverConfig.getServer().getWorkspaceService(); assertNotNull(ws.getLastWillCreate()); assertEquals(1, ws.getLastWillCreate().getFiles().size()); assertEquals(uri.toString(), ws.getLastWillCreate().getFiles().get(0).getUri()); diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/operations/rename/LSPDeleteParticipantTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/operations/rename/LSPDeleteParticipantTest.java index 1e9a81c94..0439315ab 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/operations/rename/LSPDeleteParticipantTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/operations/rename/LSPDeleteParticipantTest.java @@ -11,7 +11,9 @@ *******************************************************************************/ package org.eclipse.lsp4e.test.operations.rename; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.net.URI; @@ -24,6 +26,7 @@ import org.eclipse.lsp4e.test.utils.AbstractTestWithProject; import org.eclipse.lsp4e.test.utils.TestUtils; import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4e.tests.mock.MockWorkspaceService; import org.eclipse.lsp4j.FileOperationOptions; import org.eclipse.lsp4j.FileOperationsServerCapabilities; @@ -31,7 +34,6 @@ import org.eclipse.lsp4j.WorkspaceServerCapabilities; import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext; import org.eclipse.ltk.core.refactoring.participants.DeleteArguments; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; class LSPDeleteParticipantTest extends AbstractTestWithProject { @@ -54,21 +56,19 @@ public DeleteArguments getArguments() { } } - @BeforeEach - void setupCaps() { - MockLanguageServer.reset(() -> { - ServerCapabilities caps = MockLanguageServer.defaultServerCapabilities(); - var ws = new WorkspaceServerCapabilities(); - var fileOps = new FileOperationsServerCapabilities(); - fileOps.setWillDelete(new FileOperationOptions()); - ws.setFileOperations(fileOps); - caps.setWorkspace(ws); - return caps; - }); + public ServerCapabilities capabilities() { + ServerCapabilities caps = MockLanguageServer.defaultServerCapabilities(); + var ws = new WorkspaceServerCapabilities(); + var fileOps = new FileOperationsServerCapabilities(); + fileOps.setWillDelete(new FileOperationOptions()); + ws.setFileOperations(fileOps); + caps.setWorkspace(ws); + return caps; } @Test - void fileDeleteSendsWillDelete() throws Exception { + void fileDeleteSendsWillDelete(MockLanguageServerFactory factory) throws Exception { + factory.withCapabilities(this::capabilities); IFile file = TestUtils.createUniqueTestFile(project, "content"); TestUtils.openTextViewer(file); // start LS assertTrue(LanguageServers.forProject(project).anyMatching()); @@ -82,14 +82,15 @@ void fileDeleteSendsWillDelete() throws Exception { participant.checkConditions(new NullProgressMonitor(), new CheckConditionsContext()); participant.createPreChange(new NullProgressMonitor()); - MockWorkspaceService ws = MockLanguageServer.INSTANCE.getWorkspaceService(); + MockWorkspaceService ws = factory.getServer().getWorkspaceService(); assertNotNull(ws.getLastWillDelete()); assertEquals(1, ws.getLastWillDelete().getFiles().size()); assertEquals(uri.toString(), ws.getLastWillDelete().getFiles().get(0).getUri()); } @Test - void folderDeleteSendsWillDelete() throws Exception { + void folderDeleteSendsWillDelete(MockLanguageServerFactory factory) throws Exception { + factory.withCapabilities(this::capabilities); // Start LS with a file IFile starter = TestUtils.createUniqueTestFile(project, "content"); TestUtils.openTextViewer(starter); @@ -108,7 +109,7 @@ void folderDeleteSendsWillDelete() throws Exception { participant.checkConditions(new NullProgressMonitor(), new CheckConditionsContext()); participant.createPreChange(new NullProgressMonitor()); - MockWorkspaceService ws = MockLanguageServer.INSTANCE.getWorkspaceService(); + MockWorkspaceService ws = factory.getServer().getWorkspaceService(); assertNotNull(ws.getLastWillDelete()); assertEquals(1, ws.getLastWillDelete().getFiles().size()); assertEquals(uri.toString(), ws.getLastWillDelete().getFiles().get(0).getUri()); diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/operations/rename/LSPMoveParticipantTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/operations/rename/LSPMoveParticipantTest.java index d8fe42b22..0c46a2a7d 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/operations/rename/LSPMoveParticipantTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/operations/rename/LSPMoveParticipantTest.java @@ -11,7 +11,9 @@ *******************************************************************************/ package org.eclipse.lsp4e.test.operations.rename; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.net.URI; @@ -25,13 +27,13 @@ import org.eclipse.lsp4e.test.utils.AbstractTestWithProject; import org.eclipse.lsp4e.test.utils.TestUtils; import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4e.tests.mock.MockWorkspaceService; import org.eclipse.lsp4j.FileOperationOptions; import org.eclipse.lsp4j.FileOperationsServerCapabilities; import org.eclipse.lsp4j.ServerCapabilities; import org.eclipse.lsp4j.WorkspaceServerCapabilities; import org.eclipse.ltk.core.refactoring.participants.MoveArguments; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; class LSPMoveParticipantTest extends AbstractTestWithProject { @@ -54,21 +56,19 @@ public MoveArguments getArguments() { } } - @BeforeEach - void setupCaps() { - MockLanguageServer.reset(() -> { - ServerCapabilities caps = MockLanguageServer.defaultServerCapabilities(); - var ws = new WorkspaceServerCapabilities(); - var fileOps = new FileOperationsServerCapabilities(); - fileOps.setWillRename(new FileOperationOptions()); - ws.setFileOperations(fileOps); - caps.setWorkspace(ws); - return caps; - }); + private ServerCapabilities capabilities() { + ServerCapabilities caps = MockLanguageServer.defaultServerCapabilities(); + var ws = new WorkspaceServerCapabilities(); + var fileOps = new FileOperationsServerCapabilities(); + fileOps.setWillRename(new FileOperationOptions()); + ws.setFileOperations(fileOps); + caps.setWorkspace(ws); + return caps; } @Test - void computesNewUriFromDestinationResource() throws Exception { + void computesNewUriFromDestinationResource(MockLanguageServerFactory factory) throws Exception { + factory.withCapabilities(this::capabilities); IFile file = TestUtils.createUniqueTestFile(project, "content"); TestUtils.openTextViewer(file); // start LS assertTrue(LanguageServers.forProject(project).anyMatching()); @@ -89,7 +89,7 @@ void computesNewUriFromDestinationResource() throws Exception { assertTrue(participant.initialize(file)); participant.createPreChange(new NullProgressMonitor()); - MockWorkspaceService ws = MockLanguageServer.INSTANCE.getWorkspaceService(); + MockWorkspaceService ws = factory.getServer().getWorkspaceService(); assertNotNull(ws.getLastWillRename()); assertEquals(1, ws.getLastWillRename().getFiles().size()); assertEquals(oldUri.toString(), ws.getLastWillRename().getFiles().get(0).getOldUri()); @@ -97,7 +97,8 @@ void computesNewUriFromDestinationResource() throws Exception { } @Test - void computesNewUriFromDestinationPath() throws Exception { + void computesNewUriFromDestinationPath(MockLanguageServerFactory factory) throws Exception { + factory.withCapabilities(this::capabilities); IFile file = TestUtils.createUniqueTestFile(project, "content"); TestUtils.openTextViewer(file); // start LS assertTrue(LanguageServers.forProject(project).anyMatching()); @@ -118,7 +119,7 @@ void computesNewUriFromDestinationPath() throws Exception { assertTrue(participant.initialize(file)); participant.createPreChange(new NullProgressMonitor()); - MockWorkspaceService ws = MockLanguageServer.INSTANCE.getWorkspaceService(); + MockWorkspaceService ws = factory.getServer().getWorkspaceService(); assertNotNull(ws.getLastWillRename()); assertEquals(1, ws.getLastWillRename().getFiles().size()); assertEquals(oldUri.toString(), ws.getLastWillRename().getFiles().get(0).getOldUri()); diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/operations/rename/LSPRenameParticipantTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/operations/rename/LSPRenameParticipantTest.java index 2676df900..4934fa3d3 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/operations/rename/LSPRenameParticipantTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/operations/rename/LSPRenameParticipantTest.java @@ -11,7 +11,9 @@ *******************************************************************************/ package org.eclipse.lsp4e.test.operations.rename; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.net.URI; @@ -26,13 +28,13 @@ import org.eclipse.lsp4e.test.utils.AbstractTestWithProject; import org.eclipse.lsp4e.test.utils.TestUtils; import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4e.tests.mock.MockWorkspaceService; import org.eclipse.lsp4j.FileOperationOptions; import org.eclipse.lsp4j.FileOperationsServerCapabilities; import org.eclipse.lsp4j.ServerCapabilities; import org.eclipse.lsp4j.WorkspaceServerCapabilities; import org.eclipse.ltk.core.refactoring.participants.RenameArguments; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; class LSPRenameParticipantTest extends AbstractTestWithProject { @@ -55,21 +57,19 @@ public RenameArguments getArguments() { } } - @BeforeEach - void setupCaps() { - MockLanguageServer.reset(() -> { - ServerCapabilities caps = MockLanguageServer.defaultServerCapabilities(); - var ws = new WorkspaceServerCapabilities(); - var fileOps = new FileOperationsServerCapabilities(); - fileOps.setWillRename(new FileOperationOptions()); - ws.setFileOperations(fileOps); - caps.setWorkspace(ws); - return caps; - }); + private ServerCapabilities capabilities() { + ServerCapabilities caps = MockLanguageServer.defaultServerCapabilities(); + var ws = new WorkspaceServerCapabilities(); + var fileOps = new FileOperationsServerCapabilities(); + fileOps.setWillRename(new FileOperationOptions()); + ws.setFileOperations(fileOps); + caps.setWorkspace(ws); + return caps; } @Test - void computesNewUriFromNewName() throws Exception { + void computesNewUriFromNewName(MockLanguageServerFactory factory) throws Exception { + factory.withCapabilities(this::capabilities); IFile file = TestUtils.createUniqueTestFile(project, "content"); TestUtils.openTextViewer(file); // start LS assertTrue(LanguageServers.forProject(project).anyMatching()); @@ -92,7 +92,7 @@ void computesNewUriFromNewName() throws Exception { assertTrue(participant.initialize(file)); participant.createPreChange(new NullProgressMonitor()); - MockWorkspaceService ws = MockLanguageServer.INSTANCE.getWorkspaceService(); + MockWorkspaceService ws = factory.getServer().getWorkspaceService(); assertNotNull(ws.getLastWillRename()); assertEquals(1, ws.getLastWillRename().getFiles().size()); assertEquals(oldUri.toString(), ws.getLastWillRename().getFiles().get(0).getOldUri()); @@ -100,7 +100,8 @@ void computesNewUriFromNewName() throws Exception { } @Test - void computesNewUriForFolderFromNewName() throws Exception { + void computesNewUriForFolderFromNewName(MockLanguageServerFactory factory) throws Exception { + factory.withCapabilities(this::capabilities); // Start LS IFile starter = TestUtils.createUniqueTestFile(project, "content"); TestUtils.openTextViewer(starter); @@ -130,7 +131,7 @@ void computesNewUriForFolderFromNewName() throws Exception { assertTrue(participant.initialize(folder)); participant.createPreChange(new NullProgressMonitor()); - MockWorkspaceService ws = MockLanguageServer.INSTANCE.getWorkspaceService(); + MockWorkspaceService ws = factory.getServer().getWorkspaceService(); assertNotNull(ws.getLastWillRename()); assertEquals(1, ws.getLastWillRename().getFiles().size()); assertEquals(oldUri.toString(), ws.getLastWillRename().getFiles().get(0).getOldUri()); diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/outline/EditorToOutlineAdapterFactoryTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/outline/EditorToOutlineAdapterFactoryTest.java index ffc47cebb..6bdd2c4ef 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/outline/EditorToOutlineAdapterFactoryTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/outline/EditorToOutlineAdapterFactoryTest.java @@ -18,7 +18,7 @@ import org.eclipse.core.runtime.CoreException; import org.eclipse.lsp4e.test.utils.AbstractTestWithProject; import org.eclipse.lsp4e.test.utils.TestUtils; -import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4e.ui.UI; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.IViewPart; @@ -45,11 +45,13 @@ public static void setUpBeforeClass() { } @Test - public void testGetAdapter() throws CoreException { + public void testGetAdapter(MockLanguageServerFactory factory) throws CoreException { IFile testFile = TestUtils.createUniqueTestFile(project, "Hello World !!"); outline.partClosed(outline); - MockLanguageServer.INSTANCE.setTimeToProceedQueries(500); + factory.withConfiguration((idx, server)-> { + server.setTimeToProceedQueries(500); + }); TestUtils.openEditor(testFile); long beginOpenOutline = System.currentTimeMillis(); diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/outline/OutlineContentTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/outline/OutlineContentTest.java index ba616b5f7..562c28fa7 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/outline/OutlineContentTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/outline/OutlineContentTest.java @@ -33,7 +33,7 @@ import org.eclipse.lsp4e.outline.SymbolsModel.DocumentSymbolWithURI; import org.eclipse.lsp4e.test.utils.AbstractTestWithProject; import org.eclipse.lsp4e.test.utils.TestUtils; -import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4j.DocumentSymbol; import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.Range; @@ -51,14 +51,16 @@ public class OutlineContentTest extends AbstractTestWithProject { @Test - public void testExternalFile(@TempDir Path tempDir) throws CoreException, IOException { + public void testExternalFile(@TempDir Path tempDir, MockLanguageServerFactory factory) throws CoreException, IOException { var testFile = Files.writeString(tempDir.resolve("test.lspt"), "content\n does\n not\n matter\n but needs to cover the ranges described below"); final var symbolCow = new DocumentSymbol("cow", SymbolKind.Constant, new Range(new Position(0, 0), new Position(0, 2)), new Range(new Position(0, 0), new Position(0, 2))); - MockLanguageServer.INSTANCE.setDocumentSymbols(symbolCow); + factory.withConfiguration((idx, server)-> { + server.setDocumentSymbols(symbolCow); + }); final var editor = (ITextEditor) TestUtils.openExternalFileInEditor(testFile); @@ -81,14 +83,16 @@ public void testExternalFile(@TempDir Path tempDir) throws CoreException, IOExce } @Test - public void testExternalFileOpenedOnFileStore(@TempDir Path tempDir) throws CoreException, IOException { + public void testExternalFileOpenedOnFileStore(@TempDir Path tempDir, MockLanguageServerFactory factory) throws CoreException, IOException { var testFile = Files.writeString(tempDir.resolve("test.lspt"), "content\n does\n not\n matter\n but needs to cover the ranges described below"); final var symbolCow = new DocumentSymbol("cow", SymbolKind.Constant, new Range(new Position(0, 0), new Position(0, 2)), new Range(new Position(0, 0), new Position(0, 2))); - MockLanguageServer.INSTANCE.setDocumentSymbols(symbolCow); + factory.withConfiguration((idx, server)-> { + server.setDocumentSymbols(symbolCow); + }); final var editor = (ITextEditor) TestUtils.openExternalFileOnFileStore(testFile); @@ -111,7 +115,7 @@ public void testExternalFileOpenedOnFileStore(@TempDir Path tempDir) throws Core } @Test - public void testOutlineSorting() throws CoreException { + public void testOutlineSorting(MockLanguageServerFactory factory) throws CoreException { IFile testFile = TestUtils.createUniqueTestFile(project, "content\n does\n not\n matter\n but needs to cover the ranges described below"); final var symbolCow = new DocumentSymbol("cow", SymbolKind.Constant, new Range(new Position(0, 0), new Position(0, 2)), @@ -123,7 +127,9 @@ public void testOutlineSorting() throws CoreException { new Range(new Position(2, 0), new Position(2, 2)), new Range(new Position(2, 0), new Position(2, 2))); - MockLanguageServer.INSTANCE.setDocumentSymbols(symbolCow, symbolFox, symbolCat); + factory.withConfiguration((idx, server)-> { + server.setDocumentSymbols(symbolCow, symbolFox, symbolCat); + }); // ensure outline sorting is disabled IEclipsePreferences prefs = InstanceScope.INSTANCE.getNode(LanguageServerPlugin.PLUGIN_ID); @@ -162,14 +168,16 @@ public void testOutlineSorting() throws CoreException { } @Test - public void testNodeRemainExpandedUponSelection() throws CoreException { + public void testNodeRemainExpandedUponSelection(MockLanguageServerFactory factory) throws CoreException { IFile testFile = TestUtils.createUniqueTestFile(project, "a(b())"); - MockLanguageServer.INSTANCE.setDocumentSymbols( - new DocumentSymbol("a", SymbolKind.Constant, new Range(new Position(0, 0), new Position(0, 6)), - new Range(new Position(0, 0), new Position(0, 1)), "", - List.of(new DocumentSymbol("b", SymbolKind.Constant, - new Range(new Position(0, 2), new Position(0, 5)), - new Range(new Position(0, 2), new Position(0, 3)))))); + factory.withConfiguration((idx, server)-> { + server.setDocumentSymbols( + new DocumentSymbol("a", SymbolKind.Constant, new Range(new Position(0, 0), new Position(0, 6)), + new Range(new Position(0, 0), new Position(0, 1)), "", + List.of(new DocumentSymbol("b", SymbolKind.Constant, + new Range(new Position(0, 2), new Position(0, 5)), + new Range(new Position(0, 2), new Position(0, 3)))))); + }); final var editor = (ITextEditor) TestUtils.openEditor(testFile); LanguageServerWrapper wrapper = LanguageServiceAccessor.getLSWrappers(testFile, request -> true).iterator().next(); @@ -197,14 +205,16 @@ public void testNodeRemainExpandedUponSelection() throws CoreException { } @Test - public void testNodeRemainExpandedUponModification() throws CoreException, BadLocationException { + public void testNodeRemainExpandedUponModification(MockLanguageServerFactory factory) throws CoreException, BadLocationException { IFile testFile = TestUtils.createUniqueTestFile(project, "a(b())"); - MockLanguageServer.INSTANCE.setDocumentSymbols( - new DocumentSymbol("a", SymbolKind.Constant, new Range(new Position(0, 0), new Position(0, 6)), - new Range(new Position(0, 0), new Position(0, 1)), "", - List.of(new DocumentSymbol("b", SymbolKind.Constant, - new Range(new Position(0, 2), new Position(0, 5)), - new Range(new Position(0, 2), new Position(0, 3)))))); + factory.withConfiguration((idx, server)-> { + server.setDocumentSymbols( + new DocumentSymbol("a", SymbolKind.Constant, new Range(new Position(0, 0), new Position(0, 6)), + new Range(new Position(0, 0), new Position(0, 1)), "", + List.of(new DocumentSymbol("b", SymbolKind.Constant, + new Range(new Position(0, 2), new Position(0, 5)), + new Range(new Position(0, 2), new Position(0, 3)))))); + }); final var editor = (ITextEditor) TestUtils.openEditor(testFile); LanguageServerWrapper wrapper = LanguageServiceAccessor.getLSWrappers(testFile, request -> true).iterator().next(); diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/outline/SymbolsLabelProviderTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/outline/SymbolsLabelProviderTest.java index 5718ce61a..50177c572 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/outline/SymbolsLabelProviderTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/outline/SymbolsLabelProviderTest.java @@ -16,7 +16,6 @@ import org.eclipse.lsp4e.outline.SymbolsLabelProvider; import org.eclipse.lsp4e.outline.SymbolsModel; -import org.eclipse.lsp4e.test.utils.AbstractTest; import org.eclipse.lsp4j.DocumentSymbol; import org.eclipse.lsp4j.Location; import org.eclipse.lsp4j.Position; @@ -27,7 +26,7 @@ import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.junit.jupiter.api.Test; -public class SymbolsLabelProviderTest extends AbstractTest { +public class SymbolsLabelProviderTest { private static final Location LOCATION = new Location("path/to/foo", new Range(new Position(0,0), new Position(1,1))); private static final Location INVALID_LOCATION = new Location("file:://///invalid_location_uri", new Range(new Position(0,0), new Position(1,1))); diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/references/FindReferencesTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/references/FindReferencesTest.java index 2b883e7b4..9ea47be6f 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/references/FindReferencesTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/references/FindReferencesTest.java @@ -31,7 +31,7 @@ import org.eclipse.lsp4e.operations.references.LSSearchResult; import org.eclipse.lsp4e.test.utils.AbstractTestWithProject; import org.eclipse.lsp4e.test.utils.TestUtils; -import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4j.Location; import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.Range; @@ -73,13 +73,6 @@ public void log(UiFreezeEvent event) { @BeforeEach public void setUp() throws Exception { ensureSearchResultViewIsClosed(); - - final var testFile = TestUtils.createUniqueTestFile(project, "word1 word2\nword3 word2"); - var textViewer = TestUtils.openTextViewer(testFile); - DisplayHelper.sleep(textViewer.getTextWidget().getDisplay(), 2_000); // Give some time to the editor to update - MockLanguageServer.INSTANCE.getTextDocumentService().setMockReferences( - new Location(testFile.getLocationURI().toString(), new Range(new Position(0, 6), new Position(0, 11))), - new Location(testFile.getLocationURI().toString(), new Range(new Position(1, 6), new Position(1, 11)))); } @AfterEach @@ -88,7 +81,14 @@ public void tearDown() { } @Test - public void testFindReferences() throws Exception { + public void testFindReferences(MockLanguageServerFactory factory) throws Exception { + final var testFile = TestUtils.createUniqueTestFile(project, "word1 word2\nword3 word2"); + var textViewer = TestUtils.openTextViewer(testFile); + DisplayHelper.sleep(textViewer.getTextWidget().getDisplay(), 2_000); // Give some time to the editor to update + factory.getServer().getTextDocumentService().setMockReferences( + new Location(testFile.getLocationURI().toString(), new Range(new Position(0, 6), new Position(0, 11))), + new Location(testFile.getLocationURI().toString(), new Range(new Position(1, 6), new Position(1, 11)))); + final var handler = new LSFindReferences(); final var evaluationService = PlatformUI.getWorkbench().getService(IEvaluationService.class); final var searchResultListener = registerSearchResultListener(); @@ -98,7 +98,15 @@ public void testFindReferences() throws Exception { } @Test - public void testFindReferencesIsNonBlocking() throws Exception { + public void testFindReferencesIsNonBlocking(MockLanguageServerFactory factory) throws Exception { + final var testFile = TestUtils.createUniqueTestFile(project, "word1 word2\nword3 word2"); + var textViewer = TestUtils.openTextViewer(testFile); + DisplayHelper.sleep(textViewer.getTextWidget().getDisplay(), 2_000); // Give some time to the editor to update + factory.getServer().getTextDocumentService().setMockReferences( + new Location(testFile.getLocationURI().toString(), new Range(new Position(0, 6), new Position(0, 11))), + new Location(testFile.getLocationURI().toString(), new Range(new Position(1, 6), new Position(1, 11)))); + + final int uiFreezeThreshold = 300; final int findReferencesFakeDuration = uiFreezeThreshold * 5; @@ -107,7 +115,7 @@ public void testFindReferencesIsNonBlocking() throws Exception { waitForAndAssertCondition("UiFreezeEventLogger.INSTANCE is null", 2_000, () -> UiFreezeEventLogger.INSTANCE != null); - MockLanguageServer.INSTANCE.setTimeToProceedQueries(findReferencesFakeDuration); + factory.getServer().setTimeToProceedQueries(findReferencesFakeDuration); try { final var handler = new LSFindReferences(); final var evaluationService = PlatformUI.getWorkbench().getService(IEvaluationService.class); @@ -124,7 +132,7 @@ public void testFindReferencesIsNonBlocking() throws Exception { waitForAndAssertSearchResult(searchResultListener, findReferencesFakeDuration, findReferencesFakeDuration + 1_000); } finally { - MockLanguageServer.INSTANCE.setTimeToProceedQueries(0); + factory.getServer().setTimeToProceedQueries(0); uiFreezeMonitor.shutdown(); } diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/rename/LSPInlineRenameLinkedModeTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/rename/LSPInlineRenameLinkedModeTest.java index ebe2f42f2..2d15e4efd 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/rename/LSPInlineRenameLinkedModeTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/rename/LSPInlineRenameLinkedModeTest.java @@ -12,7 +12,8 @@ package org.eclipse.lsp4e.test.rename; import static org.eclipse.lsp4e.test.utils.TestUtils.waitForAndAssertCondition; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import java.lang.reflect.Method; import java.util.HashMap; @@ -31,7 +32,7 @@ import org.eclipse.lsp4e.operations.rename.LSPInlineRenameLinkedMode; import org.eclipse.lsp4e.test.utils.AbstractTestWithProject; import org.eclipse.lsp4e.test.utils.TestUtils; -import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4j.DocumentHighlight; import org.eclipse.lsp4j.DocumentHighlightKind; import org.eclipse.lsp4j.Position; @@ -69,7 +70,7 @@ class LSPInlineRenameLinkedModeTest extends AbstractTestWithProject { *

*/ @Test - void testInlineLinkedEditingSameFile() throws Exception { + void testInlineLinkedEditingSameFile(MockLanguageServerFactory factory) throws Exception { // Ensure inline rename is enabled for this test InstanceScope.INSTANCE.getNode(LanguageServerPlugin.PLUGIN_ID).putBoolean("org.eclipse.lsp4e.inlineRename", //$NON-NLS-1$ true); @@ -97,7 +98,9 @@ void testInlineLinkedEditingSameFile() throws Exception { DocumentHighlightKind.Read), new DocumentHighlight(new Range(new Position(0, 0), new Position(0, idLength)), DocumentHighlightKind.Text))); - MockLanguageServer.INSTANCE.setDocumentHighlights(highlights); + factory.withConfiguration((idx, server)-> { + server.setDocumentHighlights(highlights); + }); // Call the internal helper directly via reflection to avoid depending on // UI/command wiring @@ -128,7 +131,7 @@ void testInlineLinkedEditingSameFile() throws Exception { *

*/ @Test - void testInlineRenameEndToEndSameFile() throws Exception { + void testInlineRenameEndToEndSameFile(MockLanguageServerFactory factory) throws Exception { // Prepare a simple document with two occurrences of the same identifier var content = "compute();\ncompute();"; IFile file = TestUtils.createUniqueTestFile(project, content); @@ -147,7 +150,6 @@ void testInlineRenameEndToEndSameFile() throws Exception { Position secondPos = LSPEclipseUtils.toPosition(secondOffset, document); var prepareRange = new Range(firstPos, new Position(firstPos.getLine(), firstPos.getCharacter() + idLength)); - MockLanguageServer.INSTANCE.getTextDocumentService().setPrepareRenameResult(Either.forLeft(prepareRange)); // WorkspaceEdit returned by textDocument/rename: both occurrences updated to // typedName. @@ -162,7 +164,10 @@ void testInlineRenameEndToEndSameFile() throws Exception { new TextEdit( new Range(secondPos, new Position(secondPos.getLine(), secondPos.getCharacter() + idLength)), typedName))); - MockLanguageServer.INSTANCE.getTextDocumentService().setRenameEdit(new WorkspaceEdit(edits)); + factory.withConfiguration((idx, server)-> { + server.getTextDocumentService().setPrepareRenameResult(Either.forLeft(prepareRange)); + server.getTextDocumentService().setRenameEdit(new WorkspaceEdit(edits)); + }); // Open a viewer so that the document is wired to a text viewer like in real // usage diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/rename/RenameTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/rename/RenameTest.java index 50bbff04c..7091c2d05 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/rename/RenameTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/rename/RenameTest.java @@ -46,7 +46,7 @@ import org.eclipse.lsp4e.operations.rename.LSPRenameProcessor; import org.eclipse.lsp4e.test.utils.AbstractTestWithProject; import org.eclipse.lsp4e.test.utils.TestUtils; -import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.Range; import org.eclipse.lsp4j.TextEdit; @@ -84,35 +84,34 @@ public void testRenameHandlerEnablement() throws Exception { } @Test - public void testAsyncRenameHandlerEnablement() throws Exception { + public void testAsyncRenameHandlerEnablement(MockLanguageServerFactory factory) throws Exception { final int delay = 4_000; // this fixed value is not really an optimal solution, since it depends on the following things // to happen within that time frame. Should maybe re-work this in the future towards a more // precise way of steering the execution from the test here - MockLanguageServer.INSTANCE.setTimeToProceedQueries(delay); + factory.withConfiguration((idx, server)-> { + server.setTimeToProceedQueries(delay); + }); - try { - IFile file = TestUtils.createUniqueTestFile(project, "old"); - final var editor = (ITextEditor) TestUtils.openEditor(file); + IFile file = TestUtils.createUniqueTestFile(project, "old"); + final var editor = (ITextEditor) TestUtils.openEditor(file); - ICommandService commandService = PlatformUI.getWorkbench().getService(ICommandService.class); - Command command = commandService.getCommand(IWorkbenchCommandConstants.FILE_RENAME); - assertFalse(command.isEnabled()); + ICommandService commandService = PlatformUI.getWorkbench().getService(ICommandService.class); + Command command = commandService.getCommand(IWorkbenchCommandConstants.FILE_RENAME); + assertFalse(command.isEnabled()); - editor.selectAndReveal(1, 0); + editor.selectAndReveal(1, 0); - waitForAndAssertCondition(2 * delay, command::isEnabled); - assertTrue(command.isHandled()); - } finally { - // Put back so shutdown doesn't time out - MockLanguageServer.INSTANCE.setTimeToProceedQueries(0); - } + waitForAndAssertCondition(2 * delay, command::isEnabled); + assertTrue(command.isHandled()); } @Test - public void testRenameRefactoring() throws Exception { + public void testRenameRefactoring(MockLanguageServerFactory factory) throws Exception { IFile file = TestUtils.createUniqueTestFile(project, "old"); - MockLanguageServer.INSTANCE.getTextDocumentService().setRenameEdit(createSimpleMockRenameEdit(LSPEclipseUtils.toUri(file))); + factory.withConfiguration((idx, server)-> { + server.getTextDocumentService().setRenameEdit(createSimpleMockRenameEdit(LSPEclipseUtils.toUri(file))); + }); IDocument document = LSPEclipseUtils.getDocument(file); assertNotNull(document); final var processor = new LSPRenameProcessor(document, 0); @@ -128,9 +127,11 @@ public void testRenameRefactoring() throws Exception { } @Test - public void testPrepareRenameRefactoring() throws Exception { + public void testPrepareRenameRefactoring(MockLanguageServerFactory factory) throws Exception { IFile file = TestUtils.createUniqueTestFile(project, "old"); - MockLanguageServer.INSTANCE.getTextDocumentService().setRenameEdit(createSimpleMockRenameEdit(LSPEclipseUtils.toUri(file))); + factory.withConfiguration((idx, server)-> { + server.getTextDocumentService().setRenameEdit(createSimpleMockRenameEdit(LSPEclipseUtils.toUri(file))); + }); IDocument document = LSPEclipseUtils.getDocument(file); assertNotNull(document); final var processor = new LSPRenameProcessor(document, 0); @@ -146,10 +147,12 @@ public void testPrepareRenameRefactoring() throws Exception { } @Test - public void testPrepareRenameRefactoringError() throws Exception { + public void testPrepareRenameRefactoringError(MockLanguageServerFactory factory) throws Exception { IFile file = TestUtils.createUniqueTestFile(project, "old"); - MockLanguageServer.INSTANCE.getTextDocumentService().setRenameEdit(createSimpleMockRenameEdit(LSPEclipseUtils.toUri(file))); - MockLanguageServer.INSTANCE.getTextDocumentService().setPrepareRenameResult(null); + factory.withConfiguration((idx, server)-> { + server.getTextDocumentService().setRenameEdit(createSimpleMockRenameEdit(LSPEclipseUtils.toUri(file))); + server.getTextDocumentService().setPrepareRenameResult(null); + }); IDocument document = LSPEclipseUtils.getDocument(file); assertNotNull(document); final var processor = new LSPRenameProcessor(document, 0); @@ -165,10 +168,11 @@ public void testPrepareRenameRefactoringError() throws Exception { } @Test - public void testRenameRefactoringExternalFile(@TempDir Path tempDir) throws Exception { + public void testRenameRefactoringExternalFile(@TempDir Path tempDir, MockLanguageServerFactory factory) throws Exception { Path file = Files.createFile(tempDir.resolve("testPerformOperationExternalFile.lspt")); - - MockLanguageServer.INSTANCE.getTextDocumentService().setRenameEdit(createSimpleMockRenameEdit(file.toUri())); + factory.withConfiguration((idx, server)-> { + server.getTextDocumentService().setRenameEdit(createSimpleMockRenameEdit(file.toUri())); + }); IFileStore store = EFS.getStore(file.toUri()); ITextFileBufferManager manager = ITextFileBufferManager.DEFAULT; try { @@ -191,14 +195,16 @@ public void testRenameRefactoringExternalFile(@TempDir Path tempDir) throws Exce } @Test - public void testRenameChangeAlsoExternalFile(@TempDir Path tempDir) throws Exception { + public void testRenameChangeAlsoExternalFile(@TempDir Path tempDir, MockLanguageServerFactory factory) throws Exception { IFile workspaceFile = TestUtils.createUniqueTestFile(project, "old"); Path externalFile = Files.writeString(tempDir.resolve("testRenameChangeAlsoExternalFile.lspt"), "old"); final var edits = new HashMap>(2, 1.f); edits.put(LSPEclipseUtils.toUri(workspaceFile).toString(), List.of(new TextEdit(new Range(new Position(0, 0), new Position(0, 3)), "new"))); edits.put(LSPEclipseUtils.toUri(externalFile.toFile()).toString(), List.of(new TextEdit(new Range(new Position(0, 0), new Position(0, 3)), "new"))); - MockLanguageServer.INSTANCE.getTextDocumentService().setRenameEdit(new WorkspaceEdit(edits)); + factory.withConfiguration((idx, server)-> { + server.getTextDocumentService().setRenameEdit(new WorkspaceEdit(edits)); + }); IDocument document = LSPEclipseUtils.getDocument(workspaceFile); assertNotNull(document); final var processor = new LSPRenameProcessor(document, 0); @@ -215,12 +221,14 @@ public void testRenameChangeAlsoExternalFile(@TempDir Path tempDir) throws Excep } @Test - public void testRenameHandlerExecution() throws Exception { + public void testRenameHandlerExecution(MockLanguageServerFactory factory) throws Exception { // This test expects the classic dialog-based rename, so disable inline mode InstanceScope.INSTANCE.getNode(LanguageServerPlugin.PLUGIN_ID) .putBoolean("org.eclipse.lsp4e.inlineRename", false); //$NON-NLS-1$ IFile file = TestUtils.createUniqueTestFile(project, "old"); - MockLanguageServer.INSTANCE.getTextDocumentService().setRenameEdit(createSimpleMockRenameEdit(LSPEclipseUtils.toUri(file))); + factory.withConfiguration((idx, server)-> { + server.getTextDocumentService().setRenameEdit(createSimpleMockRenameEdit(LSPEclipseUtils.toUri(file))); + }); final var editor = (ITextEditor) TestUtils.openEditor(file); editor.selectAndReveal(1, 0); ICommandService commandService = PlatformUI.getWorkbench().getService(ICommandService.class); @@ -259,9 +267,11 @@ public void testRenameHandlerExecution() throws Exception { } @Test - public void testPlaceholderUsingPlaceholderFromPrepareRenameResult() throws Exception { + public void testPlaceholderUsingPlaceholderFromPrepareRenameResult(MockLanguageServerFactory factory) throws Exception { IFile file = TestUtils.createUniqueTestFile(project, "old"); - MockLanguageServer.INSTANCE.getTextDocumentService().setRenameEdit(createSimpleMockRenameEdit(LSPEclipseUtils.toUri(file))); + factory.withConfiguration((idx, server)-> { + server.getTextDocumentService().setRenameEdit(createSimpleMockRenameEdit(LSPEclipseUtils.toUri(file))); + }); IDocument document = LSPEclipseUtils.getDocument(file); assertNotNull(document); final var processor = new LSPRenameProcessor(document, 0); @@ -275,11 +285,13 @@ public void testPlaceholderUsingPlaceholderFromPrepareRenameResult() throws Exce } @Test - public void testPlaceholderUsingRangeFromPrepareRenameResult() throws Exception { + public void testPlaceholderUsingRangeFromPrepareRenameResult(MockLanguageServerFactory factory) throws Exception { IFile file = TestUtils.createUniqueTestFile(project, "old"); - MockLanguageServer.INSTANCE.getTextDocumentService().setRenameEdit(createSimpleMockRenameEdit(LSPEclipseUtils.toUri(file))); - final var range = new Range(new Position(0, 1), new Position(0, 3)); // Two last letters of "old". - MockLanguageServer.INSTANCE.getTextDocumentService().setPrepareRenameResult(Either.forLeft(range)); + factory.withConfiguration((idx, server)-> { + server.getTextDocumentService().setRenameEdit(createSimpleMockRenameEdit(LSPEclipseUtils.toUri(file))); + final var range = new Range(new Position(0, 1), new Position(0, 3)); // Two last letters of "old". + server.getTextDocumentService().setPrepareRenameResult(Either.forLeft(range)); + }); IDocument document = LSPEclipseUtils.getDocument(file); assertNotNull(document); final var processor = new LSPRenameProcessor(document, 0); diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/semanticTokens/SemanticHighlightReconcilerStrategyTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/semanticTokens/SemanticHighlightReconcilerStrategyTest.java index a575f576a..51b656fe4 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/semanticTokens/SemanticHighlightReconcilerStrategyTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/semanticTokens/SemanticHighlightReconcilerStrategyTest.java @@ -18,7 +18,7 @@ import org.eclipse.jface.text.ITextViewer; import org.eclipse.lsp4e.test.utils.AbstractTestWithProject; import org.eclipse.lsp4e.test.utils.TestUtils; -import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4j.SemanticTokens; import org.eclipse.swt.custom.StyleRange; import org.eclipse.swt.widgets.Display; @@ -34,19 +34,20 @@ public class SemanticHighlightReconcilerStrategyTest extends AbstractTestWithPro @BeforeEach public void setUp() { shell = new Shell(); - - // Setup Server Capabilities - List tokenTypes = List.of("keyword"); - List tokenModifiers = List.of("obsolete"); - SemanticTokensTestUtil.setSemanticTokensLegend(tokenTypes, tokenModifiers); } @Test - public void testKeyword() throws CoreException { + public void testKeyword(MockLanguageServerFactory factory) throws CoreException { + List tokenTypes = List.of("keyword"); + List tokenModifiers = List.of("obsolete"); + SemanticTokensTestUtil.setSemanticTokensLegend(tokenTypes, tokenModifiers, factory); + final var semanticTokens = new SemanticTokens(); semanticTokens.setData(SemanticTokensTestUtil.keywordSemanticTokens()); - MockLanguageServer.INSTANCE.getTextDocumentService().setSemanticTokens(semanticTokens); + factory.withConfiguration((idx, server) -> { + server.getTextDocumentService().setSemanticTokens(semanticTokens); + }); IFile file = TestUtils.createUniqueTestFile(project, "lsptm", SemanticTokensTestUtil.keywordText); ITextViewer textViewer = TestUtils.openTextViewer(file); diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/semanticTokens/SemanticTokensDataStreamProcessorTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/semanticTokens/SemanticTokensDataStreamProcessorTest.java index 784983e13..0a9e13ca9 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/semanticTokens/SemanticTokensDataStreamProcessorTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/semanticTokens/SemanticTokensDataStreamProcessorTest.java @@ -14,12 +14,11 @@ import org.eclipse.jface.text.Document; import org.eclipse.lsp4e.operations.semanticTokens.SemanticTokensDataStreamProcessor; -import org.eclipse.lsp4e.test.utils.AbstractTest; import org.eclipse.lsp4j.SemanticTokensLegend; import org.eclipse.swt.custom.StyleRange; import org.junit.jupiter.api.Test; -public class SemanticTokensDataStreamProcessorTest extends AbstractTest { +public class SemanticTokensDataStreamProcessorTest { @Test public void testKeyword() { diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/semanticTokens/SemanticTokensLegendProviderTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/semanticTokens/SemanticTokensLegendProviderTest.java index 307cc964b..ad211ebe1 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/semanticTokens/SemanticTokensLegendProviderTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/semanticTokens/SemanticTokensLegendProviderTest.java @@ -20,16 +20,17 @@ import org.eclipse.lsp4e.operations.semanticTokens.SemanticTokensClient; import org.eclipse.lsp4e.test.utils.AbstractTestWithProject; import org.eclipse.lsp4e.test.utils.TestUtils; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.junit.jupiter.api.Test; public class SemanticTokensLegendProviderTest extends AbstractTestWithProject { @Test - public void testSemanticTokensLegendProvider() throws CoreException { + public void testSemanticTokensLegendProvider(MockLanguageServerFactory factory) throws CoreException { // Setup Server Capabilities List tokenTypes = List.of("keyword","other"); List tokenModifiers = List.of("obsolete"); - SemanticTokensTestUtil.setSemanticTokensLegend(tokenTypes, tokenModifiers); + SemanticTokensTestUtil.setSemanticTokensLegend(tokenTypes, tokenModifiers, factory); // Setup test data IFile file = TestUtils.createUniqueTestFile(project, "lspt", "test content"); diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/semanticTokens/SemanticTokensTestUtil.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/semanticTokens/SemanticTokensTestUtil.java index db7f41907..4195efd72 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/semanticTokens/SemanticTokensTestUtil.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/semanticTokens/SemanticTokensTestUtil.java @@ -19,9 +19,11 @@ import org.eclipse.jface.text.rules.IToken; import org.eclipse.lsp4e.LSPEclipseUtils; import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.SemanticTokensLegend; import org.eclipse.lsp4j.SemanticTokensWithRegistrationOptions; +import org.eclipse.lsp4j.ServerCapabilities; import org.eclipse.swt.graphics.Color; public class SemanticTokensTestUtil { @@ -112,12 +114,16 @@ public static Function keywordTokenTypeMapper(final IToken token } }; } - public static void setSemanticTokensLegend(final List tokenTypes, List tokenModifiers) { - final var legend = new SemanticTokensLegend(tokenTypes, tokenModifiers); - final var semanticTokensWithRegistrationOptions = new SemanticTokensWithRegistrationOptions(legend); - semanticTokensWithRegistrationOptions.setFull(true); - semanticTokensWithRegistrationOptions.setRange(false); - - MockLanguageServer.INSTANCE.getInitializeResult().getCapabilities().setSemanticTokensProvider(semanticTokensWithRegistrationOptions); + public static void setSemanticTokensLegend(final List tokenTypes, List tokenModifiers, MockLanguageServerFactory factory) { + factory.withCapabilities(() -> { + final var legend = new SemanticTokensLegend(tokenTypes, tokenModifiers); + final var semanticTokensWithRegistrationOptions = new SemanticTokensWithRegistrationOptions(legend); + semanticTokensWithRegistrationOptions.setFull(true); + semanticTokensWithRegistrationOptions.setRange(false); + + ServerCapabilities capabilities = MockLanguageServer.defaultServerCapabilities(); + capabilities.setSemanticTokensProvider(semanticTokensWithRegistrationOptions); + return capabilities; + }); } } diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/semanticTokens/StyleRangeHolderTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/semanticTokens/StyleRangeHolderTest.java index d0a02e11b..dd76906e4 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/semanticTokens/StyleRangeHolderTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/semanticTokens/StyleRangeHolderTest.java @@ -17,12 +17,11 @@ import org.eclipse.jface.text.Region; import org.eclipse.jface.text.TextEvent; import org.eclipse.lsp4e.operations.semanticTokens.StyleRangeHolder; -import org.eclipse.lsp4e.test.utils.AbstractTest; import org.eclipse.swt.custom.StyleRange; import org.eclipse.swt.graphics.Color; import org.junit.jupiter.api.Test; -public class StyleRangeHolderTest extends AbstractTest { +public class StyleRangeHolderTest { private static final Color RED = new Color(255, 0, 0); private List originalStyleRanges = List.of(new StyleRange(0, 4, RED, null), new StyleRange(15, 4, RED, null), new StyleRange(24, 7, RED, null)); diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/semanticTokens/StyleRangeMergerTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/semanticTokens/StyleRangeMergerTest.java index cfcbaf190..40b0fe0da 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/semanticTokens/StyleRangeMergerTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/semanticTokens/StyleRangeMergerTest.java @@ -20,13 +20,12 @@ import org.eclipse.jface.text.TextPresentation; import org.eclipse.lsp4e.operations.semanticTokens.StyleRangeHolder; import org.eclipse.lsp4e.operations.semanticTokens.StyleRangeMerger; -import org.eclipse.lsp4e.test.utils.AbstractTest; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.StyleRange; import org.eclipse.swt.graphics.Color; import org.junit.jupiter.api.Test; -public class StyleRangeMergerTest extends AbstractTest { +public class StyleRangeMergerTest { @Test public void testSemanticHighlightMergesWithExistingStyleRanges() { diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/symbols/SymbolsModelTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/symbols/SymbolsModelTest.java index dec6d64db..091e1d8d0 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/symbols/SymbolsModelTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/symbols/SymbolsModelTest.java @@ -22,7 +22,6 @@ import java.util.List; import org.eclipse.lsp4e.outline.SymbolsModel; -import org.eclipse.lsp4e.test.utils.AbstractTest; import org.eclipse.lsp4j.DocumentSymbol; import org.eclipse.lsp4j.Location; import org.eclipse.lsp4j.Position; @@ -32,7 +31,7 @@ import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.junit.jupiter.api.Test; -public class SymbolsModelTest extends AbstractTest { +public class SymbolsModelTest { private final SymbolsModel symbolsModel = new SymbolsModel(); diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/utils/AbstractTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/utils/AbstractTest.java deleted file mode 100644 index 7adbb8feb..000000000 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/utils/AbstractTest.java +++ /dev/null @@ -1,32 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2024 Vegard IT GmbH and others. - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Sebastian Thomschke (Vegard IT GmbH) - initial implementation - *******************************************************************************/ -package org.eclipse.lsp4e.test.utils; - -import org.eclipse.lsp4e.tests.mock.MockLanguageServer; -import org.eclipse.lsp4j.ServerCapabilities; -import org.junit.jupiter.api.extension.RegisterExtension; - -/** - * Test base class that configures a {@link AllCleanExtension}. - */ -public abstract class AbstractTest { - - @RegisterExtension - public final AllCleanExtension allCleanRule = new AllCleanExtension(this::getServerCapabilities); - - /** - * Override if required, used by {@link #allCleanRule} - */ - protected ServerCapabilities getServerCapabilities() { - return MockLanguageServer.defaultServerCapabilities(); - } -} diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/utils/AbstractTestWithProject.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/utils/AbstractTestWithProject.java index 316e8271d..4e9567151 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/utils/AbstractTestWithProject.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/utils/AbstractTestWithProject.java @@ -14,16 +14,13 @@ import java.lang.reflect.Method; import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.runtime.CoreException; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.TestInfo; /** * Test base class that provides a new unique temporary test project for each @org.junit.Test run */ -public abstract class AbstractTestWithProject extends AbstractTest { +public abstract class AbstractTestWithProject { protected IProject project; @BeforeEach @@ -34,40 +31,4 @@ public void setUpProject(TestInfo testInfo) throws Exception { project = TestUtils.createProject(projectName); } - @AfterEach - public void tearDownProject() throws Exception { - if (project != null && project.exists()) { - deleteProjectWithRetries(project, 10, 500); - } - } - - /** - * Mitigation for potential - * java.nio.file.FileSystemException: The process cannot access the file because it is being used by another process - * when deleting a project. - */ - private static void deleteProjectWithRetries(IProject project, int maxAttempts, long delayMillis) - throws CoreException { - for (int attempt = 1; attempt <= maxAttempts; attempt++) { - try { - if (!project.exists()) { - break; - } - project.close(null); - project.delete(IResource.FORCE | IResource.ALWAYS_DELETE_PROJECT_CONTENT, null); - break; - } catch (CoreException ex) { - if (attempt == maxAttempts) { - throw ex; - } - try { - Thread.sleep(delayMillis); - } catch (InterruptedException ie) { - Thread.currentThread().interrupt(); - ex.printStackTrace(); - break; - } - } - } - } } diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/utils/AllCleanExtension.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/utils/AllCleanExtension.java deleted file mode 100644 index c9949b800..000000000 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/utils/AllCleanExtension.java +++ /dev/null @@ -1,70 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2019 Red Hat Inc. and others. - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Mickael Istria (Red Hat Inc.) - initial implementation - *******************************************************************************/ -package org.eclipse.lsp4e.test.utils; - -import java.util.function.Supplier; - -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.lsp4e.ConnectDocumentToLanguageServerSetupParticipant; -import org.eclipse.lsp4e.LanguageServiceAccessor; -import org.eclipse.lsp4e.tests.mock.MockConnectionProvider; -import org.eclipse.lsp4e.tests.mock.MockLanguageServer; -import org.eclipse.lsp4e.ui.UI; -import org.eclipse.lsp4j.ServerCapabilities; -import org.junit.jupiter.api.extension.AfterEachCallback; -import org.junit.jupiter.api.extension.BeforeEachCallback; -import org.junit.jupiter.api.extension.ExtensionContext; - -public class AllCleanExtension implements BeforeEachCallback, AfterEachCallback { - - private final Supplier serverConfigurer; - - public AllCleanExtension() { - this.serverConfigurer = MockLanguageServer::defaultServerCapabilities; - } - - public AllCleanExtension(final Supplier serverConfigurer) { - this.serverConfigurer = serverConfigurer; - } - - @Override - public void beforeEach(ExtensionContext context) throws Exception { - clear(); - } - - @Override - public void afterEach(ExtensionContext context) throws Exception { - clear(); - } - - private void clear() { - MockLanguageServer.INSTANCE.setTimeToProceedQueries(0); - // Give the platform three attempts to shut down windows - for (int i = 3; i > 0 && !UI.getActivePage().closeAllEditors(false); i--) {} - ConnectDocumentToLanguageServerSetupParticipant.waitForAll(); - for (IProject project : ResourcesPlugin.getWorkspace().getRoot().getProjects()) { - try { - project.delete(IResource.FORCE, null); - } catch (CoreException e) { - e.printStackTrace(); - } - } - MockLanguageServer.INSTANCE.waitBeforeTearDown(); - LanguageServiceAccessor.clearStartedServers(); - MockLanguageServer.reset(this.serverConfigurer); - MockConnectionProvider.cancellations.clear(); - } - -} diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/utils/MockLanguageServerExtension.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/utils/MockLanguageServerExtension.java new file mode 100644 index 000000000..68b1b2db5 --- /dev/null +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/utils/MockLanguageServerExtension.java @@ -0,0 +1,125 @@ +/******************************************************************************* + * Copyright (c) 2026 Contributors to the Eclipse Foundation. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * See git history + *******************************************************************************/ +package org.eclipse.lsp4e.test.utils; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.lsp4e.ConnectDocumentToLanguageServerSetupParticipant; +import org.eclipse.lsp4e.LanguageServiceAccessor; +import org.eclipse.lsp4e.tests.mock.MockConnectionProvider; +import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockLanguageServerFactory; +import org.eclipse.lsp4e.ui.UI; +import org.junit.jupiter.api.extension.AfterEachCallback; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ExtensionContext.Namespace; +import org.junit.jupiter.api.extension.ParameterContext; +import org.junit.jupiter.api.extension.ParameterResolutionException; +import org.junit.jupiter.api.extension.ParameterResolver; + +/** + * Allows test cases to define a parameter of type + * {@link MockLanguageServerFactory}, which they can use to tailor the behavior + * of all {@link MockLanguageServer} launched during the execution of the test + * case. + * + * This extension also cleans up thoroughly after each test execution, e.g., + * deleting all projects, clearing all Language Servers, etc. + */ +public class MockLanguageServerExtension implements ParameterResolver, AfterEachCallback { + + private static final String KEY = "factory"; + + private static final Namespace NAMESPACE = Namespace.create(MockLanguageServerExtension.class); + + @Override + public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) + throws ParameterResolutionException { + return parameterContext.getParameter().getType().equals(MockLanguageServerFactory.class); + } + + @Override + public @Nullable Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) + throws ParameterResolutionException { + // Store it, just in case. + MockLanguageServerFactory factory = extensionContext.getStore(NAMESPACE).computeIfAbsent(KEY, __ -> { + return new MockLanguageServerFactory(); + }, MockLanguageServerFactory.class); + MockConnectionProvider.factory = factory; + + return factory; + } + + @Override + public void afterEach(ExtensionContext context) throws Exception { + MockLanguageServerFactory factory = MockConnectionProvider.factory; + for (MockLanguageServer server : factory.getServers()) { + // Reset delay to zero, otherwise servers will be slow to respond to shutdown + // request. + server.setTimeToProceedQueries(0); + // Wait for all in-flight requests to finish. + server.waitBeforeTearDown(); + } + + // Make sure there are no pending document setups + ConnectDocumentToLanguageServerSetupParticipant.waitForAll(); + + // Give the platform three attempts to close all editors + for (int i = 3; i > 0 && !UI.getActivePage().closeAllEditors(false); i--) { + } + + // Now delete all projects + for (IProject project : ResourcesPlugin.getWorkspace().getRoot().getProjects()) { + deleteProjectWithRetries(project, 10, 500); + } + + // Cleanup any started servers + LanguageServiceAccessor.clearStartedServers(); + + // Restore factory + MockConnectionProvider.factory = new MockLanguageServerFactory(); + } + + /** + * Mitigation for potential + * java.nio.file.FileSystemException: The process cannot access the file because it is being used by another process + * when deleting a project. + */ + private static void deleteProjectWithRetries(IProject project, int maxAttempts, long delayMillis) + throws CoreException { + for (int attempt = 1; attempt <= maxAttempts; attempt++) { + try { + if (!project.exists()) { + break; + } + project.close(null); + project.delete(IResource.FORCE | IResource.ALWAYS_DELETE_PROJECT_CONTENT, null); + break; + } catch (CoreException ex) { + if (attempt == maxAttempts) { + throw ex; + } + try { + Thread.sleep(delayMillis); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + ex.printStackTrace(); + break; + } + } + } + } + +} diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/utils/TestUtils.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/utils/TestUtils.java index 52aad56b1..a13713a93 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/utils/TestUtils.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/utils/TestUtils.java @@ -12,6 +12,7 @@ *******************************************************************************/ package org.eclipse.lsp4e.test.utils; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.ByteArrayInputStream; @@ -40,6 +41,7 @@ import org.eclipse.lsp4e.LanguageServersRegistry; import org.eclipse.lsp4e.internal.ArrayUtil; import org.eclipse.lsp4e.tests.mock.MockLanguageServer; +import org.eclipse.lsp4e.tests.mock.MockServerState; import org.eclipse.lsp4e.ui.UI; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; @@ -366,7 +368,7 @@ public void waitForLanguageServerNotRunning(MockLanguageServer server) { assertTrue(new DisplayHelper() { @Override protected boolean condition() { - return !server.isRunning(); + return server.getState() != MockServerState.RUNNING; } }.waitForCondition(UI.getDisplay(), 1000)); } @@ -397,7 +399,10 @@ public void worked(int work) { } } - public static Condition numberOfChangesIs(int changes) { - return () -> MockLanguageServer.INSTANCE.getDidChangeEvents().size() == changes; + public static Condition numberOfChangesIs(int changes, MockLanguageServer server) { + return () -> { + assertEquals(changes, server.getDidChangeEvents().size()); + return true; + }; } } diff --git a/org.eclipse.lsp4e.tests.mock/src/org/eclipse/lsp4e/tests/mock/MockConnectionProvider.java b/org.eclipse.lsp4e.tests.mock/src/org/eclipse/lsp4e/tests/mock/MockConnectionProvider.java index 3af6452b4..3611e7f61 100644 --- a/org.eclipse.lsp4e.tests.mock/src/org/eclipse/lsp4e/tests/mock/MockConnectionProvider.java +++ b/org.eclipse.lsp4e.tests.mock/src/org/eclipse/lsp4e/tests/mock/MockConnectionProvider.java @@ -15,14 +15,19 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.lang.System.Logger; +import java.lang.System.Logger.Level; import java.net.URI; import java.nio.channels.Channels; import java.nio.channels.Pipe; import java.util.ArrayList; import java.util.Collection; +import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.function.Function; import org.eclipse.jdt.annotation.Nullable; @@ -41,22 +46,36 @@ public class MockConnectionProvider implements StreamConnectionProvider { private Future listener; private Collection streams = new ArrayList<>(4); - private static ExecutorService testRunner = Executors.newCachedThreadPool(); + private static final Logger LOGGER = System.getLogger(MockConnectionProvider.class.getSimpleName()); + + /** + * This field is used by the JUnit Extension to inject the correct factory for + * each test case. + */ + public static MockLanguageServerFactory factory = new MockLanguageServerFactory(); + + private static ExecutorService testRunner = Executors + .newCachedThreadPool(Thread.ofVirtual().name("MockLanguageServerListener-", 1).factory()); @Override public void start() throws IOException { + factory.connectionProviderStartCounter.incrementAndGet(); + Pipe serverOutputToClientInput = Pipe.open(); Pipe clientOutputToServerInput = Pipe.open(); errorStream = InputStream.nullInputStream(); InputStream serverInputStream = Channels.newInputStream(clientOutputToServerInput.source()); OutputStream serverOutputStream = Channels.newOutputStream(serverOutputToClientInput.sink()); - Launcher launcher = LSPLauncher.createServerLauncher(MockLanguageServer.INSTANCE, serverInputStream, + + var server = factory.create(serverOutputStream); + + Launcher launcher = LSPLauncher.createServerLauncher(server, serverInputStream, serverOutputStream, testRunner, Function.identity()); clientInputStream = Channels.newInputStream(serverOutputToClientInput.source()); clientOutputStream = Channels.newOutputStream(clientOutputToServerInput.sink()); listener = launcher.startListening(); - MockLanguageServer.INSTANCE.addRemoteProxy(launcher.getRemoteProxy()); + server.setRemoteProxy(launcher.getRemoteProxy()); // Store the output streams so we can close them to clean up. The corresponding input // streams should automatically receive an EOF and close. @@ -82,24 +101,29 @@ public InputStream getErrorStream() { @Override public void stop() { + factory.connectionProviderStopCounter.incrementAndGet(); + streams.forEach(t -> { try { t.close(); } catch (IOException e) { - e.printStackTrace(); + LOGGER.log(Level.ERROR, "Failed to close an outputstream of the MockLanguageServer", e); } }); streams.clear(); + try { + listener.get(5, TimeUnit.SECONDS); + } catch (InterruptedException | ExecutionException | TimeoutException e) { + LOGGER.log(Level.ERROR, "Failed to stop the listener of the MockLanguageServer", e); + } listener.cancel(true); listener = null; } - public static final Collection cancellations = new ArrayList<>(); - @Override public void handleMessage(Message message, LanguageServer languageServer, @Nullable URI rootURI) { if (message.toString().contains("cancelRequest")) { - cancellations.add(message); + factory.cancellations.add(message); } StreamConnectionProvider.super.handleMessage(message, languageServer, rootURI); } diff --git a/org.eclipse.lsp4e.tests.mock/src/org/eclipse/lsp4e/tests/mock/MockConnectionProviderMultiRootFolders.java b/org.eclipse.lsp4e.tests.mock/src/org/eclipse/lsp4e/tests/mock/MockConnectionProviderMultiRootFolders.java deleted file mode 100644 index de761649d..000000000 --- a/org.eclipse.lsp4e.tests.mock/src/org/eclipse/lsp4e/tests/mock/MockConnectionProviderMultiRootFolders.java +++ /dev/null @@ -1,120 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016, 2018 Rogue Wave Software Inc. and others. - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Michał Niewrzał (Rogue Wave Software Inc.) - initial implementation - * Martin Lippert (Pivotal Inc.) - Bug 531030 - fixed crash when initial project gets deleted in multi-root workspaces - *******************************************************************************/ -package org.eclipse.lsp4e.tests.mock; - -import java.io.Closeable; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.channels.Channels; -import java.nio.channels.Pipe; -import java.util.ArrayList; -import java.util.Collection; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Future; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.eclipse.lsp4e.server.StreamConnectionProvider; -import org.eclipse.lsp4j.jsonrpc.Launcher; -import org.eclipse.lsp4j.launch.LSPLauncher; -import org.eclipse.lsp4j.services.LanguageClient; - -import com.google.common.util.concurrent.ThreadFactoryBuilder; - -public class MockConnectionProviderMultiRootFolders implements StreamConnectionProvider { - private static final Logger LOG = Logger.getLogger(MockConnectionProviderMultiRootFolders.class.getName()); - - static ExecutorService sharedExecutor = new ThreadPoolExecutor(0, Runtime.getRuntime().availableProcessors(), 0, - TimeUnit.SECONDS, new LinkedBlockingQueue(), - new ThreadFactoryBuilder().setNameFormat("mock-connection-provider-%d").build()); - - static private AtomicInteger startCount = new AtomicInteger(0); - static private AtomicInteger stopCount = new AtomicInteger(0); - - static public void resetCounts() { - startCount.set(0); - stopCount.set(0); - } - - static public int getStartCount() { - return startCount.get(); - } - - static public int getStopCount() { - return stopCount.get(); - } - - private InputStream clientInputStream; - private OutputStream clientOutputStream; - private InputStream errorStream; - private Collection streams = new ArrayList<>(4); - private Future launcherFuture; - - @Override - public void start() throws IOException { - try { - Pipe serverOutputToClientInput = Pipe.open(); - Pipe clientOutputToServerInput = Pipe.open(); - errorStream = InputStream.nullInputStream(); - - InputStream serverInputStream = Channels.newInputStream(clientOutputToServerInput.source()); - OutputStream serverOutputStream = Channels.newOutputStream(serverOutputToClientInput.sink()); - - Launcher launcher = LSPLauncher.createServerLauncher( - MockLanguageServerMultiRootFolders.INSTANCE, serverInputStream, serverOutputStream, sharedExecutor, - (c) -> c); - - clientInputStream = Channels.newInputStream(serverOutputToClientInput.source()); - clientOutputStream = Channels.newOutputStream(clientOutputToServerInput.sink()); - launcherFuture = launcher.startListening(); - MockLanguageServer.INSTANCE.addRemoteProxy(launcher.getRemoteProxy()); - streams.add(clientInputStream); - streams.add(clientOutputStream); - streams.add(serverInputStream); - streams.add(serverOutputStream); - streams.add(errorStream); - - startCount.incrementAndGet(); - } catch (Exception x) { - LOG.log(Level.SEVERE, "MockConnectionProvider#start", x); - } - } - - @Override - public InputStream getInputStream() { - return clientInputStream; - } - - @Override - public OutputStream getOutputStream() { - return clientOutputStream; - } - - @Override - public InputStream getErrorStream() { - return errorStream; - } - - @Override - public void stop() { - stopCount.incrementAndGet(); - if (launcherFuture != null) { - launcherFuture.cancel(true); - } - } -} diff --git a/org.eclipse.lsp4e.tests.mock/src/org/eclipse/lsp4e/tests/mock/MockLanguageServer.java b/org.eclipse.lsp4e.tests.mock/src/org/eclipse/lsp4e/tests/mock/MockLanguageServer.java index 8fbc06f2a..b4c47a724 100644 --- a/org.eclipse.lsp4e.tests.mock/src/org/eclipse/lsp4e/tests/mock/MockLanguageServer.java +++ b/org.eclipse.lsp4e.tests.mock/src/org/eclipse/lsp4e/tests/mock/MockLanguageServer.java @@ -16,6 +16,10 @@ *******************************************************************************/ package org.eclipse.lsp4e.tests.mock; +import java.io.IOException; +import java.io.OutputStream; +import java.lang.System.Logger; +import java.lang.System.Logger.Level; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -29,6 +33,7 @@ import java.util.concurrent.Executor; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; import org.eclipse.lsp4j.CodeAction; @@ -69,6 +74,8 @@ import org.eclipse.lsp4j.TextDocumentSyncOptions; import org.eclipse.lsp4j.TextEdit; import org.eclipse.lsp4j.TypeHierarchyRegistrationOptions; +import org.eclipse.lsp4j.WorkspaceFoldersOptions; +import org.eclipse.lsp4j.WorkspaceServerCapabilities; import org.eclipse.lsp4j.jsonrpc.Launcher; import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.eclipse.lsp4j.launch.LSPLauncher; @@ -84,30 +91,37 @@ public class MockLanguageServer implements LanguageServer { */ public static final String SUPPORTED_COMMAND_ID = "mock.command"; - public static MockLanguageServer INSTANCE = new MockLanguageServer(MockLanguageServer::defaultServerCapabilities); - private volatile MockTextDocumentService textDocumentService = new MockTextDocumentService( this::buildMaybeDelayedFuture); private final MockWorkspaceService workspaceService = new MockWorkspaceService(this::buildMaybeDelayedFuture); private final InitializeResult initializeResult = new InitializeResult(); private volatile long delay = 0; private volatile Executor delayedExecutor = null; - private volatile boolean started; + private AtomicReference state = new AtomicReference(MockServerState.RUNNING); - private final List remoteProxies = new CopyOnWriteArrayList<>(); + private static final Logger LOGGER = System.getLogger(MockLanguageServer.class.getSimpleName()); - private final List> inFlight = new CopyOnWriteArrayList<>(); + /** + * The MockLanguageServer was started as a separate process. + */ + private boolean launchedStandalone = false; - public static void reset() { - INSTANCE = new MockLanguageServer(MockLanguageServer::defaultServerCapabilities); - } + /** + * The remote proxy. This can be used to send requests to the client. + */ + private LanguageClient remoteProxy = null; - public static void reset(final Supplier serverConfigurer) { - INSTANCE = new MockLanguageServer(serverConfigurer); - } + private final List> inFlight = new CopyOnWriteArrayList<>(); + + /** + * Stream which this LS uses to send messages to the client. Closing this stream + * will terminate the connection on the client side. + */ + private OutputStream output; - protected MockLanguageServer(final Supplier serverConfigurer) { - resetInitializeResult(serverConfigurer); + public MockLanguageServer(Supplier supplier, OutputStream stdout) { + initializeResult.setCapabilities(supplier.get()); + this.output = stdout; } /** @@ -117,10 +131,11 @@ protected MockLanguageServer(final Supplier serverConfigurer * @throws InterruptedException */ public static void main(String[] args) throws InterruptedException, ExecutionException { - Launcher l = LSPLauncher.createServerLauncher(MockLanguageServer.INSTANCE, System.in, + MockLanguageServer server = new MockLanguageServer(MockLanguageServer::defaultServerCapabilities, System.out); + server.launchedStandalone = true; + Launcher l = LSPLauncher.createServerLauncher(server, System.in, System.out); Future f = l.startListening(); - MockLanguageServer.INSTANCE.addRemoteProxy(l.getRemoteProxy()); f.get(); } @@ -141,14 +156,9 @@ public void waitBeforeTearDown() { }); } - public void addRemoteProxy(LanguageClient remoteProxy) { - this.textDocumentService.addRemoteProxy(remoteProxy); - this.remoteProxies.add(remoteProxy); - this.started = true; - } - - private void resetInitializeResult(final Supplier serverConfigurer) { - initializeResult.setCapabilities(serverConfigurer.get()); + public void setRemoteProxy(LanguageClient remoteProxy) { + this.textDocumentService.setRemoteProxy(remoteProxy); + this.remoteProxy = remoteProxy; } public CompletableFuture buildMaybeDelayedFuture(U value) { @@ -161,6 +171,10 @@ public CompletableFuture buildMaybeDelayedFuture(U value) { return CompletableFuture.completedFuture(value); } + /** + * Supplier to get a default set of server capabilities. + * + */ public static ServerCapabilities defaultServerCapabilities() { final var capabilities = new ServerCapabilities(); capabilities.setTextDocumentSync(TextDocumentSyncKind.Full); @@ -190,6 +204,22 @@ public static ServerCapabilities defaultServerCapabilities() { return capabilities; } + /** + * Similar to {@link #defaultServerCapabilities()}, but with workspace support + * (multi root) enabled. + * + */ + public static ServerCapabilities multiRootCapabilities() { + var capabilities = defaultServerCapabilities(); + final var workspace = new WorkspaceServerCapabilities(); + final var workspaceFolders = new WorkspaceFoldersOptions(); + workspaceFolders.setSupported(Boolean.TRUE); + + workspace.setWorkspaceFolders(workspaceFolders); + capabilities.setWorkspace(workspace); + return capabilities; + } + @Override public CompletableFuture initialize(InitializeParams params) { @@ -290,12 +320,24 @@ public InitializeResult getInitializeResult() { @Override public CompletableFuture shutdown() { - this.started = false; + state.set(MockServerState.SHUTDOWN); return buildMaybeDelayedFuture(Collections.emptySet()); } @Override public void exit() { + state.set(MockServerState.EXIT); + try { + output.close(); + } catch (IOException e) { + LOGGER.log(Level.ERROR, "Failed to close outputstream of MockLanguageServer", e); + } + if (launchedStandalone) { + // If we are running as an external Process, we actually have to exit the + // process, because LaunchConfigurationStreamProvider/StreamProxyInputStream + // cannot check for EOF but only if the underlying process has exited. + System.exit(0); + } } public void setTimeToProceedQueries(final long delayInMS) { @@ -323,12 +365,12 @@ public void setTypeDefinitions(List locations) { this.textDocumentService.setMockTypeDefinitions(locations); } - public boolean isRunning() { - return this.started; - } - - public List getRemoteProxies() { - return remoteProxies; + /** + * Get access to the language client. This can be used to send + * requests/notifications from the server to the client. + */ + public LanguageClient getRemoteProxy() { + return remoteProxy; } public void setDocumentSymbols(DocumentSymbol documentSymbol) { @@ -368,9 +410,12 @@ public void setFoldingRanges(List foldingRanges) { this.textDocumentService.setFoldingRanges(foldingRanges); } + public MockServerState getState() { + return state.get(); + } + @Override public String toString() { - return "MockLanguageServer [started=" + started + ", delay=" + delay + ", remoteProxies=" + remoteProxies.size() - + ", inFlight=" + inFlight.size() + "]"; + return "MockLanguageServer [state=" + state.get() + ", delay=" + delay + ", inFlight=" + inFlight.size() + "]"; } } diff --git a/org.eclipse.lsp4e.tests.mock/src/org/eclipse/lsp4e/tests/mock/MockLanguageServerFactory.java b/org.eclipse.lsp4e.tests.mock/src/org/eclipse/lsp4e/tests/mock/MockLanguageServerFactory.java new file mode 100644 index 000000000..925f8e2af --- /dev/null +++ b/org.eclipse.lsp4e.tests.mock/src/org/eclipse/lsp4e/tests/mock/MockLanguageServerFactory.java @@ -0,0 +1,122 @@ +/******************************************************************************* + * Copyright (c) 2026 Contributors to the Eclipse Foundation. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * See git history + *******************************************************************************/ +package org.eclipse.lsp4e.tests.mock; + +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.BiConsumer; +import java.util.function.Supplier; + +import org.eclipse.lsp4j.ServerCapabilities; +import org.eclipse.lsp4j.jsonrpc.messages.Message; + +/** + * A factory which is used to create language server instances for test cases. + * The behavior of the LS can be tailored towards a specific test case. + */ +public class MockLanguageServerFactory { + + private BiConsumer configuration = (idx, server) -> { + }; + + private Supplier capabilities = MockLanguageServer::defaultServerCapabilities; + + private final List launchedServers = new CopyOnWriteArrayList<>(); + + /** + * The amount of launched servers + */ + private final AtomicInteger launchCounter = new AtomicInteger(); + + /** + * How often was start called on the MockConnectionProvider + */ + public final AtomicInteger connectionProviderStartCounter = new AtomicInteger(); + + /** + * How often was stop called on the MockConnectionProvider + */ + public final AtomicInteger connectionProviderStopCounter = new AtomicInteger(); + + /** + * The observed cancellation messages + */ + public final Collection cancellations = new ArrayList<>(); + + /** + * Pass a consumer which is called for each newly created LanguageServer. The + * first argument is the index of the currently configured server. This can be + * used to create languages servers which behave differently, based on this + * index. + * + * Note: If you need to change the behavior of a server after it was launched, + * you can retrieve it {@link #getServer()} or {@link #getServers()} and + * configure it appropriately. + */ + public void withConfiguration(BiConsumer configuration) { + this.configuration = configuration; + } + + /** + * Supply the capabilities that will be offered by each configured + * LanguageServer. + */ + public void withCapabilities(Supplier capabilities) { + this.capabilities = capabilities; + } + + /** + * Get the list of launched servers. + */ + public List getServers() { + return List.copyOf(launchedServers); + } + + /** + * Get the most recently launched server. + */ + public MockLanguageServer getServer() { + if (launchedServers.isEmpty()) { + throw new IllegalStateException(""" + No server was launched so far. + Retrieving the actual server only works after it was connected, e.g., a document was opened. + If you want to configure it beforehand, use #withConfiguration. + """); + } + return launchedServers.getLast(); + } + + /** + * Internal hook used by the MockConnectionProvider to create a Language Server. + */ + public MockLanguageServer create(OutputStream stdout) { + MockLanguageServer server = new MockLanguageServer(capabilities, stdout); + + int launchNum = launchCounter.getAndIncrement(); + configuration.accept(launchNum, server); + launchedServers.add(server); + + return server; + } + + /** + * The amount of launched servers. + */ + public int getServerCount() { + return launchCounter.get(); + } + +} diff --git a/org.eclipse.lsp4e.tests.mock/src/org/eclipse/lsp4e/tests/mock/MockLanguageServerMultiRootFolders.java b/org.eclipse.lsp4e.tests.mock/src/org/eclipse/lsp4e/tests/mock/MockLanguageServerMultiRootFolders.java deleted file mode 100644 index ed70b01bb..000000000 --- a/org.eclipse.lsp4e.tests.mock/src/org/eclipse/lsp4e/tests/mock/MockLanguageServerMultiRootFolders.java +++ /dev/null @@ -1,253 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016-2017 Rogue Wave Software Inc. and others. - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Michał Niewrzał (Rogue Wave Software Inc.) - initial implementation - * Mickael Istria (Red Hat Inc.) - added support for delays - * Lucas Bullen (Red Hat Inc.) - Bug 508458 - Add support for codelens - * Martin Lippert (Pivotal Inc.) - Bug 531030 - fixed crash when initial project gets deleted in multi-root workspaces - * Joao Dinis Ferreira (Avaloq Group AG) - Add support for position-dependent mock document highlights - *******************************************************************************/ -package org.eclipse.lsp4e.tests.mock; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.function.Function; - -import org.eclipse.lsp4j.CodeAction; -import org.eclipse.lsp4j.CodeLens; -import org.eclipse.lsp4j.CodeLensOptions; -import org.eclipse.lsp4j.Command; -import org.eclipse.lsp4j.CompletionList; -import org.eclipse.lsp4j.CompletionOptions; -import org.eclipse.lsp4j.Diagnostic; -import org.eclipse.lsp4j.DidChangeTextDocumentParams; -import org.eclipse.lsp4j.DidCloseTextDocumentParams; -import org.eclipse.lsp4j.DidOpenTextDocumentParams; -import org.eclipse.lsp4j.DidSaveTextDocumentParams; -import org.eclipse.lsp4j.DocumentHighlight; -import org.eclipse.lsp4j.DocumentLink; -import org.eclipse.lsp4j.DocumentLinkOptions; -import org.eclipse.lsp4j.Hover; -import org.eclipse.lsp4j.InitializeParams; -import org.eclipse.lsp4j.InitializeResult; -import org.eclipse.lsp4j.Location; -import org.eclipse.lsp4j.Position; -import org.eclipse.lsp4j.ServerCapabilities; -import org.eclipse.lsp4j.SignatureHelp; -import org.eclipse.lsp4j.SignatureHelpOptions; -import org.eclipse.lsp4j.TextDocumentSyncKind; -import org.eclipse.lsp4j.TextEdit; -import org.eclipse.lsp4j.WorkspaceFoldersOptions; -import org.eclipse.lsp4j.WorkspaceServerCapabilities; -import org.eclipse.lsp4j.jsonrpc.Launcher; -import org.eclipse.lsp4j.jsonrpc.messages.Either; -import org.eclipse.lsp4j.launch.LSPLauncher; -import org.eclipse.lsp4j.services.LanguageClient; -import org.eclipse.lsp4j.services.LanguageServer; -import org.eclipse.lsp4j.services.NotebookDocumentService; -import org.eclipse.lsp4j.services.WorkspaceService; - -public final class MockLanguageServerMultiRootFolders implements LanguageServer { - - public static MockLanguageServerMultiRootFolders INSTANCE = new MockLanguageServerMultiRootFolders(); - - private MockTextDocumentService textDocumentService = new MockTextDocumentService(this::buildMaybeDelayedFuture); - private MockWorkspaceService workspaceService = new MockWorkspaceService(this::buildMaybeDelayedFuture); - private InitializeResult initializeResult = new InitializeResult(); - private long delay = 0; - private volatile boolean started; - - public static void reset() { - INSTANCE = new MockLanguageServerMultiRootFolders(); - } - - private MockLanguageServerMultiRootFolders() { - resetInitializeResult(); - } - - /** - * Starts the language server on stdin/stdout - * - * @throws ExecutionException - * @throws InterruptedException - */ - public static void main(String[] args) throws InterruptedException, ExecutionException { - Launcher l = LSPLauncher.createServerLauncher(MockLanguageServerMultiRootFolders.INSTANCE, - System.in, System.out); - Future f = l.startListening(); - MockLanguageServerMultiRootFolders.INSTANCE.addRemoteProxy(l.getRemoteProxy()); - f.get(); - } - - public void addRemoteProxy(LanguageClient remoteProxy) { - this.textDocumentService.addRemoteProxy(remoteProxy); - this.started = true; - } - - private void resetInitializeResult() { - final var capabilities = new ServerCapabilities(); - capabilities.setTextDocumentSync(TextDocumentSyncKind.Full); - final var completionProvider = new CompletionOptions(false, null); - capabilities.setCompletionProvider(completionProvider); - capabilities.setHoverProvider(true); - capabilities.setDefinitionProvider(true); - capabilities.setReferencesProvider(true); - capabilities.setDocumentFormattingProvider(true); - capabilities.setCodeActionProvider(Boolean.TRUE); - capabilities.setCodeLensProvider(new CodeLensOptions(true)); - capabilities.setDocumentLinkProvider(new DocumentLinkOptions()); - capabilities.setSignatureHelpProvider(new SignatureHelpOptions()); - capabilities.setDocumentHighlightProvider(Boolean.TRUE); - - final var workspace = new WorkspaceServerCapabilities(); - final var workspaceFolders = new WorkspaceFoldersOptions(); - workspaceFolders.setSupported(Boolean.TRUE); - - workspace.setWorkspaceFolders(workspaceFolders); - capabilities.setWorkspace(workspace); - initializeResult.setCapabilities(capabilities); - } - - CompletableFuture buildMaybeDelayedFuture(U value) { - if (delay > 0) { - return CompletableFuture.runAsync(() -> { - try { - Thread.sleep(delay); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - }).thenApply(new Function() { - @Override - public U apply(Void v) { - return value; - } - }); - } - return CompletableFuture.completedFuture(value); - } - - @Override - public CompletableFuture initialize(InitializeParams params) { - return buildMaybeDelayedFuture(initializeResult); - } - - @Override - public MockTextDocumentService getTextDocumentService() { - return textDocumentService; - } - - @Override - public WorkspaceService getWorkspaceService() { - return workspaceService; - } - - public void setCompletionList(CompletionList completionList) { - this.textDocumentService.setMockCompletionList(completionList); - } - - public void setHover(Hover hover) { - this.textDocumentService.setMockHover(hover); - } - - public void setCodeLens(List codeLens) { - this.textDocumentService.setMockCodeLenses(codeLens); - } - - public void setDefinition(List definitionLocations) { - this.textDocumentService.setMockDefinitionLocations(definitionLocations); - } - - public void setDidOpenCallback(CompletableFuture didOpenExpectation) { - this.textDocumentService.setDidOpenCallback(didOpenExpectation); - } - - public List getDidChangeEvents() { - return this.textDocumentService.getDidChangeEvents(); - } - - public void setDidSaveCallback(CompletableFuture didSaveExpectation) { - this.textDocumentService.setDidSaveCallback(didSaveExpectation); - } - - public void setDidCloseCallback(CompletableFuture didCloseExpectation) { - this.textDocumentService.setDidCloseCallback(didCloseExpectation); - } - - public void setFormattingTextEdits(List formattingTextEdits) { - this.textDocumentService.setMockFormattingTextEdits(formattingTextEdits); - } - - public void setDocumentHighlights(Map> documentHighlights) { - this.textDocumentService.setDocumentHighlights(documentHighlights); - } - - public void setCompletionTriggerChars(Set chars) { - if (chars != null) { - initializeResult.getCapabilities().getCompletionProvider().setTriggerCharacters(new ArrayList<>(chars)); - } - } - - public void setContextInformationTriggerChars(Set chars) { - if (chars != null) { - initializeResult.getCapabilities().getSignatureHelpProvider().setTriggerCharacters(new ArrayList<>(chars)); - } - } - - public InitializeResult getInitializeResult() { - return initializeResult; - } - - @Override - public CompletableFuture shutdown() { - this.started = false; - this.delay = 0; - resetInitializeResult(); - this.textDocumentService.reset(); - return CompletableFuture.completedFuture(Collections.emptySet()); - } - - @Override - public void exit() { - } - - public void setTimeToProceedQueries(int i) { - this.delay = i; - } - - public void setDiagnostics(List diagnostics) { - this.textDocumentService.setDiagnostics(diagnostics); - } - - public void setCodeActions(List> codeActions) { - this.textDocumentService.setCodeActions(codeActions); - } - - public void setSignatureHelp(SignatureHelp signatureHelp) { - this.textDocumentService.setSignatureHelp(signatureHelp); - } - - public void setDocumentLinks(List documentLinks) { - this.textDocumentService.setMockDocumentLinks(documentLinks); - } - - public boolean isRunning() { - return this.started; - } - - @Override - public NotebookDocumentService getNotebookDocumentService() { - return null; - } -} diff --git a/org.eclipse.lsp4e.tests.mock/src/org/eclipse/lsp4e/tests/mock/MockServerState.java b/org.eclipse.lsp4e.tests.mock/src/org/eclipse/lsp4e/tests/mock/MockServerState.java new file mode 100644 index 000000000..f32bb4d21 --- /dev/null +++ b/org.eclipse.lsp4e.tests.mock/src/org/eclipse/lsp4e/tests/mock/MockServerState.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2026 Contributors to the Eclipse Foundation. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * See git history + *******************************************************************************/ +package org.eclipse.lsp4e.tests.mock; + +/** + * The states of the MockLanguageServer + */ +public enum MockServerState { + /** + * The initial state when the language server was created + */ + RUNNING, + /** + * The state after shutdown was called. + */ + SHUTDOWN, + /** + * The state after exit was called. + */ + EXIT +} diff --git a/org.eclipse.lsp4e.tests.mock/src/org/eclipse/lsp4e/tests/mock/MockTextDocumentService.java b/org.eclipse.lsp4e.tests.mock/src/org/eclipse/lsp4e/tests/mock/MockTextDocumentService.java index d76f6b410..c73dc21ff 100644 --- a/org.eclipse.lsp4e.tests.mock/src/org/eclipse/lsp4e/tests/mock/MockTextDocumentService.java +++ b/org.eclipse.lsp4e.tests.mock/src/org/eclipse/lsp4e/tests/mock/MockTextDocumentService.java @@ -24,7 +24,6 @@ import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Function; import java.util.stream.Collectors; @@ -114,7 +113,10 @@ public class MockTextDocumentService implements TextDocumentService { private ConcurrentLinkedQueue didChangeEvents = new ConcurrentLinkedQueue<>(); private Function> _futureFactory; - private final List remoteProxies = new CopyOnWriteArrayList<>(); + /** + * The remote proxy. This can be used to send requests to the client. + */ + private LanguageClient remoteProxy = null; private Location[] mockReferences = new Location[0]; private List diagnostics; private List> mockCodeActions; @@ -280,17 +282,8 @@ public void didOpen(DidOpenTextDocumentParams params) { } if (this.diagnostics != null && !this.diagnostics.isEmpty()) { - // we're not sure which remote proxy to use, but we know we should only use one - // per didOpen - // for proper LS interaction; so a strategy is to use the first one and rotate - // the others - // for further executions - synchronized (this.remoteProxies) { - // and we synchronize to avoid concurrent read/write on the list - this.remoteProxies.get(0).publishDiagnostics( - new PublishDiagnosticsParams(params.getTextDocument().getUri(), this.diagnostics)); - Collections.rotate(this.remoteProxies, 1); - } + this.remoteProxy.publishDiagnostics( + new PublishDiagnosticsParams(params.getTextDocument().getUri(), this.diagnostics)); } // if (this.foldingRanges != null && !this.foldingRanges.isEmpty()) { // synchronized (this.remoteProxies) { @@ -394,27 +387,12 @@ public void setMockDocumentLinks(List documentLinks) { this.mockDocumentLinks = documentLinks; } - public void reset() { - this.mockCompletionList = new CompletionList(); - this.mockDefinitionLocations = Collections.emptyList(); - this.mockTypeDefinitions = Collections.emptyList(); - this.mockHover = null; - this.mockCodeLenses = null; - this.mockReferences = null; - this.remoteProxies.clear(); - this.mockCodeActions = new ArrayList<>(); - this.mockRenameEdit = null; - this.documentSymbols = Collections.emptyList(); - this.foldingRanges = new ArrayList<>(); - this.codeActionRequests = 0; - } - public void setDiagnostics(List diagnostics) { this.diagnostics = diagnostics; } - public void addRemoteProxy(LanguageClient remoteProxy) { - this.remoteProxies.add(remoteProxy); + public void setRemoteProxy(LanguageClient remoteProxy) { + this.remoteProxy = remoteProxy; } public void setCodeActions(List> codeActions) { diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/ConnectDocumentToLanguageServerSetupParticipant.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/ConnectDocumentToLanguageServerSetupParticipant.java index c3785e892..7abe9e56d 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/ConnectDocumentToLanguageServerSetupParticipant.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/ConnectDocumentToLanguageServerSetupParticipant.java @@ -16,6 +16,8 @@ import java.util.WeakHashMap; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -38,6 +40,12 @@ public class ConnectDocumentToLanguageServerSetupParticipant implements IDocumen private static final Set> PENDING_CONNECTIONS = Collections.synchronizedSet(Collections.newSetFromMap(new WeakHashMap<>())); + public static ScheduledExecutorService DELAYED_EXECUTOR = createExecutor(); + + private static ScheduledExecutorService createExecutor() { + return Executors.newSingleThreadScheduledExecutor(Thread.ofVirtual().name("LS-Document-Delayed-Setup").factory()); //$NON-NLS-1$ + } + @Override public void setup(IDocument document) { ITextFileBuffer buffer = ITextFileBufferManager.DEFAULT.getTextFileBuffer(document); @@ -50,9 +58,13 @@ public void setup(IDocument document) { @Override public void setup(final IDocument document, IPath location, LocationKind locationKind) { // Force document connect - CompletableFuture.runAsync( - () -> PENDING_CONNECTIONS.add(LanguageServers.forDocument(document).collectAll(ls -> CompletableFuture.completedFuture(null))), - CompletableFuture.delayedExecutor(1, TimeUnit.SECONDS)); // delay to ensure the document is initialized and can be resolved by LSPEclipseUtils.toUri + DELAYED_EXECUTOR.schedule(() -> { + PENDING_CONNECTIONS.add( + LanguageServers.forDocument(document).collectAll(ls -> CompletableFuture.completedFuture(null))); + }, + // delay to ensure the document is initialized and can be resolved by + // LSPEclipseUtils.toUri + 1, TimeUnit.SECONDS); } /** @@ -60,13 +72,21 @@ public void setup(final IDocument document, IPath location, LocationKind locatio * jobs trying to attach to them */ public static void waitForAll() { - PENDING_CONNECTIONS.forEach(cf -> { + DELAYED_EXECUTOR.shutdownNow(); + try { + DELAYED_EXECUTOR.awaitTermination(1, TimeUnit.SECONDS); + } catch (InterruptedException e) { + LanguageServerPlugin.logError("Failed to await termination of delayed document setup", e); //$NON-NLS-1$ + } + PENDING_CONNECTIONS.forEach(future -> { try { - cf.get(1000, TimeUnit.MILLISECONDS); + future.get(1, TimeUnit.SECONDS); } catch (InterruptedException | ExecutionException | TimeoutException e) { - LanguageServerPlugin.logInfo("Interrupted trying to cancel document setup"); //$NON-NLS-1$; + LanguageServerPlugin.logError("Interrupted trying to cancel document setup", e); //$NON-NLS-1$ ; } }); + + DELAYED_EXECUTOR = createExecutor(); } }