Skip to content

Commit

Permalink
Make it possible to write tests
Browse files Browse the repository at this point in the history
  • Loading branch information
jbartok committed Jan 27, 2025
1 parent 63ee5c8 commit 38e1d64
Show file tree
Hide file tree
Showing 8 changed files with 218 additions and 13 deletions.
4 changes: 2 additions & 2 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
# https://docs.gradle.org/current/userguide/platforms.html#sub::toml-dependencies-format

[versions]
gradle-tooling = "8.12-20241112084018+0000"
declarative-dsl = "8.12-20241112084018+0000"
gradle-tooling = "8.13-20250127002038+0000"
declarative-dsl = "8.13-20250121001720+0000"
detekt = "1.23.6"
lsp4j = "0.23.1"
logback = "1.5.6"
Expand Down
1 change: 1 addition & 0 deletions lsp/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ dependencies {
implementation(libs.gradle.declarative.dsl.tooling.models)

testImplementation(libs.mockk)
testImplementation(libs.gradle.tooling.api)
}

detekt {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ class DeclarativeLanguageServer : LanguageServer, LanguageClientAware {

LOGGER.info("Fetching declarative model for workspace folder: $workspaceFolderFile")
TapiConnectionHandler(workspaceFolderFile).let {
val declarativeResources = it.getDomPrequisites()
val declarativeResources = it.getDeclarativeResources()

// Create services shared between the LSP services
val documentStore = VersionedDocumentStore()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@

package org.gradle.declarative.lsp

import org.eclipse.lsp4j.ClientCapabilities
import org.eclipse.lsp4j.ClientInfo
import org.eclipse.lsp4j.CodeAction
import org.eclipse.lsp4j.CodeActionParams
import org.eclipse.lsp4j.Command
Expand All @@ -42,7 +40,14 @@ import org.eclipse.lsp4j.SignatureInformation
import org.eclipse.lsp4j.jsonrpc.messages.Either
import org.eclipse.lsp4j.services.LanguageClient
import org.eclipse.lsp4j.services.TextDocumentService
import org.gradle.declarative.dsl.schema.*
import org.gradle.declarative.dsl.schema.AnalysisSchema
import org.gradle.declarative.dsl.schema.DataClass
import org.gradle.declarative.dsl.schema.DataParameter
import org.gradle.declarative.dsl.schema.DataType
import org.gradle.declarative.dsl.schema.DataTypeRef
import org.gradle.declarative.dsl.schema.EnumClass
import org.gradle.declarative.dsl.schema.FunctionSemantics
import org.gradle.declarative.dsl.schema.SchemaFunction
import org.gradle.declarative.lsp.build.model.DeclarativeResourcesModel
import org.gradle.declarative.lsp.extension.indexBasedOverlayResultFromDocuments
import org.gradle.declarative.lsp.extension.toLspRange
Expand Down Expand Up @@ -168,12 +173,13 @@ class DeclarativeTextDocumentService : TextDocumentService {
val completions = params?.let { param ->
val uri = URI(param.textDocument.uri)
withDom(uri) { dom, schema, _ ->
dom.document.visit(
val bestFittingNode = dom.document.visit(
BestFittingNodeVisitor(
params.position,
DeclarativeDocument.DocumentNode.ElementNode::class
)
).bestFittingNode
bestFittingNode
?.getDataClass(dom.overlayResolutionContainer)
.let { it ?: schema.topLevelReceiverType }
.let { dataClass ->
Expand Down Expand Up @@ -411,7 +417,8 @@ private fun computeCompletionInsertText(
}

/**
* Computes a [placeholder](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#placeholders) based on the given data type.
* Computes a [placeholder](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#placeholders)
* based on the given data type.
*
* If there is a specific placeholder for the given data type, it will be used.
* Otherwise, a simple indexed will be used
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ private val LOGGER = LoggerFactory.getLogger(TapiConnectionHandler::class.java)

class TapiConnectionHandler(val projectRoot: File): ProgressListener {

fun getDomPrequisites(): DeclarativeResourcesModel {
fun getDeclarativeResources(): DeclarativeResourcesModel {
var connection: ProjectConnection? = null
try {
connection = GradleConnector
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,7 @@ fun <T : DocumentVisitor> DeclarativeDocument.visit(visitor: T): T {
is DeclarativeDocument.ValueNode.ValueFactoryNode -> visitor.visitValueFactoryNode(node)
else -> {}
}
}
is DeclarativeDocument.DocumentNode -> {
} else -> {
visitor.visitDocumentNode(node)
when (node) {
is DeclarativeDocument.DocumentNode.ElementNode -> visitor.visitDocumentElementNode(node)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
/*
* Copyright 2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.gradle.declarative.lsp

import io.mockk.mockk
import org.eclipse.lsp4j.CompletionParams
import org.eclipse.lsp4j.DidOpenTextDocumentParams
import org.eclipse.lsp4j.Position
import org.eclipse.lsp4j.TextDocumentIdentifier
import org.eclipse.lsp4j.TextDocumentItem
import org.eclipse.lsp4j.services.LanguageClient
import org.gradle.declarative.lsp.build.model.DeclarativeResourcesModel
import org.gradle.declarative.lsp.service.MutationRegistry
import org.gradle.declarative.lsp.service.VersionedDocumentStore
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.io.TempDir
import java.io.File
import java.nio.file.Path
import kotlin.io.path.Path
import kotlin.io.path.createDirectories
import kotlin.io.path.readLines
import kotlin.io.path.readText
import kotlin.io.path.writeText
import kotlin.test.assertEquals

class DeclarativeTextDocumentServiceTest {

@field:TempDir
lateinit var buildFolder: File

private lateinit var service: DeclarativeTextDocumentService

private lateinit var settingsFile: Path

@BeforeEach
fun setup() {
settingsFile = Path("$buildFolder/settings.gradle.dcl")

val declarativeResources = setupGradleBuild(buildFolder)

service = DeclarativeTextDocumentService()
service.initialize(
mockk<LanguageClient>(relaxed = true),
VersionedDocumentStore(),
MutationRegistry(declarativeResources, emptyList()),
DeclarativeFeatures(),
declarativeResources
)
service.didOpen(DidOpenTextDocumentParams().apply {
textDocument = TextDocumentItem().apply {
uri = settingsFile.toUri().toString()
text = settingsFile.readText()
}
})
}

@Test
fun `code completion`() {
val completionParams = CompletionParams().apply {
textDocument = TextDocumentIdentifier(settingsFile.toUri().toString())
position = Position(32, 16)
}

assertEquals(
listOf(
" compileOptions {",
" sourceCompatibility = VERSION_17",
" targetCompatibility = VERSION_17",
" }"
),
settingsFile.readLines().slice(31..34)
)

assertEquals(
listOf(
"encoding = String",
"isCoreLibraryDesugaringEnabled = Boolean",
"sourceCompatibility = JavaVersion",
"targetCompatibility = JavaVersion"
),
service.completion(completionParams).get().left.map { it.label }
)
}


@Suppress("LongMethod")
private fun setupGradleBuild(dir: File): DeclarativeResourcesModel {
Path("$dir/settings.gradle.dcl").writeText(
"""
pluginManagement {
repositories {
google()
mavenCentral()
maven {
url = uri("https://androidx.dev/studio/builds/12648882/artifacts/artifacts/repository")
}
}
}
plugins {
id("com.android.ecosystem").version("8.9.0-dev")
}
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven {
url = uri("https://androidx.dev/studio/builds/12648882/artifacts/artifacts/repository")
}
}
}
rootProject.name = "example-android-app"
include("app")
defaults {
androidApp {
compileSdk = 34
compileOptions {
sourceCompatibility = VERSION_17
targetCompatibility = VERSION_17
}
defaultConfig {
minSdk = 30
versionCode = 1
versionName = "0.1"
applicationId = "org.gradle.experimental.android.app"
}
dependenciesDcl {
implementation("org.jetbrains.kotlin:kotlin-stdlib:2.0.21")
}
}
androidLibrary {
compileSdk = 34
compileOptions {
sourceCompatibility = VERSION_17
targetCompatibility = VERSION_17
}
defaultConfig {
minSdk = 30
}
dependenciesDcl {
implementation("org.jetbrains.kotlin:kotlin-stdlib:2.0.21")
}
}
}
""".trimIndent()
)
Path("$dir/app/").createDirectories().resolve("build.gradle.dcl").writeText(
"""
androidApp {
namespace = "org.example.app"
}
""".trimIndent()
)
Path("$dir/app/src/main/kotlin/org/example/app/").createDirectories().resolve("MainActivity.kt").writeText(
"""
package org.example.app
import org.apache.commons.text.WordUtils
import android.widget.TextView
import android.os.Bundle
import android.app.Activity
class MainActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val textView = findViewById(R.id.textView) as TextView
textView.text = "Hello, World!"
}
}
""".trimIndent()
)

return TapiConnectionHandler(dir).getDeclarativeResources()
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,10 @@
* limitations under the License.
*/

package org.gradle.declarative.lsp.storage
package org.gradle.declarative.lsp.service

import io.mockk.mockk
import org.gradle.declarative.dsl.schema.AnalysisSchema
import org.gradle.declarative.lsp.service.VersionedDocumentStore
import org.gradle.internal.declarativedsl.dom.operations.overlay.DocumentOverlayResult
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertNotNull
Expand Down

0 comments on commit 38e1d64

Please sign in to comment.