diff --git a/build-tools/tooling-api-impl/src/test/java/com/itsaky/androidide/tooling/impl/ToolingApiImplTest.kt b/build-tools/tooling-api-impl/src/test/java/com/itsaky/androidide/tooling/impl/ToolingApiImplTest.kt index a6d6cb5ed..498efea84 100644 --- a/build-tools/tooling-api-impl/src/test/java/com/itsaky/androidide/tooling/impl/ToolingApiImplTest.kt +++ b/build-tools/tooling-api-impl/src/test/java/com/itsaky/androidide/tooling/impl/ToolingApiImplTest.kt @@ -43,9 +43,7 @@ class ToolingApiImplTest { fun testProjectInit() { val client = TestClient() val (server, project) = ToolingApiTestLauncher().launchServer() - server.initialize(InitializeProjectMessage(File("./src/test/test-project").absolutePath)).get() - verifyProjectProps(project, server) } diff --git a/build-tools/tooling-api-impl/src/test/test-home/.androidide/init/model.jar b/build-tools/tooling-api-impl/src/test/test-home/.androidide/init/model.jar index 1367839d9..1f334a893 100644 Binary files a/build-tools/tooling-api-impl/src/test/test-home/.androidide/init/model.jar and b/build-tools/tooling-api-impl/src/test/test-home/.androidide/init/model.jar differ diff --git a/build-tools/tooling-api-impl/src/test/test-project/app/src/main/resources/SourceFileTest_tempate.java b/build-tools/tooling-api-impl/src/test/test-project/app/src/main/resources/SourceFileTest_tempate.java new file mode 100644 index 000000000..26f944a7f --- /dev/null +++ b/build-tools/tooling-api-impl/src/test/test-project/app/src/main/resources/SourceFileTest_tempate.java @@ -0,0 +1,7 @@ +package com.itsaky.androidide.test; + +public class Main { + public static void main(String[] args) { + System.out.println("Hello World!"); + } +} diff --git a/build-tools/tooling-api-impl/src/test/test-project/app/src/main/resources/actions/AddImportAction_template.java b/build-tools/tooling-api-impl/src/test/test-project/app/src/main/resources/actions/AddImportAction_template.java new file mode 100644 index 000000000..a1e0b1285 --- /dev/null +++ b/build-tools/tooling-api-impl/src/test/test-project/app/src/main/resources/actions/AddImportAction_template.java @@ -0,0 +1,7 @@ +package com.itsaky.androidide.test; + +public class AddImportAction_template { + public static void main(String[] args) { + Stream stream = null; + } +} diff --git a/build-tools/tooling-api-impl/src/test/test-project/app/src/main/resources/actions/GenerateSettersAndGettersTest_template.java b/build-tools/tooling-api-impl/src/test/test-project/app/src/main/resources/actions/GenerateSettersAndGettersTest_template.java new file mode 100644 index 000000000..ea05a17d1 --- /dev/null +++ b/build-tools/tooling-api-impl/src/test/test-project/app/src/main/resources/actions/GenerateSettersAndGettersTest_template.java @@ -0,0 +1,11 @@ +package com.itsaky.androidide.test; + +public class GenerateSettersAndGettersTest_template { + + private String myString; + private int myInt; + + private boolean myBoolean; + + public static void main(String[] args) {} +} diff --git a/build-tools/tooling-api-impl/src/test/test-project/app/src/main/resources/android.jar b/build-tools/tooling-api-impl/src/test/test-project/app/src/main/resources/android.jar new file mode 100644 index 000000000..c909461ab Binary files /dev/null and b/build-tools/tooling-api-impl/src/test/test-project/app/src/main/resources/android.jar differ diff --git a/build-tools/tooling-api-impl/src/test/test-project/app/src/main/resources/completion/LambdaMembersCompletionTest_template.java b/build-tools/tooling-api-impl/src/test/test-project/app/src/main/resources/completion/LambdaMembersCompletionTest_template.java new file mode 100644 index 000000000..75c9d3a59 --- /dev/null +++ b/build-tools/tooling-api-impl/src/test/test-project/app/src/main/resources/completion/LambdaMembersCompletionTest_template.java @@ -0,0 +1,16 @@ +package com.itsaky.androidide.test; + +import java.util.function.Consumer; + +public class Main { + + private void testLambda () { + consume (e -> { + e.@@cursor@@ + }); + } + + private void consume (Consumer consumer) { + consumer.accept (new RuntimeException ("Hello world!")); + } +} diff --git a/build-tools/tooling-api-impl/src/test/test-project/app/src/main/resources/completion/LocalsCompletionTest_template.java b/build-tools/tooling-api-impl/src/test/test-project/app/src/main/resources/completion/LocalsCompletionTest_template.java new file mode 100644 index 000000000..c8edc5382 --- /dev/null +++ b/build-tools/tooling-api-impl/src/test/test-project/app/src/main/resources/completion/LocalsCompletionTest_template.java @@ -0,0 +1,11 @@ +package com.itsaky.androidide.test; + +public class Main { + public static void main(String[] args) { + final String aaString = args[0]; + final int aaInt = 0; + final float aaFloat = 0f; + final double aaDouble = 0.0; + a@@cursor@@ + } +} diff --git a/build-tools/tooling-api-impl/src/test/test-project/app/src/main/resources/completion/MembersCompletionTest_template.java b/build-tools/tooling-api-impl/src/test/test-project/app/src/main/resources/completion/MembersCompletionTest_template.java new file mode 100644 index 000000000..a1b779d20 --- /dev/null +++ b/build-tools/tooling-api-impl/src/test/test-project/app/src/main/resources/completion/MembersCompletionTest_template.java @@ -0,0 +1,8 @@ +package com.itsaky.androidide.test; + +public class Main { + public static void main(String[] args) { + String str = new String (); + str.@@cursor@@ + } +} diff --git a/build-tools/tooling-api-impl/src/test/test-project/app/src/main/resources/completion/StaticMembersCompletionTest_template.java b/build-tools/tooling-api-impl/src/test/test-project/app/src/main/resources/completion/StaticMembersCompletionTest_template.java new file mode 100644 index 000000000..05e9e4ec3 --- /dev/null +++ b/build-tools/tooling-api-impl/src/test/test-project/app/src/main/resources/completion/StaticMembersCompletionTest_template.java @@ -0,0 +1,7 @@ +package com.itsaky.androidide.test; + +public class Main { + public static void main(String[] args) { + String.@@cursor@@ + } +} diff --git a/build-tools/tooling-api-impl/src/test/test-project/app/src/main/resources/package/SourceFileTest_template.java b/build-tools/tooling-api-impl/src/test/test-project/app/src/main/resources/package/SourceFileTest_template.java new file mode 100644 index 000000000..26f944a7f --- /dev/null +++ b/build-tools/tooling-api-impl/src/test/test-project/app/src/main/resources/package/SourceFileTest_template.java @@ -0,0 +1,7 @@ +package com.itsaky.androidide.test; + +public class Main { + public static void main(String[] args) { + System.out.println("Hello World!"); + } +} diff --git a/build-tools/tooling-api-impl/src/test/test-project/app/src/main/resources/partial/PartialErrReparserTest_template.java b/build-tools/tooling-api-impl/src/test/test-project/app/src/main/resources/partial/PartialErrReparserTest_template.java new file mode 100644 index 000000000..5e2b62580 --- /dev/null +++ b/build-tools/tooling-api-impl/src/test/test-project/app/src/main/resources/partial/PartialErrReparserTest_template.java @@ -0,0 +1,9 @@ +package com.itsaky.androidide.lsp.java.partial; + +public class PartialReparserTest_template { + public static void main(String[] args) { + System.out.println("Hello World!"); + var str = ""; + str.; + } +} \ No newline at end of file diff --git a/build-tools/tooling-api-impl/src/test/test-project/app/src/main/resources/partial/PartialReparserTest_template.java b/build-tools/tooling-api-impl/src/test/test-project/app/src/main/resources/partial/PartialReparserTest_template.java new file mode 100644 index 000000000..52dd8e92d --- /dev/null +++ b/build-tools/tooling-api-impl/src/test/test-project/app/src/main/resources/partial/PartialReparserTest_template.java @@ -0,0 +1,8 @@ +package com.itsaky.androidide.lsp.java.partial; + +public class PartialReparserTest_template { + public static void main(String[] args) { + System.out.println("Hello World!"); + var klass = String.class + } +} \ No newline at end of file diff --git a/build-tools/tooling-api-impl/src/test/test-project/app/src/main/resources/selection/MethodBodySelectionExpansionTest_template.java b/build-tools/tooling-api-impl/src/test/test-project/app/src/main/resources/selection/MethodBodySelectionExpansionTest_template.java new file mode 100644 index 000000000..26f944a7f --- /dev/null +++ b/build-tools/tooling-api-impl/src/test/test-project/app/src/main/resources/selection/MethodBodySelectionExpansionTest_template.java @@ -0,0 +1,7 @@ +package com.itsaky.androidide.test; + +public class Main { + public static void main(String[] args) { + System.out.println("Hello World!"); + } +} diff --git a/build-tools/tooling-api-impl/src/test/test-project/app/src/main/resources/selection/SimpleSelectionExpansionTest_template.java b/build-tools/tooling-api-impl/src/test/test-project/app/src/main/resources/selection/SimpleSelectionExpansionTest_template.java new file mode 100644 index 000000000..e41cae253 --- /dev/null +++ b/build-tools/tooling-api-impl/src/test/test-project/app/src/main/resources/selection/SimpleSelectionExpansionTest_template.java @@ -0,0 +1,7 @@ +package com.itsaky.androidide.test; + +public class Main { + public static void main(String[] args) { + System.out.println(@@cursor@@"Hello World!"); + } +} \ No newline at end of file diff --git a/build-tools/tooling-api-impl/src/test/test-project/app/src/main/resources/selection/TrySelectionExpansionTest_template.java b/build-tools/tooling-api-impl/src/test/test-project/app/src/main/resources/selection/TrySelectionExpansionTest_template.java new file mode 100644 index 000000000..a0aff05a8 --- /dev/null +++ b/build-tools/tooling-api-impl/src/test/test-project/app/src/main/resources/selection/TrySelectionExpansionTest_template.java @@ -0,0 +1,13 @@ +package com.itsaky.androidide.test; + +public class Main { + public static void main(String[] args) { + try { + // something + } catch (Throwable th) { + // handle error + } finally { + // do something else + } + } +} diff --git a/build-tools/tooling-api-testing/src/main/java/com/itsaky/androidide/tooling/testing/ToolingApiTestLauncher.kt b/build-tools/tooling-api-testing/src/main/java/com/itsaky/androidide/tooling/testing/ToolingApiTestLauncher.kt index 75778d7a9..90c38160c 100644 --- a/build-tools/tooling-api-testing/src/main/java/com/itsaky/androidide/tooling/testing/ToolingApiTestLauncher.kt +++ b/build-tools/tooling-api-testing/src/main/java/com/itsaky/androidide/tooling/testing/ToolingApiTestLauncher.kt @@ -42,7 +42,10 @@ import java.util.concurrent.* */ class ToolingApiTestLauncher { - fun launchServer(client: IToolingApiClient = TestClient()): Pair { + fun launchServer( + client: IToolingApiClient = TestClient(), + implDir: String = "../tooling-api-impl" + ): Pair { val builder = ProcessBuilder( "java", @@ -53,7 +56,7 @@ class ToolingApiTestLauncher { "--add-opens", "java.base/java.io=ALL-UNNAMED", "-jar", - "../tooling-api-impl/build/libs/tooling-api-all.jar" + "$implDir/build/libs/tooling-api-all.jar" ) val androidHome = findAndroidHome() println("ANDROID_HOME=$androidHome") @@ -128,4 +131,4 @@ class ToolingApiTestLauncher { } } } -} \ No newline at end of file +} diff --git a/gradle/dependencies.gradle b/gradle/dependencies.gradle index faace0615..3c77685ea 100755 --- a/gradle/dependencies.gradle +++ b/gradle/dependencies.gradle @@ -1,6 +1,6 @@ ext { androidide = [ - javac: 'io.github.itsaky:nb-javac-android:17.0.0.2' + javac: 'io.github.itsaky:nb-javac-android:17.0.0.3-SNAPSHOT' ] common = [ diff --git a/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/JavaLanguageServer.java b/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/JavaLanguageServer.java index a2505e0ad..a4e409152 100644 --- a/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/JavaLanguageServer.java +++ b/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/JavaLanguageServer.java @@ -19,6 +19,7 @@ package com.itsaky.androidide.lsp.java; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.RestrictTo; import com.itsaky.androidide.eventbus.events.editor.DocumentChangeEvent; import com.itsaky.androidide.eventbus.events.editor.DocumentSelectedEvent; @@ -114,7 +115,8 @@ public class JavaLanguageServer implements ILanguageServer { return settings; } - protected JavaCompilerService getCompiler(Path file) { + @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) + public JavaCompilerService getCompiler(Path file) { if (!DocumentUtils.isJavaFile(file)) { return JavaCompilerService.NO_MODULE_COMPILER; } diff --git a/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/actions/diagnostics/AddImportAction.kt b/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/actions/diagnostics/AddImportAction.kt index 08cb5c53c..918c1b811 100644 --- a/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/actions/diagnostics/AddImportAction.kt +++ b/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/actions/diagnostics/AddImportAction.kt @@ -47,12 +47,12 @@ class AddImportAction() : BaseCodeAction() { override fun prepare(data: ActionData) { super.prepare(data) - if (!visible || !hasRequiredData(data, com.itsaky.androidide.lsp.models.DiagnosticItem::class.java)) { + if (!visible || !hasRequiredData(data, DiagnosticItem::class.java)) { markInvisible() return } - val diagnostic = data.get(com.itsaky.androidide.lsp.models.DiagnosticItem::class.java)!! + val diagnostic = data.get(DiagnosticItem::class.java)!! if (diagnosticCode != diagnostic.code || diagnostic.extra !is Diagnostic<*>) { markInvisible() return @@ -101,7 +101,7 @@ class AddImportAction() : BaseCodeAction() { @Suppress("UNCHECKED_CAST") val diagnostic = JavaDiagnosticUtils.asUnwrapper( - data.get(com.itsaky.androidide.lsp.models.DiagnosticItem::class.java)!!.extra as Diagnostic + data.get(DiagnosticItem::class.java)!!.extra as Diagnostic )!! val file = requireFile(data) val module = diff --git a/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/edits/ClassImportEditHandler.kt b/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/edits/ClassImportEditHandler.kt index 91a27538b..bea9a1ef1 100644 --- a/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/edits/ClassImportEditHandler.kt +++ b/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/edits/ClassImportEditHandler.kt @@ -19,8 +19,8 @@ package com.itsaky.androidide.lsp.java.edits import com.itsaky.androidide.lsp.java.compiler.JavaCompilerService import com.itsaky.androidide.lsp.java.utils.EditHelper -import com.itsaky.androidide.lsp.util.RewriteHelper import com.itsaky.androidide.lsp.models.CompletionItem +import com.itsaky.androidide.lsp.util.RewriteHelper import io.github.rosemoe.sora.widget.CodeEditor import java.nio.file.Path @@ -36,10 +36,10 @@ class ClassImportEditHandler(val imports: Set, file: Path) : IJavaEditHa override fun performEdits( compiler: JavaCompilerService, editor: CodeEditor, - completionItem: com.itsaky.androidide.lsp.models.CompletionItem + completionItem: CompletionItem ) { val className = completionItem.data!!.className val edits = EditHelper.addImportIfNeeded(compiler, file, imports, className) - com.itsaky.androidide.lsp.util.RewriteHelper.performEdits(edits, editor) + RewriteHelper.performEdits(edits, editor) } } diff --git a/lsp/java/src/test/java/com/itsaky/androidide/lsp/java/BaseJavaTest.kt b/lsp/java/src/test/java/com/itsaky/androidide/lsp/java/BaseJavaTest.kt deleted file mode 100644 index 577ad4226..000000000 --- a/lsp/java/src/test/java/com/itsaky/androidide/lsp/java/BaseJavaTest.kt +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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 . - */ - -package com.itsaky.androidide.lsp.java - -import com.itsaky.androidide.lsp.api.CursorDependentTest -import com.itsaky.androidide.lsp.api.ILanguageServer - -/** @author Akash Yadav */ -open class BaseJavaTest : CursorDependentTest() { - protected val mServer = JavaLanguageServerProvider.INSTANCE.server() - override fun getServer(): ILanguageServer = mServer -} diff --git a/lsp/java/src/test/java/com/itsaky/androidide/lsp/java/JavaLSPTest.kt b/lsp/java/src/test/java/com/itsaky/androidide/lsp/java/JavaLSPTest.kt new file mode 100644 index 000000000..16494cf74 --- /dev/null +++ b/lsp/java/src/test/java/com/itsaky/androidide/lsp/java/JavaLSPTest.kt @@ -0,0 +1,67 @@ +/* + * 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 . + */ + +package com.itsaky.androidide.lsp.java + +import com.itsaky.androidide.lsp.api.ILanguageServerRegistry +import com.itsaky.androidide.lsp.api.LSPTest +import com.itsaky.androidide.lsp.java.actions.AddImportTester +import com.itsaky.androidide.lsp.java.compiler.JavaCompilerService +import com.itsaky.androidide.lsp.java.partial.PartialReparserImplTester +import com.itsaky.androidide.lsp.java.providers.JavaCompletionProviderTester +import com.itsaky.androidide.lsp.java.providers.JavaSelectionProviderTester +import com.itsaky.androidide.projects.ProjectManager +import org.junit.Before +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.DEFAULT_VALUE_STRING) +open class JavaLSPTest : LSPTest() { + + protected val server by lazy { + ILanguageServerRegistry.getDefault().getServer(JavaLanguageServer.SERVER_ID) + as JavaLanguageServer + } + + @Before + fun setup() { + log.debug("Initializing project...") + initProjectIfNeeded() + } + + override fun registerServer() { + ILanguageServerRegistry.getDefault().register(JavaLanguageServer()) + } + + override fun getServerId() = JavaLanguageServer.SERVER_ID + + protected fun getCompiler() : JavaCompilerService { + return JavaCompilerProvider.get(ProjectManager.app) + } + + @Test + override fun test() { + AddImportTester().test() + PartialReparserImplTester().test() + JavaCompletionProviderTester().test() + JavaSelectionProviderTester().test() + } +} diff --git a/lsp/java/src/test/java/com/itsaky/androidide/lsp/java/JavaLanguageServerProvider.kt b/lsp/java/src/test/java/com/itsaky/androidide/lsp/java/JavaLanguageServerProvider.kt deleted file mode 100644 index 416cd33b3..000000000 --- a/lsp/java/src/test/java/com/itsaky/androidide/lsp/java/JavaLanguageServerProvider.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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 . - */ - -package com.itsaky.androidide.lsp.java - -import com.itsaky.androidide.lsp.api.ILanguageServer -import com.itsaky.androidide.lsp.api.LanguageServerProvider -import com.itsaky.androidide.lsp.java.JavaLanguageServer - -class JavaLanguageServerProvider : LanguageServerProvider() { - private val server: JavaLanguageServer = JavaLanguageServer() - override fun getServer(): ILanguageServer { - return server - } - - companion object { - @JvmStatic val INSTANCE: LanguageServerProvider = JavaLanguageServerProvider() - } -} diff --git a/lsp/java/src/test/java/com/itsaky/androidide/lsp/java/actions/AddImportTest.kt b/lsp/java/src/test/java/com/itsaky/androidide/lsp/java/actions/AddImportTester.kt similarity index 75% rename from lsp/java/src/test/java/com/itsaky/androidide/lsp/java/actions/AddImportTest.kt rename to lsp/java/src/test/java/com/itsaky/androidide/lsp/java/actions/AddImportTester.kt index a567ab8d6..8a69e982b 100644 --- a/lsp/java/src/test/java/com/itsaky/androidide/lsp/java/actions/AddImportTest.kt +++ b/lsp/java/src/test/java/com/itsaky/androidide/lsp/java/actions/AddImportTester.kt @@ -18,27 +18,24 @@ package com.itsaky.androidide.lsp.java.actions import com.google.common.truth.Truth.assertThat -import com.itsaky.androidide.lsp.java.BaseJavaTest +import com.itsaky.androidide.lsp.java.JavaLSPTest import com.itsaky.androidide.lsp.java.actions.diagnostics.AddImportAction -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 AddImportTest : BaseJavaTest() { +class AddImportTester : JavaLSPTest() { + + override fun test() { + addImport() + } @Suppress("UNCHECKED_CAST") - @Test - fun testAddImport() { + fun addImport() { openFile("AddImportAction") val diagnostic = - mServer.analyze(file!!).diagnostics.first { it.code == "compiler.err.cant.resolve.location" } + server.analyze(file!!).diagnostics.first { it.code == "compiler.err.cant.resolve.location" } val file = this.file!!.toFile() - val data = createActionData(diagnostic, file, this.file!!, this.mServer) + val data = createActionData(diagnostic, file, this.file!!, this.server) val action = AddImportAction() action.prepare(data) diff --git a/lsp/java/src/test/java/com/itsaky/androidide/lsp/java/partial/PartialReparserImplTest.kt b/lsp/java/src/test/java/com/itsaky/androidide/lsp/java/partial/PartialReparserImplTester.kt similarity index 81% rename from lsp/java/src/test/java/com/itsaky/androidide/lsp/java/partial/PartialReparserImplTest.kt rename to lsp/java/src/test/java/com/itsaky/androidide/lsp/java/partial/PartialReparserImplTester.kt index 5fbeebcbf..9ad78fec0 100644 --- a/lsp/java/src/test/java/com/itsaky/androidide/lsp/java/partial/PartialReparserImplTest.kt +++ b/lsp/java/src/test/java/com/itsaky/androidide/lsp/java/partial/PartialReparserImplTester.kt @@ -18,14 +18,13 @@ package com.itsaky.androidide.lsp.java.partial import com.google.common.truth.Truth.assertThat -import com.itsaky.androidide.lsp.java.BaseJavaTest -import com.itsaky.androidide.lsp.java.JavaLanguageServer +import com.itsaky.androidide.eventbus.events.editor.ChangeType.INSERT +import com.itsaky.androidide.eventbus.events.editor.DocumentChangeEvent +import com.itsaky.androidide.lsp.java.JavaLSPTest import com.itsaky.androidide.lsp.java.compiler.SourceFileObject import com.itsaky.androidide.lsp.java.models.CompilationRequest import com.itsaky.androidide.lsp.java.models.PartialReparseRequest import com.itsaky.androidide.lsp.java.visitors.PrintingVisitor -import com.itsaky.androidide.lsp.models.ChangeType.INSERT -import com.itsaky.androidide.lsp.models.DocumentChangeEvent import com.itsaky.androidide.models.Range import com.sun.source.tree.ExpressionStatementTree import com.sun.source.tree.LiteralTree @@ -36,31 +35,27 @@ import com.sun.tools.javac.tree.JCTree.JCMethodInvocation import com.sun.tools.javac.tree.JCTree.JCVariableDecl import com.sun.tools.javac.tree.TreeScanner import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner -import org.robolectric.annotation.Config import javax.lang.model.type.ArrayType /** @author Akash Yadav */ -@RunWith(RobolectricTestRunner::class) -@Config(manifest = Config.NONE) -class PartialReparserImplTest : BaseJavaTest() { - - // TODO Move this to project ':build-tools:javac-utils' - val jls = mServer as JavaLanguageServer +class PartialReparserImplTester : JavaLSPTest() { @Test - fun parseMethod() { + override fun test() { + parseMethod() + testSimpleErrorneousStatement() + } + + private fun parseMethod() { openFile("PartialReparserTest") - jls.compiler.compile(file).run { task -> + getCompiler().compile(file).run { task -> AssertingScanner().scan(task.root() as JCCompilationUnit) } } - @Test - fun testSimpleErrorneousStatement() { + private fun testSimpleErrorneousStatement() { openFile("PartialErrReparserTest") - jls.compiler + getCompiler() .compile( CompilationRequest( listOf(SourceFileObject(file)), @@ -68,22 +63,23 @@ class PartialReparserImplTest : BaseJavaTest() { ) ) .run { PrintingVisitor().scan(it.root() as JCCompilationUnit) } - jls.onContentChange( - com.itsaky.androidide.lsp.models.DocumentChangeEvent( + dispatchEvent( + DocumentChangeEvent( file!!, contents!!.insert(192, "trim().").toString(), 2, INSERT, "trim().".length, - com.itsaky.androidide.models.Range.NONE + Range.NONE ) ) - jls.compiler.compile( - CompilationRequest( - listOf(SourceFileObject(file)), - PartialReparseRequest(179, contents.toString()) + getCompiler() + .compile( + CompilationRequest( + listOf(SourceFileObject(file)), + PartialReparseRequest(179, contents.toString()) + ) ) - ) } override fun openFile(fileName: String) { diff --git a/lsp/java/src/test/java/com/itsaky/androidide/lsp/java/providers/JavaCompletionProviderTest.kt b/lsp/java/src/test/java/com/itsaky/androidide/lsp/java/providers/JavaCompletionProviderTester.kt similarity index 72% rename from lsp/java/src/test/java/com/itsaky/androidide/lsp/java/providers/JavaCompletionProviderTest.kt rename to lsp/java/src/test/java/com/itsaky/androidide/lsp/java/providers/JavaCompletionProviderTester.kt index 2d5965c08..cf17497bd 100644 --- a/lsp/java/src/test/java/com/itsaky/androidide/lsp/java/providers/JavaCompletionProviderTest.kt +++ b/lsp/java/src/test/java/com/itsaky/androidide/lsp/java/providers/JavaCompletionProviderTester.kt @@ -17,21 +17,20 @@ package com.itsaky.androidide.lsp.java.providers import com.google.common.truth.Truth.assertThat -import com.itsaky.androidide.lsp.java.BaseJavaTest +import com.itsaky.androidide.lsp.java.JavaLSPTest import com.itsaky.androidide.lsp.models.CompletionParams -import com.itsaky.androidide.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.DEFAULT_VALUE_STRING) -class JavaCompletionProviderTest : BaseJavaTest() { +class JavaCompletionProviderTester : JavaLSPTest() { - @Test - fun testLocals() { + override fun test() { + locals() + members() + staticAccess() + lambdaVariableMemberAccess() + } + + fun locals() { openFile("LocalsCompletionTest") val pos = cursorPosition() @@ -39,8 +38,7 @@ class JavaCompletionProviderTest : BaseJavaTest() { assertThat(items).containsAtLeast("aaString", "aaInt", "aaFloat", "aaDouble", "args") } - @Test - fun testMembers() { + fun members() { // Complete members of String openFile("MembersCompletionTest") @@ -50,8 +48,7 @@ class JavaCompletionProviderTest : BaseJavaTest() { .containsAtLeast("getClass", "toLowerCase", "toUpperCase", "substring", "charAt") } - @Test - fun testLambdaVariableMemberAccess() { + fun lambdaVariableMemberAccess() { // Complete members of Throwable openFile("LambdaMembersCompletionTest") @@ -60,8 +57,7 @@ class JavaCompletionProviderTest : BaseJavaTest() { assertThat(items).containsAtLeast("getMessage", "getCause", "getStackTrace", "printStackTrace") } - @Test - fun testStaticAccess() { + fun staticAccess() { // Complete static members of String openFile("StaticMembersCompletionTest") @@ -76,9 +72,8 @@ class JavaCompletionProviderTest : BaseJavaTest() { } private fun completionTitles(pos: com.itsaky.androidide.models.Position): List { - return mServer.completionProvider - .complete(com.itsaky.androidide.lsp.models.CompletionParams(pos, file!!).apply { prefix = "" }) - .items - .map { it.label } + return server.complete(CompletionParams(pos, file!!).apply { prefix = "" }).items.map { + it.label + } } } diff --git a/lsp/java/src/test/java/com/itsaky/androidide/lsp/java/providers/JavaSelectionProviderTest.kt b/lsp/java/src/test/java/com/itsaky/androidide/lsp/java/providers/JavaSelectionProviderTest.kt deleted file mode 100644 index 52ca011e8..000000000 --- a/lsp/java/src/test/java/com/itsaky/androidide/lsp/java/providers/JavaSelectionProviderTest.kt +++ /dev/null @@ -1,105 +0,0 @@ -/* - * 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 . - */ -package com.itsaky.androidide.lsp.java.providers - -import com.google.common.truth.Truth.assertThat -import com.itsaky.androidide.lsp.java.BaseJavaTest -import com.itsaky.androidide.lsp.models.ChangeType.NEW_TEXT -import com.itsaky.androidide.lsp.models.DocumentChangeEvent -import com.itsaky.androidide.lsp.models.ExpandSelectionParams -import com.itsaky.androidide.models.Position -import com.itsaky.androidide.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 - -/** @author Akash Yadav */ -@RunWith(RobolectricTestRunner::class) -@Config(manifest = Config.NONE) -class JavaSelectionProviderTest : BaseJavaTest() { - - @Before - fun init() { - LOG.debug("Initializing JavaSelectionProviderTest") - } - - @Test - fun testSimpleSelectionExpansion() { - openFile("SimpleSelectionExpansionTest") - cursor = requireCursor() - deleteCursorText() - mServer.documentHandler.onContentChange( - com.itsaky.androidide.lsp.models.DocumentChangeEvent(file!!, contents.toString(), 1, NEW_TEXT, 0, com.itsaky.androidide.models.Range.NONE) - ) - - val range = findRange() - val expanded = mServer.expandSelection(com.itsaky.androidide.lsp.models.ExpandSelectionParams(file!!, range)) - - assertThat(expanded).isEqualTo(com.itsaky.androidide.models.Range(com.itsaky.androidide.models.Position(4, 27), com.itsaky.androidide.models.Position(4, 41))) - } - - @Test - fun testMethodSelection() { - openFile("MethodBodySelectionExpansionTest") - - val start = com.itsaky.androidide.models.Position(3, 43) - val end = com.itsaky.androidide.models.Position(5, 5) - val range = com.itsaky.androidide.models.Range(start, end) - - val expanded = mServer.expandSelection(com.itsaky.androidide.lsp.models.ExpandSelectionParams(file!!, range)) - assertThat(expanded).isEqualTo(com.itsaky.androidide.models.Range(com.itsaky.androidide.models.Position(3, 4), end)) - } - - @Test - fun testTryCatchSelection() { - openFile("TrySelectionExpansionTest") - - // Test expand selection if catch block is selected - val start = com.itsaky.androidide.models.Position(7, 10) - val end = com.itsaky.androidide.models.Position(8, 9) - val range = com.itsaky.androidide.models.Range(start, end) - - val expanded = mServer.expandSelection(com.itsaky.androidide.lsp.models.ExpandSelectionParams(file!!, range)) - assertThat(expanded).isEqualTo(com.itsaky.androidide.models.Range(com.itsaky.androidide.models.Position(4, 8), com.itsaky.androidide.models.Position(10, 9))) - } - - @Test - fun testTryFinallySelection() { - openFile("TrySelectionExpansionTest") - - // Test expand selection if catch block is selected - val start = com.itsaky.androidide.models.Position(8, 18) - val end = com.itsaky.androidide.models.Position(10, 9) - val range = com.itsaky.androidide.models.Range(start, end) - - val expanded = mServer.expandSelection(com.itsaky.androidide.lsp.models.ExpandSelectionParams(file!!, range)) - assertThat(expanded).isEqualTo(com.itsaky.androidide.models.Range(com.itsaky.androidide.models.Position(4, 8), com.itsaky.androidide.models.Position(10, 9))) - } - - private fun findRange(): com.itsaky.androidide.models.Range { - val pos = Content(contents!!).indexer.getCharPosition(cursor) - val position = com.itsaky.androidide.models.Position(pos.line, pos.column, pos.index) - return com.itsaky.androidide.models.Range(position, position) - } - - override fun openFile(fileName: String) { - super.openFile("selection/${fileName}") - } -} diff --git a/lsp/java/src/test/java/com/itsaky/androidide/lsp/java/providers/JavaSelectionProviderTester.kt b/lsp/java/src/test/java/com/itsaky/androidide/lsp/java/providers/JavaSelectionProviderTester.kt new file mode 100644 index 000000000..b250eb749 --- /dev/null +++ b/lsp/java/src/test/java/com/itsaky/androidide/lsp/java/providers/JavaSelectionProviderTester.kt @@ -0,0 +1,94 @@ +/* + * 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 . + */ +package com.itsaky.androidide.lsp.java.providers + +import com.google.common.truth.Truth.assertThat +import com.itsaky.androidide.eventbus.events.editor.ChangeType.NEW_TEXT +import com.itsaky.androidide.eventbus.events.editor.DocumentChangeEvent +import com.itsaky.androidide.lsp.java.JavaLSPTest +import com.itsaky.androidide.lsp.models.ExpandSelectionParams +import com.itsaky.androidide.models.Position +import com.itsaky.androidide.models.Range +import io.github.rosemoe.sora.text.Content + +/** @author Akash Yadav */ +class JavaSelectionProviderTester : JavaLSPTest() { + + override fun test() { + testSimpleSelectionExpansion() + testMethodSelection() + testTryCatchSelection() + testTryFinallySelection() + } + + private fun testSimpleSelectionExpansion() { + openFile("SimpleSelectionExpansionTest") + cursor = requireCursor() + deleteCursorText() + dispatchEvent(DocumentChangeEvent(file!!, contents.toString(), 1, NEW_TEXT, 0, Range.NONE)) + + val range = findRange() + val expanded = server.expandSelection(ExpandSelectionParams(file!!, range)) + + assertThat(expanded).isEqualTo(Range(Position(4, 27), Position(4, 41))) + } + + private fun testMethodSelection() { + openFile("MethodBodySelectionExpansionTest") + + val start = Position(3, 43) + val end = Position(5, 5) + val range = Range(start, end) + + val expanded = server.expandSelection(ExpandSelectionParams(file!!, range)) + assertThat(expanded).isEqualTo(Range(Position(3, 4), end)) + } + + private fun testTryCatchSelection() { + 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 = server.expandSelection(ExpandSelectionParams(file!!, range)) + assertThat(expanded).isEqualTo(Range(Position(4, 8), Position(10, 9))) + } + + private fun testTryFinallySelection() { + 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 = server.expandSelection(ExpandSelectionParams(file!!, range)) + assertThat(expanded).isEqualTo(Range(Position(4, 8), Position(10, 9))) + } + + private fun findRange(): Range { + val pos = Content(contents!!).indexer.getCharPosition(cursor) + val position = Position(pos.line, pos.column, pos.index) + return Range(position, position) + } + + override fun openFile(fileName: String) { + super.openFile("selection/${fileName}") + } +} diff --git a/lsp/testing/build.gradle b/lsp/testing/build.gradle index 160b70866..8fe3f0f85 100644 --- a/lsp/testing/build.gradle +++ b/lsp/testing/build.gradle @@ -51,6 +51,8 @@ dependencies { implementation project (':lsp:api') implementation project (':actions') implementation project (':common') + implementation project (':build-tools:eventbus-android') + implementation project (':build-tools:tooling-api-testing') implementation common.editor implementation tests.junit implementation tests.google_truth diff --git a/lsp/testing/src/main/java/com/itsaky/androidide/lsp/api/BaseLanguageServerTest.kt b/lsp/testing/src/main/java/com/itsaky/androidide/lsp/api/BaseLanguageServerTest.kt deleted file mode 100644 index f33f412c2..000000000 --- a/lsp/testing/src/main/java/com/itsaky/androidide/lsp/api/BaseLanguageServerTest.kt +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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 . - */ -package com.itsaky.androidide.lsp.api - -import android.content.Context -import com.itsaky.androidide.actions.ActionData -import com.itsaky.androidide.lsp.models.DocumentOpenEvent -import org.robolectric.RuntimeEnvironment -import java.nio.file.Path - -/** @author Akash Yadav */ -abstract class BaseLanguageServerTest { - protected var file: Path? = null - protected var contents: StringBuilder? = null - - open fun openFile(fileName: String) { - file = FileProvider.sourceFile(fileName) - contents = FileProvider.contents(file!!) - - getServer().documentHandler.onFileOpened(com.itsaky.androidide.lsp.models.DocumentOpenEvent(file!!, contents.toString(), 0)) - } - - protected open fun createActionData(vararg values: Any): ActionData { - val data = ActionData() - - data.put(Context::class.java, RuntimeEnvironment.getApplication()) - for (value in values) { - if (value is Path) { - data.put(Path::class.java, value) - } else { - data.put(value::javaClass.get(), value) - } - } - - return data - } - - protected abstract fun getServer(): ILanguageServer -} diff --git a/lsp/testing/src/main/java/com/itsaky/androidide/lsp/api/CursorDependentTest.kt b/lsp/testing/src/main/java/com/itsaky/androidide/lsp/api/CursorDependentTest.kt deleted file mode 100644 index 8c1e745ca..000000000 --- a/lsp/testing/src/main/java/com/itsaky/androidide/lsp/api/CursorDependentTest.kt +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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 . - */ -package com.itsaky.androidide.lsp.api - -import com.google.common.truth.Truth.assertThat -import com.itsaky.androidide.lsp.models.ChangeType.NEW_TEXT -import com.itsaky.androidide.lsp.models.DocumentChangeEvent -import com.itsaky.androidide.models.Position -import com.itsaky.androidide.models.Range -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 { - this.cursor = super.contents!!.indexOf(cursorText) - assertThat(cursor).isGreaterThan(-1) - return cursor - } - - fun deleteCursorText() { - contents!!.delete(this.cursor, this.cursor + cursorText.length) - assertThat(contents!!.indexOf(cursorText)).isEqualTo(-1) - - // As the content has been changed, we have to - // Update the content in language server - getServer().documentHandler.onContentChange(com.itsaky.androidide.lsp.models.DocumentChangeEvent(file!!, contents!!.toString(), 1, NEW_TEXT, 0, com.itsaky.androidide.models.Range.NONE)) - } - - fun cursorPosition(): com.itsaky.androidide.models.Position { - return cursorPosition(true) - } - - fun cursorPosition(deleteCursorText: Boolean): com.itsaky.androidide.models.Position { - requireCursor() - - if (deleteCursorText) { - deleteCursorText() - } - - val pos = Content(contents!!).indexer.getCharPosition(cursor) - return com.itsaky.androidide.models.Position(pos.line, pos.column, pos.index) - } -} diff --git a/lsp/testing/src/main/java/com/itsaky/androidide/lsp/api/FileProvider.kt b/lsp/testing/src/main/java/com/itsaky/androidide/lsp/api/FileProvider.kt index c6097d326..7263064c6 100644 --- a/lsp/testing/src/main/java/com/itsaky/androidide/lsp/api/FileProvider.kt +++ b/lsp/testing/src/main/java/com/itsaky/androidide/lsp/api/FileProvider.kt @@ -16,10 +16,7 @@ */ package com.itsaky.androidide.lsp.api -import com.google.common.truth.Truth.assertThat -import org.junit.Test import java.io.File -import java.nio.file.Files import java.nio.file.Path import java.nio.file.Paths import kotlin.io.path.readText @@ -30,34 +27,6 @@ import kotlin.io.path.readText * @author Akash Yadav */ class FileProvider { - @Test - fun testPath() { - val path = sourceFile("SourceFileTest") - assertThat(Files.exists(path)).isTrue() - assertThat(path.fileName.toString()).isEqualTo("SourceFileTest.java") - } - - @Test - fun testNested() { - val path = sourceFile("package/SourceFileTest") - assertThat(Files.exists(path)).isTrue() - assertThat(path.fileName.toString()).isEqualTo("SourceFileTest.java") - } - - @Test - fun testExtension() { - val folder = File(".").canonicalFile - - assertThat(extension).isNotEmpty() - assertThat(extension) - .isEqualTo( - when (folder.name) { - "xml" -> "xml" - "java" -> "java" - else -> "" - } - ) - } companion object { @@ -71,6 +40,11 @@ class FileProvider { } } + @JvmStatic + fun implModule(): Path = + Paths.get(System.getProperty("user.dir")!!).resolve("../../build-tools/tooling-api-impl") + @JvmStatic fun projectRoot(): Path = implModule().resolve("src/test/test-project") + /** * Get the path to the 'resources' directory. * @@ -78,7 +52,7 @@ class FileProvider { */ @JvmStatic fun resources(): Path { - return Paths.get(".", "src", "test", "resources") + return projectRoot().resolve("app/src/main/resources") } /** diff --git a/lsp/testing/src/main/java/com/itsaky/androidide/lsp/api/LSPTest.kt b/lsp/testing/src/main/java/com/itsaky/androidide/lsp/api/LSPTest.kt new file mode 100644 index 000000000..94b4e16fc --- /dev/null +++ b/lsp/testing/src/main/java/com/itsaky/androidide/lsp/api/LSPTest.kt @@ -0,0 +1,152 @@ +/* + * 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 . + */ + +package com.itsaky.androidide.lsp.api + +import android.content.Context +import com.google.common.truth.Truth.assertThat +import com.itsaky.androidide.actions.ActionData +import com.itsaky.androidide.eventbus.events.editor.ChangeType.NEW_TEXT +import com.itsaky.androidide.eventbus.events.editor.DocumentChangeEvent +import com.itsaky.androidide.eventbus.events.editor.DocumentOpenEvent +import com.itsaky.androidide.lsp.api.util.ReflectiveLogListener +import com.itsaky.androidide.models.Range +import com.itsaky.androidide.projects.ProjectManager +import com.itsaky.androidide.tooling.api.IProject +import com.itsaky.androidide.tooling.api.IToolingApiServer +import com.itsaky.androidide.tooling.api.messages.InitializeProjectMessage +import com.itsaky.androidide.tooling.testing.ToolingApiTestLauncher +import com.itsaky.androidide.utils.Environment +import com.itsaky.androidide.utils.ILogger +import com.itsaky.androidide.utils.ILogger.Priority +import io.github.rosemoe.sora.text.Content +import java.nio.file.Path +import java.util.* +import kotlin.io.path.pathString +import org.greenrobot.eventbus.EventBus +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.RuntimeEnvironment +import org.robolectric.annotation.Config +import java.io.File + +/** + * Runs tests for a language server. + * + * @author Akash Yadav + */ +@RunWith(RobolectricTestRunner::class) +@Config(manifest = Config.DEFAULT_VALUE_STRING) +abstract class LSPTest { + + protected lateinit var toolingServer: IToolingApiServer + protected lateinit var toolingProject: IProject + protected var cursor: Int = -1 + private val cursorText = "@@cursor@@" + protected var file: Path? = null + protected var contents: StringBuilder? = null + + protected val log = ILogger.newInstance(javaClass.simpleName) + + companion object { + @JvmStatic + protected var isInitialized: Boolean = false + } + + protected open fun initProjectIfNeeded() { + if (isInitialized) { + return + } + + val (server, project) = + ToolingApiTestLauncher().launchServer(implDir = FileProvider.implModule().pathString) + this.toolingProject = project + this.toolingServer = server + + server + .initialize(InitializeProjectMessage(FileProvider.projectRoot().toFile().absolutePath)) + .get() + + Environment.ANDROID_JAR = FileProvider.resources().resolve("android.jar").toFile() + Environment.JAVA_HOME = File(System.getProperty("java.home")!!) + registerServer() + ProjectManager.register() + ProjectManager.setupProject(project) + ProjectManager.notifyProjectUpdate() + isInitialized = true + } + + protected abstract fun registerServer() + protected abstract fun getServerId(): String + abstract fun test() + + protected fun requireCursor(): Int { + this.cursor = contents!!.indexOf(cursorText) + assertThat(cursor).isGreaterThan(-1) + return cursor + } + + protected fun deleteCursorText() { + contents!!.delete(this.cursor, this.cursor + cursorText.length) + assertThat(contents!!.indexOf(cursorText)).isEqualTo(-1) + + // As the content has been changed, we have to + // Update the content in language server + dispatchEvent(DocumentChangeEvent(file!!, contents.toString(), 1, NEW_TEXT, 0, Range.NONE)) + } + + protected fun cursorPosition(): com.itsaky.androidide.models.Position { + return cursorPosition(true) + } + + protected fun cursorPosition(deleteCursorText: Boolean): com.itsaky.androidide.models.Position { + requireCursor() + + if (deleteCursorText) { + deleteCursorText() + } + + val pos = Content(contents!!).indexer.getCharPosition(cursor) + return com.itsaky.androidide.models.Position(pos.line, pos.column, pos.index) + } + + protected open fun openFile(fileName: String) { + file = FileProvider.sourceFile(fileName).normalize() + contents = FileProvider.contents(file!!) + + dispatchEvent(DocumentOpenEvent(file!!, contents.toString(), 0)) + } + + protected open fun dispatchEvent(event: Any) { + EventBus.getDefault().post(event) + } + + protected open fun createActionData(vararg values: Any): ActionData { + val data = ActionData() + + data.put(Context::class.java, RuntimeEnvironment.getApplication()) + for (value in values) { + if (value is Path) { + data.put(Path::class.java, value) + } else { + data.put(value::javaClass.get(), value) + } + } + + return data + } +} diff --git a/lsp/testing/src/main/java/com/itsaky/androidide/lsp/api/LanguageServerProvider.kt b/lsp/testing/src/main/java/com/itsaky/androidide/lsp/api/LanguageServerProvider.kt deleted file mode 100644 index d1e32c722..000000000 --- a/lsp/testing/src/main/java/com/itsaky/androidide/lsp/api/LanguageServerProvider.kt +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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 . - */ -package com.itsaky.androidide.lsp.api - -import com.google.common.truth.Truth.assertThat -import com.itsaky.androidide.utils.Environment -import com.itsaky.androidide.lsp.api.FileProvider.Companion.resources -import com.itsaky.androidide.lsp.models.InitializeParams -import org.jetbrains.annotations.Contract -import java.io.File - -/** - * Provides instance to the java language server to test classes. - * - * @author Akash Yadav - */ -abstract class LanguageServerProvider { - - fun server(): ILanguageServer { - - // TODO replace with android.jar -// if (Environment.COMPILER_MODULE == null) { -// val javaHome = System.getProperty("java.home") -// assertThat(javaHome).isNotEmpty() -// Environment.COMPILER_MODULE = File(javaHome) -// } - - initIfNecessary() - - return getServer() - } - - protected abstract fun getServer(): ILanguageServer - - protected open fun initIfNecessary() { - if (!getServer().isInitialized) { - getServer().initialize(createInitParams()) - } - } - - @Contract(" -> new") - private fun createInitParams(): com.itsaky.androidide.lsp.models.InitializeParams { - return com.itsaky.androidide.lsp.models.InitializeParams(mutableSetOf(resources())) - } -} diff --git a/lsp/testing/src/main/java/com/itsaky/androidide/lsp/api/LoggingTest.kt b/lsp/testing/src/main/java/com/itsaky/androidide/lsp/api/LoggingTest.kt deleted file mode 100644 index bf84a6144..000000000 --- a/lsp/testing/src/main/java/com/itsaky/androidide/lsp/api/LoggingTest.kt +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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 . - */ -package com.itsaky.androidide.lsp.api - -import com.itsaky.androidide.utils.ILogger -import com.itsaky.androidide.utils.ILogger.Priority -import com.itsaky.androidide.lsp.api.util.ReflectiveLogListener -import java.util.* - -/** - * This class provides an efficient way to log messages. - * - * @author Akash Yadav - */ -abstract class LoggingTest : BaseLanguageServerTest() { - companion object { - private var logListener: ReflectiveLogListener? = null - - init { - logListener = ReflectiveLogListener(LoggingTest::class.java) - ILogger.addLogListener(logListener) - } - - @Suppress("unused") - @JvmStatic - fun log(priority: Priority, tag: String, message: String) { - System.out.printf(Locale.ROOT, "%-8s%-26s%-20s", priority, tag, message) - println() - } - } - - @Suppress("PropertyName") @JvmField protected val LOG = ILogger.newInstance(javaClass.simpleName) -} diff --git a/lsp/testing/src/test/java/com/itsaky/androidide/lsp/api/FileProviderTest.kt b/lsp/testing/src/test/java/com/itsaky/androidide/lsp/api/FileProviderTest.kt new file mode 100644 index 000000000..9a7ddbd3b --- /dev/null +++ b/lsp/testing/src/test/java/com/itsaky/androidide/lsp/api/FileProviderTest.kt @@ -0,0 +1,61 @@ +/* + * 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 . + */ + +package com.itsaky.androidide.lsp.api + +import com.google.common.truth.Truth +import java.io.File +import java.nio.file.Files +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 FileProviderTest { + + @Test + fun testPath() { + val path = FileProvider.sourceFile("SourceFileTest") + Truth.assertThat(Files.exists(path)).isTrue() + Truth.assertThat(path.fileName.toString()).isEqualTo("SourceFileTest.java") + } + + @Test + fun testNested() { + val path = FileProvider.sourceFile("package/SourceFileTest") + Truth.assertThat(Files.exists(path)).isTrue() + Truth.assertThat(path.fileName.toString()).isEqualTo("SourceFileTest.java") + } + + @Test + fun testExtension() { + val folder = File(".").canonicalFile + + Truth.assertThat(FileProvider.extension).isNotEmpty() + Truth.assertThat(FileProvider.extension) + .isEqualTo( + when (folder.name) { + "xml" -> "xml" + "java" -> "java" + else -> "" + } + ) + } +} diff --git a/lsp/xml/src/test/java/com/itsaky/androidide/lsp/xml/XmlLanguageServerProvider.kt b/lsp/xml/src/test/java/com/itsaky/androidide/lsp/xml/XmlLanguageServerProvider.kt index 483353bc1..4c41b04f9 100644 --- a/lsp/xml/src/test/java/com/itsaky/androidide/lsp/xml/XmlLanguageServerProvider.kt +++ b/lsp/xml/src/test/java/com/itsaky/androidide/lsp/xml/XmlLanguageServerProvider.kt @@ -18,8 +18,6 @@ package com.itsaky.androidide.lsp.xml import com.itsaky.androidide.lsp.api.ILanguageServer -import com.itsaky.androidide.lsp.api.LanguageServerProvider -import com.itsaky.androidide.lsp.xml.XMLLanguageServer import com.itsaky.sdk.SDKInfo import org.robolectric.RuntimeEnvironment diff --git a/lsp/xml/src/test/java/com/itsaky/androidide/lsp/xml/providers/XMLCompletionProviderTest.kt b/lsp/xml/src/test/java/com/itsaky/androidide/lsp/xml/providers/XMLCompletionProviderTest.kt index 8b9856365..118985c8a 100644 --- a/lsp/xml/src/test/java/com/itsaky/androidide/lsp/xml/providers/XMLCompletionProviderTest.kt +++ b/lsp/xml/src/test/java/com/itsaky/androidide/lsp/xml/providers/XMLCompletionProviderTest.kt @@ -72,7 +72,7 @@ class XMLCompletionProviderTest : BaseXMLTest() { private fun complete(): Pair> { val createCompletionParams = createCompletionParams() - val result = mServer.completionProvider.complete(createCompletionParams) + val result = mServer.complete(createCompletionParams) return result.isIncomplete to result.items .filter { it.label != null }