Moved common LSP test classes to another module

This commit is contained in:
Akash Yadav
2022-04-01 14:03:12 +05:30
parent 0eb5ca6f41
commit 69ee34df3e
23 changed files with 334 additions and 130 deletions
+1 -1
View File
@@ -86,7 +86,7 @@ android {
dependencies {
// Annotation processors
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.13.1'
implementation common.editor
implementation common.utilcode
+54 -54
View File
@@ -43,8 +43,61 @@ subprojects {
}
project.afterEvaluate {
task checkTranslations() {
task format (type: GoogleJavaFormat) {
def php = new File("/usr/bin/php")
if (!php.exists()) {
project.logger.lifecycle("'${php.absolutePath}' not found. Skipping translation check.")
return
}
def resDir = project.file("src/main/res")
def strings = new File(resDir, "values/strings.xml")
def reportDir = new File(project.rootProject.buildDir, "translation-reports")
reportDir.delete()
if (resDir.exists() && strings.exists()) {
def translationDirs = resDir.listFiles((FileFilter) (file -> {
return file.isDirectory() && file.getName().startsWith("values-")
}))
for (def dir : translationDirs) {
final var translation = new File(dir, "strings.xml")
if (translation.exists()) {
def out = new File(reportDir, "${project.path.replace(':', '/')}/${dir.name}.txt")
if (!out.parentFile.exists()) {
out.parentFile.mkdirs()
}
if (out.exists()) {
out.delete()
}
out.createNewFile()
def result = exec {
ignoreExitValue true
standardOutput new FileOutputStream(out)
commandLine "${php.absolutePath}",
"${project.rootProject.file(".tools/strings-check.php")}",
"${strings.absolutePath}",
"${translation.absolutePath}"
}
if (result.getExitValue() == 0) {
out.delete()
} else {
project.logger.lifecycle("Translation report for '${project.path}/${dir.name}' is written to '${out.absolutePath}'")
}
} else {
project.logger.info("No translation file specifed for '${dir.name}'. Skipping..")
}
}
} else {
project.logger.info("Default strings.xml file does not exist for project '${project.name}'")
}
}
task format(type: GoogleJavaFormat) {
source 'src/main'
source 'src/test'
include '**/*.java'
@@ -68,59 +121,6 @@ subprojects {
println "Task preBuild not found in project ${project.displayName}"
}
}
task checkTranslations() {
def php = new File ("/usr/bin/php")
if (!php.exists()) {
project.logger.lifecycle("'${php.absolutePath}' not found. Skipping translation check.")
return
}
def resDir = project.file("src/main/res")
def strings = new File(resDir, "values/strings.xml")
def reportDir = new File(project.rootProject.buildDir, "translation-reports")
reportDir.delete()
if (resDir.exists() && strings.exists()) {
def translationDirs = resDir.listFiles((FileFilter) (file -> {
return file.isDirectory() && file.getName().startsWith("values-") }))
for (def dir : translationDirs) {
final var translation = new File(dir, "strings.xml")
if (translation.exists()) {
def out = new File(reportDir, "${project.path.replace(':', '/')}/${dir.name}.txt")
if (!out.parentFile.exists()) {
out.parentFile.mkdirs()
}
if (out.exists()) {
out.delete()
}
out.createNewFile()
def result = exec {
ignoreExitValue true
standardOutput new FileOutputStream(out)
commandLine "${php.absolutePath}",
"${project.rootProject.file(".tools/strings-check.php")}",
"${strings.absolutePath}",
"${translation.absolutePath}"
}
if (result.getExitValue() == 0) {
out.delete()
} else {
project.logger.lifecycle("Translation report for '${project.path}/${dir.name}' is written to '${out.absolutePath}'")
}
} else {
project.logger.info("No translation file specifed for '${dir.name}'. Skipping..")
}
}
} else {
project.logger.info("Default strings.xml file does not exist for project '${project.name}'")
}
}
}
allprojects {
-2
View File
@@ -35,6 +35,4 @@ dependencies {
implementation androidx.animated_vectors
api androidx.multidex
testImplementation tests.junit4
}
+5 -1
View File
@@ -34,6 +34,10 @@ ext {
]
tests = [
junit4: 'junit:junit:4.13'
junit: 'junit:junit:4.13.2',
google_truth: 'com.google.truth:truth:1.1.3',
robolectric: 'org.robolectric:robolectric:4.7.3',
androidx_junit: 'androidx.test.ext:junit:1.1.3',
androidx_espresso: 'androidx.test.espresso:espresso-core:3.4.0'
]
}
+2
View File
@@ -37,6 +37,7 @@ android {
targetCompatibility rootProject.ext.javaTargetVersion
}
}
dependencies {
implementation common.editor
implementation "androidx.core:core-ktx:1.7.0"
@@ -44,6 +45,7 @@ dependencies {
compileOnly project(':common')
}
repositories {
mavenCentral()
}
@@ -67,6 +67,13 @@ public interface ILanguageServer {
*/
void initialize(@NonNull InitializeParams params) throws AlreadyInitializedException;
/**
* Checks if this language server has been initialized.
*
* @return <code>true</code> if the server has been initialized, <code>false</code> otherwise.
*/
boolean isInitialized();
/**
* Returns the capabilities that the LSP implementation provides.
*
+7 -7
View File
@@ -59,14 +59,14 @@ dependencies {
implementation "androidx.core:core-ktx:1.7.0"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
testImplementation project(':lsp:testing')
testImplementation project(':common')
testImplementation 'com.google.truth:truth:1.1.3'
testImplementation 'junit:junit:4.13.2'
testImplementation 'org.robolectric:robolectric:4.7.3'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
androidTestImplementation 'com.google.truth:truth:1.1.3'
testImplementation common.utilcode
testImplementation tests.junit
testImplementation tests.google_truth
testImplementation tests.robolectric
androidTestImplementation tests.androidx_junit
androidTestImplementation tests.androidx_espresso
androidTestImplementation tests.google_truth
}
repositories {
@@ -147,7 +147,8 @@ public class JavaLanguageServer implements ILanguageServer, IDocumentHandler {
initialized = true;
}
boolean isInitialized() {
@Override
public boolean isInitialized() {
return initialized;
}
@@ -0,0 +1,16 @@
package com.itsaky.lsp.java
import com.itsaky.lsp.api.ILanguageServer
import com.itsaky.lsp.api.LanguageServerProvider
class JavaLanguageServerProvider : LanguageServerProvider() {
private val server: JavaLanguageServer = JavaLanguageServer()
override fun getServer(): ILanguageServer {
return server
}
companion object {
@JvmStatic
val INSTANCE: LanguageServerProvider = JavaLanguageServerProvider()
}
}
@@ -0,0 +1,55 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.lsp.java.providers
import com.google.common.truth.Truth.assertThat
import com.itsaky.lsp.api.CursorDependentTest
import com.itsaky.lsp.api.ILanguageServer
import com.itsaky.lsp.java.JavaLanguageServerProvider
import com.itsaky.lsp.models.CompletionParams
import com.itsaky.lsp.models.Position
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
/**
* @author Akash Yadav
*/
@RunWith(RobolectricTestRunner::class)
@Config(manifest = Config.NONE)
class JavaCompletionProviderTest : CursorDependentTest() {
private val server: ILanguageServer = JavaLanguageServerProvider.INSTANCE.server()
override fun getServer(): ILanguageServer = server
@Test
fun testLocals() {
openFile("LocalsCompletionTest")
val pos = cursorPosition()
val items = completionTitles(pos)
assertThat(items).containsAtLeast("aString", "anInt", "aFloat", "aDouble", "args")
}
override fun openFile(fileName: String) {
super.openFile("completion/${fileName}")
}
private fun completionTitles(pos: Position): List<CharSequence> {
return server.completionProvider.complete(CompletionParams(pos, file!!)).items.map { it.label }
}
}
@@ -17,18 +17,19 @@
package com.itsaky.lsp.java.providers
import com.google.common.truth.Truth.assertThat
import com.itsaky.lsp.java.CursorDependentTest
import com.itsaky.lsp.java.FileProvider.Companion.contents
import com.itsaky.lsp.java.FileProvider.Companion.sourceFile
import com.itsaky.lsp.java.LanguageServerProvider
import com.itsaky.lsp.models.*
import com.itsaky.lsp.api.CursorDependentTest
import com.itsaky.lsp.api.ILanguageServer
import com.itsaky.lsp.java.JavaLanguageServerProvider
import com.itsaky.lsp.models.DocumentChangeEvent
import com.itsaky.lsp.models.ExpandSelectionParams
import com.itsaky.lsp.models.Position
import com.itsaky.lsp.models.Range
import io.github.rosemoe.sora.text.Content
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
import java.nio.file.Path
/**
* @author Akash Yadav
@@ -36,26 +37,24 @@ import java.nio.file.Path
@RunWith(RobolectricTestRunner::class)
@Config(manifest = Config.NONE)
class JavaSelectionProviderTest : CursorDependentTest() {
private var file: Path? = null
private var contents: StringBuilder? = null
private var cursor: Int = -1
private val server: ILanguageServer = JavaLanguageServerProvider.INSTANCE.server()
override fun getServer(): ILanguageServer = server
@Before
fun init() {
LOG.debug("Initializing JavaSelectionProviderTest")
LanguageServerProvider.initIfNecessary()
}
@Test
fun testSimpleSelectionExpansion() {
openFile("SimpleSelectionExpansionTest")
cursor = requireCursor(contents!!)
contents!!.delete(cursor, cursor + CURSOR.length)
assertThat(contents!!.indexOf(CURSOR)).isEqualTo(-1)
LanguageServerProvider.server().onContentChange(DocumentChangeEvent(file!!, contents.toString(), 1))
cursor = requireCursor()
deleteCursorText()
server.documentHandler.onContentChange(DocumentChangeEvent(file!!, contents.toString(), 1))
val range = findRange()
val expanded = LanguageServerProvider.server()
val expanded = server
.expandSelection(ExpandSelectionParams(file!!, range))
assertThat(expanded).isEqualTo(Range(Position(4, 27), Position(4, 41)))
@@ -63,39 +62,39 @@ class JavaSelectionProviderTest : CursorDependentTest() {
@Test
fun testMethodSelection() {
openFile("MethodBodySelectionExpansionTest");
openFile("MethodBodySelectionExpansionTest")
val start = Position(3, 43)
val end = Position(5, 5)
val range = Range(start, end)
val expanded = LanguageServerProvider.server().expandSelection(ExpandSelectionParams(file!!, range))
val expanded = server.expandSelection(ExpandSelectionParams(file!!, range))
assertThat(expanded).isEqualTo(Range(Position(3, 4), end))
}
@Test
fun testTryCatchSelection() {
openFile("TrySelectionExpansionTest");
openFile("TrySelectionExpansionTest")
// Test expand selection if catch block is selected
val start = Position(7, 10)
val end = Position(8, 9)
val range = Range(start, end)
val expanded = LanguageServerProvider.server().expandSelection(ExpandSelectionParams(file!!, range))
val expanded = server.expandSelection(ExpandSelectionParams(file!!, range))
assertThat(expanded).isEqualTo(Range(Position(4, 8), Position(10, 9)))
}
@Test
fun testTryFinallySelection() {
openFile("TrySelectionExpansionTest");
openFile("TrySelectionExpansionTest")
// Test expand selection if catch block is selected
val start = Position(8, 18)
val end = Position(10, 9)
val range = Range(start, end)
val expanded = LanguageServerProvider.server().expandSelection(ExpandSelectionParams(file!!, range))
val expanded = server.expandSelection(ExpandSelectionParams(file!!, range))
assertThat(expanded).isEqualTo(Range(Position(4, 8), Position(10, 9)))
}
@@ -105,11 +104,7 @@ class JavaSelectionProviderTest : CursorDependentTest() {
return Range(position, position)
}
private fun openFile(fileName: String) {
file = sourceFile("selection/$fileName")
contents = contents(file!!)
LanguageServerProvider.server()
.onFileOpened(DocumentOpenEvent(file!!, contents.toString(), 0))
override fun openFile(fileName: String) {
super.openFile("selection/${fileName}")
}
}
@@ -0,0 +1,11 @@
package com.itsaky.androidide.test;
public class Main {
public static void main(String[] args) {
final String aṣ = args[0];
final int anInt = 0;
final float aFloat = 0f;
final double aDouble = 0.0;
a@@cursor@@
}
}
+1
View File
@@ -0,0 +1 @@
/build
+52
View File
@@ -0,0 +1,52 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
android {
compileSdkVersion rootProject.ext.compileSdk
buildToolsVersion rootProject.ext.buildTools
defaultConfig {
minSdkVersion rootProject.ext.minSdk
targetSdkVersion rootProject.ext.targetSdk
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility rootProject.ext.javaSourceVersion
targetCompatibility rootProject.ext.javaTargetVersion
}
}
dependencies {
implementation "androidx.core:core-ktx:1.7.0"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation project(':lsp:api')
implementation project(':common')
implementation common.editor
implementation tests.junit
implementation tests.google_truth
implementation tests.robolectric
}
+1
View File
@@ -0,0 +1 @@
<manifest package="com.itsaky.lsp.testing"/>
@@ -1,42 +1,38 @@
/*
* This file is part of AndroidIDE.
*
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.lsp.java
package com.itsaky.lsp.api
import com.google.common.truth.Truth.assertThat
import com.itsaky.lsp.models.DocumentOpenEvent
import java.nio.file.Path
/**
* A cursor dependent test is a test that needs to have cursor positions specified in the content.
* `@@cursor@@` denotes the position of the cursor in source files.
*
* @author Akash Yadav
*/
open class CursorDependentTest : LoggingTest() {
abstract class BaseLanguageServerTest {
protected var file: Path? = null
protected var contents: StringBuilder? = null
protected val CURSOR = "@@cursor@@"
fun requireCursor(content: String): Int {
val cursor = content.indexOf(CURSOR)
assertThat(cursor).isGreaterThan(-1)
return cursor
open fun openFile(fileName: String) {
file = FileProvider.sourceFile(fileName)
contents = FileProvider.contents(file!!)
getServer().documentHandler
.onFileOpened(DocumentOpenEvent(file!!, contents.toString(), 0))
}
fun requireCursor(content: StringBuilder): Int {
val cursor = content.indexOf(CURSOR)
assertThat(cursor).isGreaterThan(-1)
return cursor
}
protected abstract fun getServer(): ILanguageServer
}
@@ -0,0 +1,63 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.lsp.api
import com.google.common.truth.Truth.assertThat
import com.itsaky.lsp.models.Position
import io.github.rosemoe.sora.text.Content
/**
* A cursor dependent test is a test that needs to have cursor positions specified in the content.
* `@@cursor@@` denotes the position of the cursor in source files.
*
* @author Akash Yadav
*/
abstract class CursorDependentTest : LoggingTest() {
protected var cursor: Int = -1
private val cursorText = "@@cursor@@"
fun requireCursor(): Int {
assertThat(cursor).isGreaterThan(-1)
return cursor
}
fun deleteCursorText() {
contents!!.delete(this.cursor, this.cursor + cursorText.length)
assertThat(contents!!.indexOf(cursorText)).isEqualTo(-1)
}
fun cursorPosition(): Position {
return cursorPosition(true)
}
fun cursorPosition(deleteCursorText: Boolean): Position {
requireCursor()
if (deleteCursorText) {
deleteCursorText()
}
val pos = Content(contents!!).indexer.getCharPosition(cursor)
return Position(pos.line, pos.column, pos.index)
}
override fun openFile(fileName: String) {
super.openFile(fileName)
this.cursor = super.contents!!.indexOf(cursorText)
}
}
@@ -14,7 +14,7 @@
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.lsp.java
package com.itsaky.lsp.api
import com.google.common.truth.Truth.assertThat
import org.junit.Test
@@ -14,11 +14,11 @@
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.lsp.java
package com.itsaky.lsp.api
import com.google.common.truth.Truth.assertThat
import com.itsaky.androidide.utils.Environment
import com.itsaky.lsp.java.FileProvider.Companion.resources
import com.itsaky.lsp.api.FileProvider.Companion.resources
import com.itsaky.lsp.models.InitializeParams
import org.jetbrains.annotations.Contract
import java.io.File
@@ -28,9 +28,9 @@ import java.io.File
*
* @author Akash Yadav
*/
object LanguageServerProvider {
private val server = JavaLanguageServer()
fun server(): JavaLanguageServer {
abstract class LanguageServerProvider {
fun server(): ILanguageServer {
if (Environment.COMPILER_MODULE == null) {
val javaHome = System.getProperty("java.home")
@@ -38,12 +38,16 @@ object LanguageServerProvider {
Environment.COMPILER_MODULE = File(javaHome)
}
return server
initIfNecessary()
return getServer()
}
fun initIfNecessary() {
if (!server().isInitialized) {
server().initialize(createInitParams())
protected abstract fun getServer(): ILanguageServer
private fun initIfNecessary() {
if (!getServer().isInitialized) {
getServer().initialize(createInitParams())
}
}
@@ -14,11 +14,10 @@
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.lsp.java
package com.itsaky.lsp.api
import com.itsaky.androidide.utils.Logger
import com.itsaky.lsp.java.LoggingTest
import com.itsaky.lsp.java.util.ReflectiveLogListener
import com.itsaky.lsp.api.util.ReflectiveLogListener
import java.util.*
/**
@@ -26,7 +25,7 @@ import java.util.*
*
* @author Akash Yadav
*/
open class LoggingTest {
abstract class LoggingTest : BaseLanguageServerTest() {
companion object {
private var logListener: ReflectiveLogListener? = null
@@ -14,7 +14,7 @@
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.lsp.java.util
package com.itsaky.lsp.api.util
import com.itsaky.androidide.utils.Logger
+1
View File
@@ -11,3 +11,4 @@ include ':gradle-plugin'
include ':lsp:api'
include ':lsp:java'
include ':lsp:xml'
include ':lsp:testing'
-2
View File
@@ -35,6 +35,4 @@ dependencies {
implementation project (":common")
api project (':sdk-info')
testImplementation tests.junit4
}