[lsi][testing] Extracted the reusable language server test

infrastructure

Change-Id: I848bc2f59b1b636ff3ee666aa1057eb15025a116
Signed-off-by: akosyakov <anton.kosyakov@typefox.io>
This commit is contained in:
akosyakov 2016-06-03 11:02:53 +02:00
parent 8d7e5d9724
commit 66caca99ad
9 changed files with 200 additions and 205 deletions

View file

@ -10,13 +10,17 @@ package org.eclipse.xtext.ide.tests.server
import com.google.inject.AbstractModule
import com.google.inject.Guice
import com.google.inject.Inject
import io.typefox.lsapi.CompletionItem
import io.typefox.lsapi.Diagnostic
import io.typefox.lsapi.Hover
import io.typefox.lsapi.InitializeParamsImpl
import io.typefox.lsapi.InitializeResult
import io.typefox.lsapi.Location
import io.typefox.lsapi.MarkedString
import io.typefox.lsapi.Position
import io.typefox.lsapi.PublishDiagnosticsParams
import io.typefox.lsapi.Range
import io.typefox.lsapi.ReferenceContextImpl
import io.typefox.lsapi.SymbolInformation
import java.io.File
import java.io.FileWriter
@ -27,45 +31,60 @@ import java.util.List
import java.util.Map
import java.util.concurrent.CompletableFuture
import java.util.function.Consumer
import org.eclipse.xtend.lib.annotations.Accessors
import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor
import org.eclipse.xtext.LanguageInfo
import org.eclipse.xtext.ide.server.LanguageServerImpl
import org.eclipse.xtext.ide.server.ServerModule
import org.eclipse.xtext.ide.server.UriExtensions
import org.eclipse.xtext.ide.server.concurrent.RequestManager
import org.eclipse.xtext.resource.IResourceServiceProvider
import org.eclipse.xtext.util.CancelIndicator
import org.eclipse.xtext.util.Files
import org.eclipse.xtext.util.Modules2
import org.junit.Before
import static io.typefox.lsapi.util.LsapiFactories.*
import static org.junit.Assert.*
import static extension io.typefox.lsapi.util.LsapiFactories.*
/**
* @author Sven Efftinge - Initial contribution and API
*/
class AbstractLanguageServerTest implements Consumer<PublishDiagnosticsParams> {
@FinalFieldsConstructor
abstract class AbstractLanguageServerTest implements Consumer<PublishDiagnosticsParams> {
@Accessors
protected val String fileExtension
@Before
def void setup() {
val module = Modules2.mixin(new ServerModule, new AbstractModule() {
override protected configure() {
bind(RequestManager).toInstance(new RequestManager() {
override runWrite((CancelIndicator)=>void writeRequest, CancelIndicator cancelIndicator) {
writeRequest.apply(cancelIndicator)
return CompletableFuture.completedFuture(null)
}
override <V> runRead((CancelIndicator)=>V readRequest, CancelIndicator cancelIndicator) {
return CompletableFuture.completedFuture(readRequest.apply(cancelIndicator))
}
})
}
})
val injector = Guice.createInjector(module)
injector.injectMembers(this)
val resourceServiceProvider = resourceServerProviderRegistry.extensionToFactoryMap.get(fileExtension)
if (resourceServiceProvider instanceof IResourceServiceProvider)
languageInfo = resourceServiceProvider.get(LanguageInfo)
// register notification callbacks
languageServer.getTextDocumentService().onPublishDiagnostics(this)
@ -77,11 +96,15 @@ class AbstractLanguageServerTest implements Consumer<PublishDiagnosticsParams> {
root.deleteOnExit
}
@Inject
protected IResourceServiceProvider.Registry resourceServerProviderRegistry
@Inject extension UriExtensions
@Inject protected LanguageServerImpl languageServer
protected Map<String, List<? extends Diagnostic>> diagnostics = newHashMap()
protected File root
protected LanguageInfo languageInfo
protected def Path getRootPath() {
root.toPath().toAbsolutePath().normalize()
@ -103,9 +126,13 @@ class AbstractLanguageServerTest implements Consumer<PublishDiagnosticsParams> {
}
protected def void open(String fileUri, String model) {
languageServer.didOpen(newDidOpenTextDocumentParams(fileUri, "testlang", 1, model))
open(fileUri, languageInfo.languageName, model)
}
protected def void open(String fileUri, String langaugeId, String model) {
languageServer.didOpen(newDidOpenTextDocumentParams(fileUri, langaugeId, 1, model))
}
protected def void close(String fileUri) {
languageServer.didClose(newDidCloseTextDocumentParams(fileUri))
}
@ -131,7 +158,7 @@ class AbstractLanguageServerTest implements Consumer<PublishDiagnosticsParams> {
«element.toExpectation»
«ENDFOR»
'''
protected def dispatch String toExpectation(Void it) { '' }
protected def dispatch String toExpectation(Location it) '''«uri.relativize» «range.toExpectation»'''
@ -150,4 +177,154 @@ class AbstractLanguageServerTest implements Consumer<PublishDiagnosticsParams> {
}
'''
protected def dispatch String toExpectation(CompletionItem it) '''
«label»«IF !detail.nullOrEmpty» («detail»)«ENDIF»«IF insertText != label» -> «insertText»«ENDIF»
'''
protected dispatch def String toExpectation(Hover it) '''
«range.toExpectation»
«FOR content : contents»
«content.toExpectation»
«ENDFOR»
'''
protected dispatch def String toExpectation(
MarkedString it
) '''«IF !language.nullOrEmpty»«language» -> «ENDIF»«value»'''
protected def void testCompletion((TestCompletionConfiguration)=>void configurator) {
val extension configuration = new TestCompletionConfiguration
configuration.filePath = 'MyModel.' + fileExtension
configurator.apply(configuration)
val fileUri = filePath -> model
initialize
open(fileUri, model)
val completionItems = languageServer.completion(newTextDocumentPositionParams(fileUri, line, column))
val actualCompletionItems = completionItems.get.items.toExpectation
assertEquals(expectedCompletionItems, actualCompletionItems)
}
protected def void testDefinition((DefinitionTestConfiguration)=>void configurator) {
val extension configuration = new DefinitionTestConfiguration
configuration.filePath = 'MyModel.' + fileExtension
configurator.apply(configuration)
val fileUri = filePath -> model
initialize
open(fileUri, model)
val definitions = languageServer.definition(newTextDocumentPositionParams(fileUri, line, column))
val actualDefinitions = definitions.get.toExpectation
assertEquals(expectedDefinitions, actualDefinitions)
}
protected def void testHover((HoverTestConfiguration)=>void configurator) {
val extension configuration = new HoverTestConfiguration
configuration.filePath = 'MyModel.' + fileExtension
configurator.apply(configuration)
val fileUri = filePath -> model
initialize
open(fileUri, model)
val hover = languageServer.hover(newTextDocumentPositionParams(fileUri, line, column))
val actualHover = hover.get.toExpectation
assertEquals(expectedHover, actualHover)
}
protected def void testDocumentSymbol((DocumentSymbolConfiguraiton)=>void configurator) {
val extension configuration = new DocumentSymbolConfiguraiton
configuration.filePath = 'MyModel.' + fileExtension
configurator.apply(configuration)
val fileUri = filePath -> model
initialize
open(fileUri, model)
val symbols = languageServer.documentSymbol(fileUri.newDocumentSymbolParams)
val String actualSymbols = symbols.get.toExpectation
assertEquals(expectedSymbols, actualSymbols)
}
protected def void testSymbol((WorkspaceSymbolConfiguraiton)=>void configurator) {
val extension configuration = new WorkspaceSymbolConfiguraiton
configuration.filePath = 'MyModel.' + fileExtension
configurator.apply(configuration)
val fileUri = filePath -> model
initialize
open(fileUri, model)
val symbols = languageServer.symbol(query.newWorkspaceSymbolParams).get
val String actualSymbols = symbols.toExpectation
assertEquals(expectedSymbols, actualSymbols)
}
protected def void testReferences((ReferenceTestConfiguration)=>void configurator) {
val extension configuration = new ReferenceTestConfiguration
configuration.filePath = 'MyModel.' + fileExtension
configurator.apply(configuration)
val fileUri = filePath -> model
initialize
open(fileUri, model)
val referenceContext = new ReferenceContextImpl
referenceContext.includeDeclaration = includeDeclaration
val definitions = languageServer.references(newReferenceParams(fileUri, line, column, referenceContext))
val actualDefinitions = definitions.get.toExpectation
assertEquals(expectedReferences, actualDefinitions)
}
}
@Accessors
class TestCompletionConfiguration extends TextDocumentPositionConfiguration {
String expectedCompletionItems = ''
}
@Accessors
class DefinitionTestConfiguration extends TextDocumentPositionConfiguration {
String expectedDefinitions = ''
}
@Accessors
class HoverTestConfiguration extends TextDocumentPositionConfiguration {
String expectedHover = ''
}
@Accessors
class DocumentSymbolConfiguraiton extends TextDocumentConfiguration {
String expectedSymbols = ''
}
@Accessors
class ReferenceTestConfiguration extends TextDocumentPositionConfiguration {
boolean includeDeclaration = false
String expectedReferences = ''
}
@Accessors
class WorkspaceSymbolConfiguraiton extends TextDocumentConfiguration {
String query = ''
String expectedSymbols = ''
}
@Accessors
class TextDocumentPositionConfiguration extends TextDocumentConfiguration {
int line = 0
int column = 0
}
@Accessors
class TextDocumentConfiguration {
String model = ''
String filePath
}

View file

@ -7,17 +7,12 @@
*******************************************************************************/
package org.eclipse.xtext.ide.tests.server
import io.typefox.lsapi.CompletionItem
import org.eclipse.xtend.lib.annotations.Accessors
import org.junit.Test
import static io.typefox.lsapi.util.LsapiFactories.*
import static org.junit.Assert.*
/**
* @author kosyakov - Initial contribution and API
*/
class CompletionTest extends AbstractLanguageServerTest {
class CompletionTest extends AbstractTestLangLanguageServerTest {
@Test
def void testCompletion_01() {
@ -60,31 +55,4 @@ class CompletionTest extends AbstractLanguageServerTest {
]
}
protected def testCompletion((TestCompletionConfiguration)=>void configurator) {
val extension configuration = new TestCompletionConfiguration
configurator.apply(configuration)
val fileUri = filePath -> model
initialize
open(fileUri, model)
val completionItems = languageServer.completion(newTextDocumentPositionParams(fileUri, line, column))
val actualCompletionItems = completionItems.get.items.toExpectation
assertEquals(expectedCompletionItems, actualCompletionItems)
}
protected def dispatch String toExpectation(CompletionItem it) '''
«label»«IF !detail.nullOrEmpty» («detail»)«ENDIF»«IF insertText != label» -> «insertText»«ENDIF»
'''
@Accessors
static class TestCompletionConfiguration {
String model = ''
String filePath = 'MyModel.testlang'
int line = 0
int column = 0
String expectedCompletionItems = ''
}
}

View file

@ -7,16 +7,12 @@
*******************************************************************************/
package org.eclipse.xtext.ide.tests.server
import org.eclipse.xtend.lib.annotations.Accessors
import org.junit.Test
import static org.junit.Assert.*
import static io.typefox.lsapi.util.LsapiFactories.*
/**
* @author kosyakov - Initial contribution and API
*/
class DefinitionTest extends AbstractLanguageServerTest {
class DefinitionTest extends AbstractTestLangLanguageServerTest {
@Test
def void testDefinition_01() {
@ -35,27 +31,4 @@ class DefinitionTest extends AbstractLanguageServerTest {
]
}
protected def void testDefinition((DefinitionTestConfiguration)=>void configurator) {
val extension configuration = new DefinitionTestConfiguration
configurator.apply(configuration)
val fileUri = filePath -> model
initialize
open(fileUri, model)
val definitions = languageServer.definition(newTextDocumentPositionParams(fileUri, line, column))
val actualDefinitions = definitions.get.toExpectation
assertEquals(expectedDefinitions, actualDefinitions)
}
@Accessors
static class DefinitionTestConfiguration {
String model = ''
String filePath = 'MyModel.testlang'
int line = 0
int column = 0
String expectedDefinitions = ''
}
}

View file

@ -7,17 +7,12 @@
*******************************************************************************/
package org.eclipse.xtext.ide.tests.server
import org.eclipse.xtend.lib.annotations.Accessors
import org.junit.Test
import static org.junit.Assert.*
import static extension io.typefox.lsapi.util.LsapiFactories.*
/**
* @author kosyakov - Initial contribution and API
*/
class DocumentSymbolTest extends AbstractLanguageServerTest {
class DocumentSymbolTest extends AbstractTestLangLanguageServerTest {
@Test
def void testDocumentSymbol_01() {
@ -58,24 +53,4 @@ class DocumentSymbolTest extends AbstractLanguageServerTest {
]
}
protected def void testDocumentSymbol((DocumentSymbolConfiguraiton)=>void configurator) {
val extension configuration = new DocumentSymbolConfiguraiton
configurator.apply(configuration)
val fileUri = filePath -> model
initialize
open(fileUri, model)
val symbols = languageServer.documentSymbol(fileUri.newDocumentSymbolParams)
val String actualSymbols = symbols.get.toExpectation
assertEquals(expectedSymbols, actualSymbols)
}
@Accessors
static class DocumentSymbolConfiguraiton {
String model = ''
String filePath = 'MyModel.testlang'
String expectedSymbols = ''
}
}

View file

@ -7,18 +7,12 @@
*******************************************************************************/
package org.eclipse.xtext.ide.tests.server
import io.typefox.lsapi.Hover
import io.typefox.lsapi.MarkedString
import org.eclipse.xtend.lib.annotations.Accessors
import org.junit.Test
import static io.typefox.lsapi.util.LsapiFactories.*
import static org.junit.Assert.*
/**
* @author kosyakov - Initial contribution and API
*/
class HoverTest extends AbstractLanguageServerTest {
class HoverTest extends AbstractTestLangLanguageServerTest {
@Test
def void testHover_01() {
@ -73,38 +67,4 @@ class HoverTest extends AbstractLanguageServerTest {
]
}
protected def void testHover((HoverTestConfiguration)=>void configurator) {
val extension configuration = new HoverTestConfiguration
configurator.apply(configuration)
val fileUri = filePath -> model
initialize
open(fileUri, model)
val hover = languageServer.hover(newTextDocumentPositionParams(fileUri, line, column))
val actualHover = hover.get.toExpectation
assertEquals(expectedHover, actualHover)
}
@Accessors
static class HoverTestConfiguration {
String model = ''
String filePath = 'MyModel.testlang'
int line = 0
int column = 0
String expectedHover = ''
}
protected dispatch def String toExpectation(Hover it) '''
«range.toExpectation»
«FOR content : contents»
«content.toExpectation»
«ENDFOR»
'''
protected dispatch def String toExpectation(
MarkedString it
) '''«IF !language.nullOrEmpty»«language» -> «ENDIF»«value»'''
}

View file

@ -17,7 +17,7 @@ import static extension io.typefox.lsapi.util.LsapiFactories.*
/**
* @author Sven Efftinge - Initial contribution and API
*/
class OpenDocumentTest extends AbstractLanguageServerTest {
class OpenDocumentTest extends AbstractTestLangLanguageServerTest {
@Test
def void testOpenedDocumentShadowsPersistedFile() {

View file

@ -7,17 +7,12 @@
*******************************************************************************/
package org.eclipse.xtext.ide.tests.server
import io.typefox.lsapi.ReferenceContextImpl
import org.eclipse.xtend.lib.annotations.Accessors
import org.junit.Test
import static io.typefox.lsapi.util.LsapiFactories.*
import static org.junit.Assert.*
/**
* @author kosyakov - Initial contribution and API
*/
class ReferenceTest extends AbstractLanguageServerTest {
class ReferenceTest extends AbstractTestLangLanguageServerTest {
@Test
def void testReferences_01() {
@ -53,30 +48,4 @@ class ReferenceTest extends AbstractLanguageServerTest {
]
}
protected def void testReferences((ReferenceTestConfiguration)=>void configurator) {
val extension configuration = new ReferenceTestConfiguration
configurator.apply(configuration)
val fileUri = filePath -> model
initialize
open(fileUri, model)
val referenceContext = new ReferenceContextImpl
referenceContext.includeDeclaration = includeDeclaration
val definitions = languageServer.references(newReferenceParams(fileUri, line, column, referenceContext))
val actualDefinitions = definitions.get.toExpectation
assertEquals(expectedReferences, actualDefinitions)
}
@Accessors
static class ReferenceTestConfiguration {
String model = ''
String filePath = 'MyModel.testlang'
int line = 0
int column = 0
boolean includeDeclaration = false
String expectedReferences = ''
}
}

View file

@ -17,7 +17,7 @@ import static extension io.typefox.lsapi.util.LsapiFactories.*
/**
* @author Sven Efftinge - Initial contribution and API
*/
class ServerTest extends AbstractLanguageServerTest {
class ServerTest extends AbstractTestLangLanguageServerTest {
@Test
def void testInitializeBuild() {

View file

@ -7,21 +7,16 @@
*******************************************************************************/
package org.eclipse.xtext.ide.tests.server
import org.eclipse.xtend.lib.annotations.Accessors
import org.junit.Test
import static org.junit.Assert.*
import static extension io.typefox.lsapi.util.LsapiFactories.*
/**
* @author kosyakov - Initial contribution and API
*/
class WorkspaceSymbolTest extends AbstractLanguageServerTest {
class WorkspaceSymbolTest extends AbstractTestLangLanguageServerTest {
@Test
def void testDocumentSymbol_01() {
testDocumentSymbol[
def void testSymbol_01() {
testSymbol[
model = '''
type Foo {
int bar
@ -53,8 +48,8 @@ class WorkspaceSymbolTest extends AbstractLanguageServerTest {
}
@Test
def void testDocumentSymbol_02() {
testDocumentSymbol[
def void testSymbol_02() {
testSymbol[
model = '''
type Foo {
int bar
@ -84,27 +79,5 @@ class WorkspaceSymbolTest extends AbstractLanguageServerTest {
'''
]
}
protected def void testDocumentSymbol((WorkspaceSymbolConfiguraiton)=>void configurator) {
val extension configuration = new WorkspaceSymbolConfiguraiton
configurator.apply(configuration)
val fileUri = filePath -> model
initialize
open(fileUri, model)
val symbols = languageServer.symbol(query.newWorkspaceSymbolParams).get
val String actualSymbols = symbols.toExpectation
assertEquals(expectedSymbols, actualSymbols)
}
@Accessors
static class WorkspaceSymbolConfiguraiton {
String model = ''
String filePath = 'MyModel.testlang'
String query = ''
String expectedSymbols = ''
}
}