REPL: Extract IDE-specific tests to a separate test set
This commit is contained in:
@@ -67,4 +67,6 @@ projectTest(taskName = "embeddableTest", parallel = true) {
|
||||
workingDir = rootDir
|
||||
dependsOn(embeddableTestRuntime)
|
||||
classpath = embeddableTestRuntime
|
||||
|
||||
exclude("**/JvmReplIdeTest.class")
|
||||
}
|
||||
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.scripting.ide_services
|
||||
|
||||
import com.intellij.mock.MockApplication
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.vfs.VirtualFileManager
|
||||
import com.intellij.util.indexing.FileContentImpl
|
||||
import junit.framework.TestCase
|
||||
import org.jetbrains.kotlin.analysis.decompiler.psi.KotlinClassFileDecompiler
|
||||
import org.jetbrains.kotlin.analysis.decompiler.stub.file.ClsKotlinBinaryClassCache
|
||||
import org.jetbrains.kotlin.analysis.decompiler.stub.file.FileAttributeService
|
||||
import org.jetbrains.kotlin.analysis.decompiler.stub.files.DummyFileAttributeService
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.psi.stubs.KotlinClassStub
|
||||
import org.jetbrains.kotlin.scripting.compiler.plugin.impl.KJvmCompiledModuleInMemoryImpl
|
||||
import org.jetbrains.kotlin.scripting.ide_services.test_util.JvmTestRepl
|
||||
import org.jetbrains.kotlin.scripting.ide_services.test_util.checkCompile
|
||||
import java.io.File
|
||||
import kotlin.io.path.ExperimentalPathApi
|
||||
import kotlin.io.path.createTempDirectory
|
||||
import kotlin.script.experimental.jvm.impl.KJvmCompiledModuleInMemory
|
||||
import kotlin.script.experimental.util.get
|
||||
|
||||
// This test checks the functionality that works only in IDE
|
||||
// and doesn't run with embeddableTest configuration
|
||||
class JvmReplIdeTest : TestCase() {
|
||||
fun testReplScriptClassFileDecompilation() {
|
||||
JvmTestRepl()
|
||||
.use { repl ->
|
||||
val compiledSnippet = checkCompile(repl, "10 + 10")
|
||||
val snippetValue = compiledSnippet.get()!!
|
||||
|
||||
val compiledModule = snippetValue.getCompiledModule() as KJvmCompiledModuleInMemoryImpl
|
||||
val folder = saveCompiledOutput("repl-script-decompilation", compiledModule)
|
||||
|
||||
val scriptClassName = "Line_0_simplescript"
|
||||
val fileUrl = "file://" + folder.resolve("$scriptClassName.class").invariantSeparatorsPath
|
||||
val vFile = VirtualFileManager.getInstance().findFileByUrl(fileUrl)!!
|
||||
val fileContent = FileContentImpl.createByContent(vFile, vFile.contentsToByteArray(false))
|
||||
|
||||
val application = ApplicationManager.getApplication() as MockApplication
|
||||
KotlinCoreEnvironment.underApplicationLock {
|
||||
registerDecompilerServices(application)
|
||||
}
|
||||
|
||||
val fileStub = KotlinClassFileDecompiler().stubBuilder.buildFileStub(fileContent)!!
|
||||
val childrenStubs = fileStub.childrenStubs
|
||||
assertTrue(childrenStubs.any { it is KotlinClassStub && it.name == scriptClassName })
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalPathApi::class)
|
||||
companion object {
|
||||
private val outputJarDir = createTempDirectory("temp-ide-services-ide-test")
|
||||
|
||||
private fun saveCompiledOutput(subfolder: String, module: KJvmCompiledModuleInMemory): File {
|
||||
val folder = outputJarDir.resolve(subfolder).toFile()
|
||||
module.compilerOutputFiles.forEach { (name, contents) ->
|
||||
val file = folder.resolve(name)
|
||||
file.parentFile.mkdirs()
|
||||
file.writeBytes(contents)
|
||||
}
|
||||
return folder
|
||||
}
|
||||
|
||||
private fun registerDecompilerServices(application: MockApplication) {
|
||||
application.registerService(FileAttributeService::class.java, DummyFileAttributeService)
|
||||
application.registerService(ClsKotlinBinaryClassCache::class.java, ClsKotlinBinaryClassCache())
|
||||
}
|
||||
}
|
||||
}
|
||||
-158
@@ -5,23 +5,12 @@
|
||||
|
||||
package org.jetbrains.kotlin.scripting.ide_services
|
||||
|
||||
import com.intellij.mock.MockApplication
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.vfs.VirtualFileManager
|
||||
import com.intellij.util.indexing.FileContentImpl
|
||||
import junit.framework.TestCase
|
||||
import org.jetbrains.kotlin.analysis.decompiler.psi.KotlinClassFileDecompiler
|
||||
import org.jetbrains.kotlin.analysis.decompiler.stub.file.ClsKotlinBinaryClassCache
|
||||
import org.jetbrains.kotlin.analysis.decompiler.stub.file.FileAttributeService
|
||||
import org.jetbrains.kotlin.analysis.decompiler.stub.files.DummyFileAttributeService
|
||||
import org.jetbrains.kotlin.cli.common.ExitCode
|
||||
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocationWithRange
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||
import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.config.Services
|
||||
import org.jetbrains.kotlin.scripting.compiler.plugin.impl.KJvmCompiledModuleInMemoryImpl
|
||||
import org.jetbrains.kotlin.scripting.ide_services.test_util.*
|
||||
import java.io.File
|
||||
import kotlin.io.path.ExperimentalPathApi
|
||||
@@ -29,15 +18,11 @@ import kotlin.io.path.createTempDirectory
|
||||
import kotlin.io.path.invariantSeparatorsPathString
|
||||
import kotlin.reflect.full.isSubclassOf
|
||||
import kotlin.script.experimental.api.*
|
||||
import kotlin.script.experimental.jvm.impl.KJvmCompiledModuleInMemory
|
||||
import kotlin.script.experimental.jvm.impl.KJvmCompiledScript
|
||||
import kotlin.script.experimental.jvm.jvm
|
||||
import kotlin.script.experimental.jvm.updateClasspath
|
||||
import kotlin.script.experimental.jvm.util.isError
|
||||
import kotlin.script.experimental.jvm.util.isIncomplete
|
||||
import kotlin.script.experimental.jvm.util.scriptCompilationClasspathFromContext
|
||||
import kotlin.script.experimental.util.LinkedSnippet
|
||||
import kotlin.script.experimental.util.get
|
||||
|
||||
// Adapted form GenericReplTest
|
||||
|
||||
@@ -353,28 +338,6 @@ class JvmIdeServicesTest : TestCase() {
|
||||
}
|
||||
}
|
||||
|
||||
fun testReplScriptClassFileDecompilation() {
|
||||
JvmTestRepl()
|
||||
.use { repl ->
|
||||
val compiledSnippet = checkCompile(repl, "10 + 10")
|
||||
val snippetValue = compiledSnippet.get()!!
|
||||
|
||||
val compiledModule = snippetValue.getCompiledModule() as KJvmCompiledModuleInMemoryImpl
|
||||
val folder = saveCompiledOutput("repl-script-decompilation", compiledModule)
|
||||
|
||||
val vFile = VirtualFileManager.getInstance().findFileByNioPath(folder.resolve("Line_0_simplescript.class").toPath())!!
|
||||
val fileContent = FileContentImpl.createByFile(vFile)
|
||||
|
||||
val application = ApplicationManager.getApplication() as MockApplication
|
||||
KotlinCoreEnvironment.underApplicationLock {
|
||||
registerDecompilerServices(application)
|
||||
}
|
||||
|
||||
val fileStub = KotlinClassFileDecompiler().stubBuilder.buildFileStub(fileContent)
|
||||
assertNotNull(fileStub)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalPathApi::class)
|
||||
companion object {
|
||||
private const val MODULE_PATH = "plugins/scripting/scripting-ide-services-test"
|
||||
@@ -401,21 +364,6 @@ class JvmIdeServicesTest : TestCase() {
|
||||
|
||||
return CliCompilationResult(exitCode, jarPath)
|
||||
}
|
||||
|
||||
private fun saveCompiledOutput(subfolder: String, module: KJvmCompiledModuleInMemory): File {
|
||||
val folder = outputJarDir.resolve(subfolder).toFile()
|
||||
module.compilerOutputFiles.forEach { (name, contents) ->
|
||||
val file = folder.resolve(name)
|
||||
file.parentFile.mkdirs()
|
||||
file.writeBytes(contents)
|
||||
}
|
||||
return folder
|
||||
}
|
||||
|
||||
private fun registerDecompilerServices(application: MockApplication) {
|
||||
application.registerService(ClsKotlinBinaryClassCache::class.java)
|
||||
application.registerService(FileAttributeService::class.java, DummyFileAttributeService)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -472,109 +420,3 @@ class LegacyReplTestLong : TestCase() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun JvmTestRepl.compileAndEval(codeLine: SourceCode): Pair<ResultWithDiagnostics<LinkedSnippet<out CompiledSnippet>>, EvaluatedSnippet?> {
|
||||
|
||||
val compRes = compile(codeLine)
|
||||
|
||||
val evalRes = compRes.valueOrNull()?.let {
|
||||
eval(it)
|
||||
}
|
||||
return compRes to evalRes?.valueOrNull().get()
|
||||
}
|
||||
|
||||
private fun assertCompileFails(
|
||||
repl: JvmTestRepl,
|
||||
@Suppress("SameParameterValue")
|
||||
line: String
|
||||
) {
|
||||
val compiledSnippet =
|
||||
checkCompile(repl, line)
|
||||
|
||||
TestCase.assertNull(compiledSnippet)
|
||||
}
|
||||
|
||||
private fun assertEvalUnit(
|
||||
repl: JvmTestRepl,
|
||||
@Suppress("SameParameterValue")
|
||||
line: String
|
||||
) {
|
||||
val compiledSnippet =
|
||||
checkCompile(repl, line)
|
||||
|
||||
val evalResult = repl.eval(compiledSnippet!!)
|
||||
val valueResult = evalResult.valueOrNull().get()
|
||||
|
||||
TestCase.assertNotNull("Unexpected eval result: $evalResult", valueResult)
|
||||
TestCase.assertTrue(valueResult!!.result is ResultValue.Unit)
|
||||
}
|
||||
|
||||
private fun <R> assertEvalResult(repl: JvmTestRepl, line: String, expectedResult: R) {
|
||||
val compiledSnippet =
|
||||
checkCompile(repl, line)
|
||||
|
||||
val evalResult = repl.eval(compiledSnippet!!)
|
||||
val valueResult = evalResult.valueOrNull().get()
|
||||
|
||||
TestCase.assertNotNull("Unexpected eval result: $evalResult", valueResult)
|
||||
TestCase.assertTrue(valueResult!!.result is ResultValue.Value)
|
||||
TestCase.assertEquals(expectedResult, (valueResult.result as ResultValue.Value).value)
|
||||
}
|
||||
|
||||
private inline fun <reified R> assertEvalResultIs(repl: JvmTestRepl, line: String) {
|
||||
val compiledSnippet =
|
||||
checkCompile(repl, line)
|
||||
|
||||
val evalResult = repl.eval(compiledSnippet!!)
|
||||
val valueResult = evalResult.valueOrNull().get()
|
||||
|
||||
TestCase.assertNotNull("Unexpected eval result: $evalResult", valueResult)
|
||||
TestCase.assertTrue(valueResult!!.result is ResultValue.Value)
|
||||
TestCase.assertTrue((valueResult.result as ResultValue.Value).value is R)
|
||||
}
|
||||
|
||||
private fun checkCompile(repl: JvmTestRepl, line: String): LinkedSnippet<KJvmCompiledScript>? {
|
||||
val codeLine = repl.nextCodeLine(line)
|
||||
val compileResult = repl.compile(codeLine)
|
||||
return compileResult.valueOrNull()
|
||||
}
|
||||
|
||||
private data class CompilationErrors(
|
||||
val message: String,
|
||||
val location: CompilerMessageLocationWithRange?
|
||||
)
|
||||
|
||||
private fun <T> ResultWithDiagnostics<T>.getErrors(): CompilationErrors =
|
||||
CompilationErrors(
|
||||
reports.joinToString("\n") { report ->
|
||||
report.location?.let { loc ->
|
||||
CompilerMessageLocationWithRange.create(
|
||||
report.sourcePath,
|
||||
loc.start.line,
|
||||
loc.start.col,
|
||||
loc.end?.line,
|
||||
loc.end?.col,
|
||||
null
|
||||
)?.toString()?.let {
|
||||
"$it "
|
||||
}
|
||||
}.orEmpty() + report.message
|
||||
},
|
||||
reports.firstOrNull {
|
||||
when (it.severity) {
|
||||
ScriptDiagnostic.Severity.ERROR -> true
|
||||
ScriptDiagnostic.Severity.FATAL -> true
|
||||
else -> false
|
||||
}
|
||||
}?.let {
|
||||
val loc = it.location ?: return@let null
|
||||
CompilerMessageLocationWithRange.create(
|
||||
it.sourcePath,
|
||||
loc.start.line,
|
||||
loc.start.col,
|
||||
loc.end?.line,
|
||||
loc.end?.col,
|
||||
null
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
+111
@@ -5,14 +5,18 @@
|
||||
|
||||
package org.jetbrains.kotlin.scripting.ide_services.test_util
|
||||
|
||||
import junit.framework.TestCase
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocationWithRange
|
||||
import org.jetbrains.kotlin.scripting.ide_services.compiler.KJvmReplCompilerWithIdeServices
|
||||
import java.io.Closeable
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import kotlin.script.experimental.api.*
|
||||
import kotlin.script.experimental.jvm.BasicJvmReplEvaluator
|
||||
import kotlin.script.experimental.jvm.impl.KJvmCompiledScript
|
||||
import kotlin.script.experimental.util.LinkedSnippet
|
||||
import kotlin.script.experimental.jvm.util.toSourceCodePosition
|
||||
import kotlin.script.experimental.util.get
|
||||
|
||||
internal class JvmTestRepl (
|
||||
private val compileConfiguration: ScriptCompilationConfiguration = simpleScriptCompilationConfiguration,
|
||||
@@ -55,3 +59,110 @@ fun <T> ResultWithDiagnostics<Iterable<T>>.toList() = this.valueOrNull()?.toList
|
||||
|
||||
@JvmName("sequenceToList")
|
||||
fun <T> ResultWithDiagnostics<Sequence<T>>.toList() = this.valueOrNull()?.toList().orEmpty()
|
||||
|
||||
internal fun JvmTestRepl.compileAndEval(codeLine: SourceCode): Pair<ResultWithDiagnostics<LinkedSnippet<out CompiledSnippet>>, EvaluatedSnippet?> {
|
||||
|
||||
val compRes = compile(codeLine)
|
||||
|
||||
val evalRes = compRes.valueOrNull()?.let {
|
||||
eval(it)
|
||||
}
|
||||
return compRes to evalRes?.valueOrNull().get()
|
||||
}
|
||||
|
||||
internal fun assertCompileFails(
|
||||
repl: JvmTestRepl,
|
||||
@Suppress("SameParameterValue")
|
||||
line: String
|
||||
) {
|
||||
val compiledSnippet =
|
||||
checkCompile(repl, line)
|
||||
|
||||
TestCase.assertNull(compiledSnippet)
|
||||
}
|
||||
|
||||
internal fun assertEvalUnit(
|
||||
repl: JvmTestRepl,
|
||||
@Suppress("SameParameterValue")
|
||||
line: String
|
||||
) {
|
||||
val compiledSnippet =
|
||||
checkCompile(repl, line)
|
||||
|
||||
val evalResult = repl.eval(compiledSnippet!!)
|
||||
val valueResult = evalResult.valueOrNull().get()
|
||||
|
||||
TestCase.assertNotNull("Unexpected eval result: $evalResult", valueResult)
|
||||
TestCase.assertTrue(valueResult!!.result is ResultValue.Unit)
|
||||
}
|
||||
|
||||
internal fun <R> assertEvalResult(repl: JvmTestRepl, line: String, expectedResult: R) {
|
||||
val compiledSnippet =
|
||||
checkCompile(repl, line)
|
||||
|
||||
val evalResult = repl.eval(compiledSnippet!!)
|
||||
val valueResult = evalResult.valueOrNull().get()
|
||||
|
||||
TestCase.assertNotNull("Unexpected eval result: $evalResult", valueResult)
|
||||
TestCase.assertTrue(valueResult!!.result is ResultValue.Value)
|
||||
TestCase.assertEquals(expectedResult, (valueResult.result as ResultValue.Value).value)
|
||||
}
|
||||
|
||||
internal inline fun <reified R> assertEvalResultIs(repl: JvmTestRepl, line: String) {
|
||||
val compiledSnippet =
|
||||
checkCompile(repl, line)
|
||||
|
||||
val evalResult = repl.eval(compiledSnippet!!)
|
||||
val valueResult = evalResult.valueOrNull().get()
|
||||
|
||||
TestCase.assertNotNull("Unexpected eval result: $evalResult", valueResult)
|
||||
TestCase.assertTrue(valueResult!!.result is ResultValue.Value)
|
||||
TestCase.assertTrue((valueResult.result as ResultValue.Value).value is R)
|
||||
}
|
||||
|
||||
internal fun checkCompile(repl: JvmTestRepl, line: String): LinkedSnippet<KJvmCompiledScript>? {
|
||||
val codeLine = repl.nextCodeLine(line)
|
||||
val compileResult = repl.compile(codeLine)
|
||||
return compileResult.valueOrNull()
|
||||
}
|
||||
|
||||
internal data class CompilationErrors(
|
||||
val message: String,
|
||||
val location: CompilerMessageLocationWithRange?
|
||||
)
|
||||
|
||||
internal fun <T> ResultWithDiagnostics<T>.getErrors(): CompilationErrors =
|
||||
CompilationErrors(
|
||||
reports.joinToString("\n") { report ->
|
||||
report.location?.let { loc ->
|
||||
CompilerMessageLocationWithRange.create(
|
||||
report.sourcePath,
|
||||
loc.start.line,
|
||||
loc.start.col,
|
||||
loc.end?.line,
|
||||
loc.end?.col,
|
||||
null
|
||||
)?.toString()?.let {
|
||||
"$it "
|
||||
}
|
||||
}.orEmpty() + report.message
|
||||
},
|
||||
reports.firstOrNull {
|
||||
when (it.severity) {
|
||||
ScriptDiagnostic.Severity.ERROR -> true
|
||||
ScriptDiagnostic.Severity.FATAL -> true
|
||||
else -> false
|
||||
}
|
||||
}?.let {
|
||||
val loc = it.location ?: return@let null
|
||||
CompilerMessageLocationWithRange.create(
|
||||
it.sourcePath,
|
||||
loc.start.line,
|
||||
loc.start.col,
|
||||
loc.end?.line,
|
||||
loc.end?.col,
|
||||
null
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user