blob: ae83bc9775a1188751e80286a0b5f07ab2b59155 [file] [log] [blame]
/******************************************************************************
* Copyright (c) 2016 TypeFox and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
******************************************************************************/
package org.eclipse.lsp4j.test.launch;
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.eclipse.lsp4j.CompletionItem;
import org.eclipse.lsp4j.CompletionItemKind;
import org.eclipse.lsp4j.CompletionList;
import org.eclipse.lsp4j.CompletionParams;
import org.eclipse.lsp4j.MessageParams;
import org.eclipse.lsp4j.MessageType;
import org.eclipse.lsp4j.Position;
import org.eclipse.lsp4j.TextDocumentIdentifier;
import org.eclipse.lsp4j.jsonrpc.Endpoint;
import org.eclipse.lsp4j.jsonrpc.Launcher;
import org.eclipse.lsp4j.jsonrpc.json.StreamMessageProducer;
import org.eclipse.lsp4j.jsonrpc.messages.Either;
import org.eclipse.lsp4j.jsonrpc.services.ServiceEndpoints;
import org.eclipse.lsp4j.launch.LSPLauncher;
import org.eclipse.lsp4j.services.LanguageClient;
import org.eclipse.lsp4j.services.LanguageServer;
import org.eclipse.xtext.xbase.lib.Pair;
import org.eclipse.xtext.xbase.lib.util.ToStringBuilder;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
public class LauncherTest {
private static final long TIMEOUT = 2000;
@Test public void testNotification() throws IOException {
MessageParams p = new MessageParams();
p.setMessage("Hello World");
p.setType(MessageType.Info);
client.expectedNotifications.put("window/logMessage", p);
serverLauncher.getRemoteProxy().logMessage(p);
client.joinOnEmpty();
}
@Test public void testRequest() throws Exception {
CompletionParams p = new CompletionParams();
p.setPosition(new Position(1,1));
p.setTextDocument(new TextDocumentIdentifier("test/foo.txt"));
CompletionList result = new CompletionList();
result.setIsIncomplete(true);
result.setItems(new ArrayList<>());
CompletionItem item = new CompletionItem();
item.setDetail("test");
item.setDocumentation("doc");
item.setFilterText("filter");
item.setInsertText("insert");
item.setKind(CompletionItemKind.Field);
result.getItems().add(item);
server.expectedRequests.put("textDocument/completion", new Pair<>(p, result));
CompletableFuture<Either<List<CompletionItem>, CompletionList>> future = clientLauncher.getRemoteProxy().getTextDocumentService().completion(p);
Assert.assertEquals(Either.forRight(result).toString(), future.get(TIMEOUT, TimeUnit.MILLISECONDS).toString());
client.joinOnEmpty();
}
static class AssertingEndpoint implements Endpoint {
public Map<String, Pair<Object, Object>> expectedRequests = new LinkedHashMap<>();
@Override
public CompletableFuture<?> request(String method, Object parameter) {
Assert.assertTrue(expectedRequests.containsKey(method));
Pair<Object, Object> result = expectedRequests.remove(method);
Assert.assertEquals(result.getKey().toString(), parameter.toString());
return CompletableFuture.completedFuture(result.getValue());
}
public Map<String, Object> expectedNotifications = new LinkedHashMap<>();
@Override
public void notify(String method, Object parameter) {
Assert.assertTrue(expectedNotifications.containsKey(method));
Object object = expectedNotifications.remove(method);
Assert.assertEquals(object.toString(), parameter.toString());
}
/**
* wait max 1 sec for all expectations to be removed
*/
public void joinOnEmpty() {
long before = System.currentTimeMillis();
do {
if (expectedNotifications.isEmpty() && expectedNotifications.isEmpty()) {
return;
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} while ( System.currentTimeMillis() < before + 1000);
Assert.fail("expectations weren't empty "+toString());
}
@Override
public String toString() {
return new ToStringBuilder(this).addAllFields().toString();
}
}
private AssertingEndpoint server;
private Launcher<LanguageClient> serverLauncher;
private Future<?> serverListening;
private AssertingEndpoint client;
private Launcher<LanguageServer> clientLauncher;
private Future<?> clientListening;
private Level logLevel;
@Before public void setup() throws IOException {
PipedInputStream inClient = new PipedInputStream();
PipedOutputStream outClient = new PipedOutputStream();
PipedInputStream inServer = new PipedInputStream();
PipedOutputStream outServer = new PipedOutputStream();
inClient.connect(outServer);
outClient.connect(inServer);
server = new AssertingEndpoint();
serverLauncher = LSPLauncher.createServerLauncher(ServiceEndpoints.toServiceObject(server, LanguageServer.class), inServer, outServer);
serverListening = serverLauncher.startListening();
client = new AssertingEndpoint();
clientLauncher = LSPLauncher.createClientLauncher(ServiceEndpoints.toServiceObject(client, LanguageClient.class), inClient, outClient);
clientListening = clientLauncher.startListening();
Logger logger = Logger.getLogger(StreamMessageProducer.class.getName());
logLevel = logger.getLevel();
logger.setLevel(Level.SEVERE);
}
@After public void teardown() throws InterruptedException, ExecutionException {
clientListening.cancel(true);
serverListening.cancel(true);
Thread.sleep(10);
Logger logger = Logger.getLogger(StreamMessageProducer.class.getName());
logger.setLevel(logLevel);
}
}